Akka Actors: Best Practices

Actors are components of message-passing systems that are particularly popular these days. They make concurrency a lot easier to understand compared to the traditional thread-monitor-lock model.

An actor is a thread-like program that run independently from other actors. It has a mailbox to receive messages from other actors, where each message represents a task to complete. Although actors are much easier understand, we still need to pay attention on how to use them. Following is a list of golden rules when using actors:

Never block

Actors should never be blocked to wait for some result to come back. Instead of waiting, the time could be used to process other messages. Moreover, when an actor is blocked, it will lose requests/messages from other actors and the system could risk to collapse due to deadlocks. If blocking cannot be avoided, delegate to special actors that are dedicated just to the specific blocking tasks.

Communicate only via messages

The idea behind the message-passing system is to keep all the shared data within the message. If the communication doesn’t happen through messages, we risk to introduce some extra shared data that need to be protected by locks. A part from the performance loss, what’s the point of using the actor model if we still have to deal with locks?

Messages should be immutable

As mentioned before, the messages contain all the shared data between the actors. Having immutable messages guarantees that the shared data is thread-safe. This can be easily achieved by using case classes for your messages: not only the immutability is guaranteed, but pattern matching can be easily used to identify the type of your message.

Messages should be complete and self-contained

When receiving a message, an actor should have all the information needed to process it. This reduces dependencies between actors and it allows an actor not to have any memory/history of when/why a specific request was made. Don’t be scared of adding some redundancy to your messages if it helps to improve your system performance.

If you try to follow these simple rules, your concurrent challenges will be a lot easier to tackle — and the system more performant!

RESTful now more important than ever.

REST APIs are becoming more and more popular: they allow horizontal scalability, they are flexible to change and easy to use without the need of detailed documentation.
However, some APIs claim to be RESTful when they are not. This is mainly for two reasons:
– We don’t always have a clear idea of what RESTful means, we just associate it to the HTTP protocol standards.
– Building a pure RESTful API can be really challenging.

What are the features of a REST API? What are the benefits of developing a pure REST API?

Uniformity

Not only it needs to use the standard HTTP methods, but it needs to use them with their standard meaning.
By definition, an operation is idempotent if it always have the same effect whether applied once or multiple times. The following HTTP methods should always be idempotent:
GET: when retrieving existing information without altering the status of our system.
PUT: when updating/adding to an existing resource. Note that by applying this operation more than once, we shouldn’t create any side effect.
DELETE: when deleting a resource. If we try to remove a resource that doesn’t exist or that it has already been deleted, this shouldn’t cause a different behaviour of the API.
HEAD: same as GET, but with an empty body. This is usually used to retrieve metadata about large data without actually retrieving it.
OPTIONS: when retrieving information about what the methods are allowed by the URI.

There is only one HTTP method that is non-idempotent:
– POST: when creating a new resource. This is not idempotent as we shouldn’t be able to create a resource that already exists.

Also, our return codes should respect the HTTP standards. The most used ones:
200 means “OK”
204 means: “OK” with empty body
400 means “Bad Request”
404 means “Resource not found”
500 means “Internal Error”

For a list of all HTTP code status see  http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.

Adopting HTTP standards allows us to safely depend on and use the API: we will know that when using an idempotent method, we can safely repeat the operation if needed. On the other side, when POSTing, we are aware that this can cause side effects that we need to take care of.

Addressability

Each resource should be uniquely identified by a URI: every time a resource is created it needs to have an address that identifies it.
Addressability is also about readability and predictability: not only the URI should be informative on what the resource is, but it should also be easy to remember and consistent with the other URIs we have created so far.
There are a lot of different opinions on how to build efficient URIs (e.g.: http://www.restapitutorial.com/lessons/restfulresourcenaming.html), chose one convention and stick to it! This will make your API a lot easier to use and our clients a lot happier!

Connectedness

Resources need to be linked together…literally!
While a SOAP API uses a WSDL to define the communication between client and service, a REST API doesn’t have such a technical precise definition of what it can do: as a client we should learn how to use the API by using it, we shouldn’t necessarily rely on any official documentation. One way of achieving this is by using hypermedia to link resources together. For example, if we return the information about a customer we could provide the URI to retrieve all his accounts. We could also prove URIs that provide and explain specific values (e.g.: enums, query params, etc) accepted/returned by that specific operation.

Statelessness

Statuses should never be maintained by the system: they should either be provided by the client or stored in a database. Although this seems to be a small detail, this allows our service horizontally: when our service in under lots of pressure due to high demand, we just need to run a new node of the service to increase our computational power. This operation is completely seamless to our clients because API calls are not influenced by previous calls (i.e.: they are stateless). Another advantage is that stateless calls are also independent between each other: it will allow us to parallelize some calls without worrying too much about side effects.

To Feature Branch or Not to Feature Branch?

Even when working with Agile methodologies and a Continuous Integration pipeline, some developers love feature branching – and they complain a lot when they are forbidden from using it!
The arguments in its favour are usually:
– “It makes easy to code review”
– “I can focus on my task and worry about conflicts later”
– “No feature branching means no code reviews. We will drop our code quality!”

Let’s discuss them 🙂

“It makes easy to code review”

Code reviews are essential in the team to ensure high quality and a consistent style in the code. Although it’s true that branches make easy to create pull requests, they are not the only way to review the code. I personally prefer to have a team meeting where all the commits are discussed all together face-to-face. There are several benefits in this approach:
– Misunderstandings are reduced – no more long cold threads comments arguing!
– Less experienced team members can learn from the most experienced ones.
– The team can discuss (and change if needed!) its guidelines and style when needed.

Unfortunately, there are some disadvantages as well:
– Meetings are time consuming and they need to be properly organised.
– Each developer needs to read the code to review before the meeting to build some basic understanding of it: again, discipline and time needed!

“I can focus on my task and worry about conflicts later”

Feature branching delays conflicts, doesn’t make them disappear! This is against the continuous integration methodology: it is better to discover conflicts as soon as we create them rather than on a Friday afternoon at 16.00 with the release scheduled on Monday at 11.00 (yes, it happened 😐 )

“We will drop our code quality!”

Actually, it’s the opposite! Feature branching discourages refactoring to avoid the generation of conflicts – if you ever had to deal with git conflict you know what I am talking about!