5. Code architecture

5. Code architecture #

Code architecture - way of organizing your code.

Organizing your code in a meaningful manner helps when you want to maintain, extract parts of it, create libs, test, define the visibility.

Updated code and source examples are located here : github.com/becoming/code-architecture/

We can distinguish 2 main types of architecture of the code:

  • Feature based.
  • Layer based.

Feature based #

In a feature based architecture you group files in packages by their BUSINESS meaning.

This can be useful when you are building monoliths, apps that are doing multiple things. One monolith can do multiple jobs in one single domain, as well can do multiple jobs for multiple domains. It all depends on how big it.

There are developers who are using layer based architecture even in monoliths. This is far from being optimal as each and every packages has lots of classes and when you think about developing a feature, you need to pay attention of what class you change as it might impact multiple features at once.

The bigger the monolith is - the harder is to maintain it.

Use case #

We have one monolith for all the use cases:

  • manage the users.
  • AND their image galleries.
  • AND the uploaded files.
  • AND a basket for this e-commerce website that sells images (like https://www.shutterstock.com).

Example #

Here’s a list of commonly used packages and examples of files names inside:

  • user - UserController, UserService, UserRepository, UserEntity.java, AddressEntity, CountryEntity, AddressValidationHelper
  • card - CardController, CardService, CardRepository, CardEntity

Here’s a visual example:

Special cases #

If one of the feature packages becomes large, you can always start using the layered based architecture within the feature package. At some point you’ll start to think that it can be a good idea to extract this particular feature into a dedicated microservice. Or an application that runs on its own.

In some cases you might need some kind of core package that hase the common functionality. Generally speaking it is a good idea to extract this to a external library. Or create the needed function next to the actual usage.

  • core - StringHelper

Layer based #

In a layer based architecture you group files in packages by their TECHNICAL meaning.

This can be useful when you are building microservices. One microservice is supposed to do one job in one single domain.

Use cases #

We have multiple microservices, one per use case:

  • manage the users.
    • CRUD for a list of users.
  • image gallery.
    • manages the albums and their information.
    • have references to the actual files from another microservice.
  • file service.
    • CRUD for a list of files and their metadata.
  • basket for a e-commerce website.

Therefore, we are expected to have only one feature that is to be covered by the code of the ┬Ás in question.

Example #

Here’s a list of commonly used packages and examples of files names inside:

  • controllers - UserController, CardController
  • services - UserService, CardService
  • repositories - UserRepository, CardRepository
  • entities - UserEntity.java, AddressEntity, CountryEntity, CardEntity
  • helpers - AddressValidationHelper, StringHelper

Here’s a visual example:

ArchUnit - Test the architecture #

In case you plan to unit test the architecture or the applications you work on, one the greatest solutions is : https://www.archunit.org/.

It’ll help you easily describe tests who’ll check that all the naming conventions are in place. There are no useless packages, badly named classes, etc.