By Daniel Kift
The Coding Assignment
Like almost every other tech company, one stage of the upday hiring process involves asking candidates to write some code. Each company has their own way of assessing a candidate’s skills.
Some companies ask candidates to invert a binary tree on a whiteboard against the clock. Others involve competitive coding style exercises on platforms like HackerRank.
We prefer to ask candidates to do a task that they would typically do in their day-to-day role. In our case, this means writing a Spring Boot app with a RESTful API for creating, reading, updating, and deleting news articles.
Here are some tips for what we look for in this part of the process.
The Important Stuff
The only one way to get an instant rejection is to submit an application without any tests. We need to know that the code works before clients start using it.
The following types of test should give us some confidence:
- Unit tests
These tests should test individual units of code, run quickly by mocking slow collaborators (e.g. those doing IO like reading from databases, disk, making network requests and so on), and cover multiple paths and edge-cases
- REST tests
These tests involve sending REST requests via something like REST-assured or a regular HTTP client to ensure that the individual units integrate with each other correctly and the application works as a whole.
To ensure the application is well tested, we look for a few things:
- Strong assertions
Tests must include an assertion or mock verification. Weak assertions like isNotNull() are rarely sufficient to know that your code is behaving correctly.
- Multiple cases
Tests should not just check the happy path. Consider different paths, exceptional cases, and boundary values
Are test names clear? Following test naming conventions can help.
Does the test use patterns to make clear what is being tested
Tests should be independent. They should not need to run in any order, and clear up any state created during their execution so that they don’t influence other tests
- A Green suite
Last but not least, the tests should all be passing
A specific test coverage metric (e.g. 80%) isn’t so important to us. We don’t need you to test whether Spring Boot or the Java standard libraries work, but the core business logic should be tested.
Once an API is being used by clients in production, it becomes very difficult to change or remove it. So getting the API design right in the first case is important. The things we look for in this area are:
- A resource-oriented API (see https://cloud.google.com/apis/design/resources)
- The correct HTTP methods should be used. GETs for idempotent requests that can be cached. POST/PUTs for creating new resources, DELETEs for deleting resources and so on
- Sensible response status codes should be used as well. 2xx for success, 4xx for user errors, 5xx for server errors
- Ideally there will be some mechanism for versioning in case we need to make a backwards-incompatible change to the API
Hyperlinks / HATEOAS for discoverability of other APIs would also be great but is not expected.
Architecture / Separation of Concerns
Once the API is defined, some business logic and data-access code will be needed. These concerns should be split into separate layers. This helps guide implementations towards following the Single Responsibility Principle. It also makes it easier to test and evolve layers independently.
- controllers should take care of REST / HTTP concerns.
- services should contain the business logic of the application.
- repositories should handle data access.
Typically requests will flow from layer to layer. Layers further down (e.g. repositories) should not depend on layers further up (e.g. controllers).
Tools like jQ can help enforce this separation (and other best practices).
Packages structure could be an entire topic on its own. For a coding assignment, whether you slice your application vertically around business capabilities (preferred), or horizontally around these layers (model, view, controller) isn’t as important as whether the code has a sensible structure and is easy to navigate.
Does the application behave appropriately when errors occur. Those errors may be:
- client errors — invalid client requests (e.g. malformed request body, missing parameters, etc.)
- server errors — like unreachable resources, null pointers, etc.
Error handling doesn’t need to be exhaustive, but we’d like candidates to show that they have considered some error cases and know how to deal with them.
Error responses should be useful for users and developers trying to use your API. They should also not expose internal implementation details, like stack traces, that could alert malicious users of potential vulnerabilities in your code.
Is a simple README provided, including information like:
- How to start the application
- How to call the APIs. Providing this information via Swagger or Spring REST Docs would be even better.
- What features weren’t included due to time constraints, and what you might have done given more time
The Nice to Haves
- Are only necessary dependencies imported?
- Are transitive dependencies from spring-boot-starters preferred?
- Are dependencies appropriately scoped (e.g. to ensure test dependencies aren’t packaged in the final JAR)?
- Are recent versions of dependencies used (e.g. to reduce the likelihood of using libraries with vulnerabilities)?
https://start.spring.io is a good place to start for setting up appropriate dependencies.
Some care should be taken when writing and committing the code, for example:
- Is the code formatted?
- Is there any commented out code or unfinished TODOs?
- Does the code contain typos or spelling mistakes?
- Does the code follow code conventions of the language used, whether it be Java or Kotlin?
- Is a .gitignore file included?
- Do methods and variables have meaningful names?
- Are classes and methods small and focused, with a single responsibility?
IDE plugins like sonarlint can help you spot some of these issues.
How Easily Can We Run the App?
The most basic requirement is that the application should start. Ideally it will start with one click or command, and an instruction manual is not needed to get it running.
Lots of different tools and approaches are valid (e.g. JPA, JDBC, jOOQ). The chosen approach isn’t as important as whether the data model makes sense.
Similarly, the database technology used isn’t as important as the ability to describe why it is a good choice (typically in a follow up interview).
Depending on the choice made, extra points are available for thinking about things like paging and sorting, and dealing with common problems (e.g. n+1).
Logging & Metrics
Is it possible to understand what is happening in the application at runtime, so that it can be operated successfully in production?
- Are exceptions logged with their stack traces to help diagnose issues?
- Is there a health check API?
- Are custom application metrics sent?
Technical skills are not the most important quality we look for in a new team member. We see a willingness to learn, ability to communicate, and empathy as more important.
That means, a perfect solution to the homework assignment isn’t expected. We also try to adapt our review based on the experience level of the candidate. But, we would like to see that you have a good foundational knowledge of REST, Spring, and Java or Kotlin so that you are successful when you start working with us.