Architecture By Principle
By: Greg Farrow
Tags: Software Engineering, Principles, Productivity, Solutions Architecture, Software Development

Principles of Architecture @ ResponseTap

Serverless First. Cloud-First. AWS First.

We believe in Serverless First, wholeheartedly.

This Principle encapsulates our desire to minimise the amount of effort we put into managing infrastructure. We also want to ensure massive scalability. We don’t want to manage datacentres or hardware.

We first ventured into the Cloud several years ago and have been using AWS ever since. Could we use other vendors? Sure. But we choose not to until a compelling reason becomes apparent.

Making vendor choice a Principle means that we don’t need to evaluate Cloud vendors for every solution repeatedly.

Configure First. Write Code Second.

Code contains defects. It is also slow to write and test. The best code is that which doesn’t need to be written.

So what we prefer to do is use other people’s code and configure it for our purposes. We are often able to build solutions, by merely configuring AWS services, such as SNS Subscription Filters.

Building things yourself is rarely preferable to other solutions.

Simplicity is better than complexity.

Does that seem obvious? As technically minded people, we are all too often guilty of over-complicating our solutions. We try to abide by Lean, by maximising value while minimising resources.

Solve the problem you have, not the problem you think you might have in future. Complexity often comes from trying to second-guess what the future may hold for your solution. It is always better to build something simple and extend it — instead of creating something complex which doesn’t solve the problem effectively.

Massively Scalable. Event-Driven.

We’ve learnt from experience that taking a system and retroactively making it more scalable is hard. It’s not unusual that for us to achieve scale in these services, we need to re-write them.

Every new service we build is designed to run at a massive scale, from scratch. Scale is achieved relatively easily using serverless technologies.

When you build using serverless, you need to avoid state. Serverless functions, such as AWS Lambda are ephemeral. They are also charged for the time they are active. Therefore it is an anti-pattern to have a FaaS function sat waiting for a response from another service.

We try to ensure that we use Event-Driven functions wherever possible and adhere to Eventual Consistency.

What we build will fail. We embrace those failures.

No software is perfect.

The reverse side of that coin is that our solution will fail. We can mitigate this and attempt to prevent it (which we should definitely do!). What we can’t do is prevent it entirely. So we must expect it to fail.

Expecting failure is a mindset shift. When my solution fails, what will happen? There will be logs, metrics, alerts and transparency around those failures because we expected them.

Services are modular, isolated and single purpose.

One of the biggest problems an engineering team will face is that of inter-dependency.

If a small change is required, it is frustrating and wasteful if that change forces linked code and services to be updated as well. The result is slow delivery and increased risk of introducing defects.

It is much better all-round if code and services are isolated and independent and they have no knowledge or opinion about other services or concepts within those services.

Services provide an interface and are ignorant of how they are consumed.

If we build services in a modular way, they need to be able to communicate. The interaction between services should never be an afterthought. Whenever we create a new service, we include contract writing and interfaces within our “Definition of Done”.

We prevent direct access to data sources from outside of the service.

Change is sought but challenged.

A fantastic part of working in Development is the culture of embracing change. Change for change’s sake is as bad as being resistant to change.

We encourage and embrace change as a means for us to progress and improve. But any change needs to be challenged. We question if that change is necessary and if it is beneficial.

Business logic is ephemeral, preferably stateless and computed late.

In this context Business Logic means the application of an opinion. Business Logic can change. We are minimising that amount of work required to change that Business Logic allows the Product to react quickly to changing market demands.

Most products receive raw inputs, processes these inputs and provide outputs. The Product expresses an opinion as to what those outputs should be. For instance, when collecting event data, raw events are received, stored and presented in a report of some type. If you apply Business Logic only to the report, then it is easy to create a new report which expresses different Business Logic.

However, if Business Logic is applied to the raw events directly, or as an early part of the data processing, then changing the Business Logic is a more difficult task.

We design our Product with the expectation that the Business Logic will one day change.

Security is of paramount importance. Granting access to any part of your Product should be done in a considered way. Access is only allowed to those users and systems which require it — and only for the time that it is necessary — and only for the specific execution of their function.