Сomplex Code: Story of One Interview
Tags: interview, java, javascript, codequality
Published: 2020-06-29 20:08:48

After posting about my interview on some [eastern European forum](https://habr.com/ru/post/507684/) and sharing it with my colleagues and friends, I realized this might be an interesting topic for the IT community in general.

Maybe it does not happen so often in the Netherlands, where I live at the moment. The interview processes that at least I’ve experienced were organized very well. Maybe the problem lies on a cultural level and is deeply connected with the roots of the company. I don’t know. But I decided not to reveal the name of this organization. I believe it might happen in many companies, even ones with big names which you would never imagine could complete a job interview like that. 

And I believe the responsibility falls not on a single person, but on an organization that hasn’t built a culture of job interviews. Anyway, this story is a good reference for people on both sides — the job candidate and the interviewer. I will be really glad if it will serve as good feedback to the people that work there, even when they were not able to provide feedback appropriately to me. Everybody makes mistakes, and everybody deserves to have a chance to learn from them.

#### Here is my story (translated from my native language):

I would like to share a story of my failure, looking at negative feedback from a company after a technical assignment. Of course, any negative experience is always a great opportunity to review strategies, to make particular conclusions, and to learn from mistakes. In this case, I have a good reason to evaluate my interview experience, even though it didn’t end with an offer. I want to thank you in advance for the time you spend reading this article, along with the code, and the effort you put into understanding it. I would be doubly grateful if you will share your opinion on this topic.

All source code is available in a public repository on GitHub via this [link](https://github.com/itallix/noughts-crosses). There were no commits made after the publication, despite some things I would fix and clean, but I intentionally didn’t do that. There is always some kind of agreement with ourselves about the time we want to spend on a task. We try to prioritize based on personal preferences unless otherwise specified in the requirements. Someone might prefer to write documentation on their API. Someone might decide to increase test coverage. In my case, as you can see, there are no e2e tests, for example. There are no unit tests for UI components. Also, CSS is a mess, and it doesn’t follow any methodology. It is likely you can continue this list with other shortcomings. And bugs ;) There are some.

So, being impressed with a company profile, confirmed by a review from a former colleague who once worked there, I decided to submit my resume. A week or two later, a recruiter contacted me and proposed I talk with the lead of one of the company’s teams. The conversation with the lead was quite generic. The person asked, what technologies do you use? What are you proud of? What problems were solved? Some real examples? I also asked him some questions. It was just a normal conversation, quite typical for an IT company. Later the same day, the company’s recruiter told me they would like to move forward, and after I agreed, they sent me a task to complete as part of the interview process. Below is the original set of requirements:

>
Build a service to play a tic-tac-toe game.
The game should contain multiple sessions. Each player can either join the existing game session or create a new one.
The initial screen should contain a list of game sessions and brief overviews — like how many players are playing now and when was the last move. Data should be updated in real-time.
The game session board should have a fixed size of 10x10. Several players can play there. Each player can make a move at any time but cannot make several moves in a row.
The game server can store the state of the game process in memory.
Implement the solution using any technologies convenient for you, but it will be great if you make them on _[project technologies are specified]_

I decided to implement this assignment on technologies convenient for me. The languages ​​chosen were Java and Javascript. I choose Spring and React as frameworks. State storage was in memory as highlighted in the task.

Just a week before, I was completing a technical task for another company, which also featured the game but with a different logic. The game was called [Kalah](https://en.wikipedia.org/wiki/Kalah). The architecture that I laid down for it and the principles that followed seemed to be quite appropriate here. And it seemed appropriate for the implementation of simple games in general. The main priorities I set for myself when solving the problem included the following:
1. As far as availability of documentation for the API is concerned, snippets with Rest API semantics will be generated by integration tests to kill two birds with one stone. This is where [Spring Rest Docs](https://spring.io/projects/spring-restdocs) comes in.
2. Use WebSockets to build an interactive dashboard and the game session. Long polling is no longer fashionable. We take stomp and sockjs recommended by the Spring framework. As an additional advantage, if the server does not support WebSockets, the library falls back on long polling transparent to the client. So, why not?
3. Put the game rules encapsulation in separate classes. So, for Kalah, for example, I had three rules: the move rule, the capture rule, and the end game rule. This approach seemed very appropriate to me because each rule can be tested separately and can be removed from the game. Also, the game can be complicated by adding a new class with the implementation of another rule. I had two such rules in tic-tac-toe — the [TurnRule](https://github.com/itallix/noughts-crosses/blob/master/server/src/main/java/io/karniushin/tictactoe/core/service/handler/rule/DefaultTurnRule.java), which also assumed responsibility for validation, but I would move it to a higher level, and the [EndGameRule](https://github.com/itallix/noughts-crosses/blob/master/server/src/main/java/io/karniushin/tictactoe/core/service/handler/rule/DefaultEndGameRule.java), which determined a winner or a draw. It should also be noted that I determined the order of the rules using Spring order annotation, which tells the container the order to inject the beans. This decision may seem controversial, but the presence of a test that verifies this order is given makes it quite viable.
4. I decided to implement the algorithm for finding the winner by betting on the composition while thinking about efficiency, not forgetting that I cannot go beyond linear complexity. I wrote a [set of custom iterators](https://github.com/itallix/noughts-crosses/tree/master/server/src/main/java/io/karniushin/tictactoe/core/service/handler/rule/condition), each of which identified winnings — horizontally, vertically, and the main and secondary diagonals. It seems that reading [such an algorithm](https://github.com/itallix/noughts-crosses/blob/98f31c4b7f1648e923cde7f76d06542dee1b4e4f/server/src/main/java/io/karniushin/tictactoe/core/service/handler/rule/condition/WinCondition.java#L14) is easier. Also, you can turn on/off a specific iterator at any time, which makes the architecture quite flexible.
5. Implement front-end with react/redux/saga. This is the set that we use in our projects. It has shown its effectiveness over a long time. I'm not sure it makes sense to comment on redux and why I use it. But, at the expense of redux-saga, I frequently hear criticism. I can only say I was also initially wary of this library, but when I studied it better, I realized it is very convenient to work with this approach, both in terms of testing and of reading code.

Regarding the server code features, to protect against race conditions, I used ReentrantLock’s map. The game session has its ReentrantLock instance. I decided not to implement synchronization with client time but simply generate the turn time on the server.

After [the initial feedback](https://gist.github.com/itallix/fb1f4af531da0db65afc719e73af10e9) about the UX, with a proposal to fix and add some things I also decided to rewrite the front-end using functional components with hooks. I have wanted to test this approach for a long time, and I liked it. The authors of reactjs in the documentation emphasize this approach minimizes the number of errors made by programmers related to the component’s life cycle when using a style based on classes and callbacks. I think this is an important point. If you are not yet using a new approach in your work, I recommend you try it. 

I received the following feedback a week later:
>
My colleagues and I carefully inspected the new version of the assignment.
Based on the results, I decided not to continue the hiring process.
Below is the feedback on the assignment from us:
- The code is confusing and difficult to understand, much more difficult than it could be.
- Per our front-end developer, there was over-engineering on the front-end.
>
Quoting his words below:
>
_Apparently, the task was done on technologies the candidate knew, although we did not ask for any redux and redux-saga. And regarding CSS, which was written by hand, there are just library styles overridden. This is a bad way to write CSS._
>
Given the complexity of the codebase in our product, it is important for us that the candidate does things in a simple way. 
Thank you for your time and effort!

Of course, when I received this feedback, I would have like to have a conceptual discussion to be able to defend certain decisions. I accept the comment regarding CSS, but I don't understand the rest. Is it over-engineering? Or am I faced with the technical immaturity of the interviewers? In principle, any assessment is very subjective by nature and has the right to exist.

I have thought about the meaning of the question, what is complex code? It seems the answer to this question is very simple: It is a code that is difficult to read and difficult to change. Like many others, I prefer to think we are writing code for people, not for machines. And, I try to leave room for the thought process of composing the code before I sit down to write it. Does my composition complicate the reading of this code and pretend to be stigmatized — over-engineering? I would like to see opinions on this issue in your comments. 
___
#### Internet Wisdom

>
Anyone can write code, but it takes a master to write simple code.

>
Communication is crucial.

#### Some comments I find interesting from the original post
>
TurnHandler + GameRule is an attempt at wishful thinking. According to the code, there is an idea that "a wide class of games can be modeled with chain of responsibility pattern." This incorrect assumption leads to a code that is too complex, which is not justified for such a simple game as tic-tac-toe. It becomes difficult to judge whether the rules of the game are coded correctly at all. Mix up two rules and everything will fall apart. The sad thing is that more complex games will not fit into the [Chain of Responsibility](https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern). As a result, all this complexity is not needed.

>
They wanted simple tic-tac-toe game and you gave them Enterprise monster.

>
Just learn Java better. Forget about Spring.

>
Front-end is terrible. I wouldn’t trust a person who is using saga and redux for a long time and still thinking this is normal. Check it in IE11. You will learn a lot of new things.

_One of our applications has ~460k of js code (including tests and json mocks) and written with sagas and redux. It is trusted by many customers. IE11 is supported. Most escalations from Support Team usually are not UI related. Maybe we tried different versions, who knows..._
___
Cover image credit: Photo by [Daniel McCullough](https://unsplash.com/@d_mccullough) on [Unsplash](https://unsplash.com/s/photos/interview?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)