On Software Architetture(s)

Every piece of software written has an architecture. Yes, even a bash script has a (embryonal) architecture: it has input, output, and satisfy some kind of feature (or features).

There are a number of viable choice for implementing or adopt an architecture for the code you are going to write.

Why is important to know it

Why is so important to be aware of it? If having an architecture is an intrinsic property of any software, why should you care about it? The answer relates to:

  • feature list
  • requirements
  • problem domain
  • time to market

All these aspect, and more, should influence the choice of the software architecture is going to be adopted, and so the code that need to be written.

Framework adoption

Whenever, and whatever, one adopt a framework for implementing a feature set, respecting requirements, the developer team is selecting an architecture for the software that will be produced.

A Framework is a kind of ready-to-use pattern that (generally) fit a specific kind of problem. Typically a framework implement a well known design pattern, MVC is the most common provided, but also Agent oriented for supporting concurrency.

Every language has its own set of frameworks, and it is common to find the same kind of feature list.

A framework feature list is something different from a software feature list: a software feature list is related to the domain of the application, while a framework feature list is related to the design patterns it supports.

Advances of adopting a framework are:

  • Sometime the framework impose the structure of the code (but when this happens it is for good reason, for example Android framework impose the use of intent, the use of well defined methods for create/start/resume/stop/destroy lifecycle of an Activity, and other things that an android application must respect. So, if you have to provide code for lifecycle someway, this is not a cons, if you are porting your code to a framework it may be challenging
  • You start quickly, implement just the minimal staff, and it is ready for the market.
  • Often a framework provide a testing suite, so unit test would be easily written, and code smell fixed as soon as you start coding

Library adoption

Clearly stated, a library is not a framework, but the use of a framework does not exclude the adoption of additional library.

What I mean here with “library” is a library providing design pattern, as defined by the Gang of Four.

Every programming language has their own set of library (PHP has lavarel, symfony, fuelPHP, etc. C++ has the STL).

These kind of library (providing design pattern) are effective on OOP (of course) and more useful on language supporting generics.

The language support for generics (someway) is key factor for the success of a OOP library.

Other kinds of library are utility library, supporting for example compression, that agree with the language convention (i.e. Stream API)

Distributed Architecture: Miniservice vs Microservice

On cloud based application, it is common to adopt an extra-code architecture.

The idea to have an extra-code architecture is someway frightening: so you loose control on how the process is going on.

This is a real problem, in fact to mitigate the loose of control there are some well known strategies:

  • Implement Observability: by instrumenting the code to export metrics in opentelemetry, readable by data visualisation tools such as Prometheus, Graphana, InfluxDB, etc.
  • Adopt a message broker: rely on a well known, distributed, message broker, lower the risk of data loss during the process workflow (or feature workflow)
  • Adopt a fast db for data sharing/storage: typically a NoSQL DB, such as MongoDB, CouchDB, etc. but also a TSDB (Time Series DB) useful for example when implementing CQRS architecture in a distributed environment

Miniservices are separate, loosely-coupled components, just like microservices, but in the business domain rather than the business domain feature.

featureMicroserviceMiniservice
rely on external Message BrokerNatively. Each µService is designed to scale-on-loadit is possible and useful, but at scalability is more expensive in term of state-management and concurrent resource access.
statefulnessJust keep track of a single payload and resultKeep track of domain related feature, that can involves a more complex job made of a complex transient state
access to shared dbIt access shared resource just for specific payload, in defined point of execution (task start, and task end)It may require multiple access to shared db, during the fulfilment of a feature request. It may requires lock or internal state management

The main difference between Miniservice and Microservice is about number of feature and scalability:

  • microservice is smaller, just implement one feature, and scale easily by the mean of external orchestrator
  • Miniservice is generally bigger, scale vertically, horizontally only if designed for it, it implement more features, all related to a given domain

Microservice is more fine-grained and the choice of this architecture should be guided by some requirements:

  • the microservice is used by more than one service
  • most of the time is stateless
  • it needs to scale for adapting to the workload

Example of microservice is a microservice producing PDF document from a template defined in a agreed template format (let’s call it template-to-pdf). template-to-pdf can be used by more different service requiring the PDF production, it must scales as soon as possible to be ready to produce a new document (strange but true: PDF production is a resource consuming task), and is not domain specific.

Note that miniservice architecture does not exclude microservice architecture: miniservice group all domain related features, while relying on microservices for some specific feature.

Miniservice & Microservice in Kubernetes

Kubernetes can serve the fine-grained scalability of microservice, still keeping the domain based decouple character of a miniservice. This is done by Service object:

  • Service routes the request to every single feature implemented by microservice
  • Service collect all the feature related to a well defined domain

A Deployment for a microservice implementing a single feature scales by HPA (Horizontal Pod Autoscale) feature, based on metrics. Metric can be taken from the message broker queue size, so adapting to the current system load.

Design Patterns & Architectural Patterns

Since the first idea do adopt pattern for designing software, people started to adapt, and adopt, the pattern for every kind of software field. It is more simple to talk about pattern, it is simple to share knowledge and to work together on something, it is more simple to find a solution because, someway, the problem is a declination of an already solved problem, probably on other domain: it just change the names, not the methods.

Also Patterns can be composed, used together, to implement a completely new software, still adhering to well known idioma.

Architectural Patterns differ from OOP Design Pattern because (at least the original patterns listed in the book of GoF) the former deals with concurrency and asynchronicity of action.

Architectural Patterns often include the usage of:

  • NoSQL db
  • RDBMS
  • TSDB
  • Supporting service
  • Message Broker
  • Orchestrator
  • Communication Channel
  • Segregation (for security)

Not necessarily all these staff, but also some more.

Reference

Fundamentals of Software Architecture, 2nd Edition