I’ve seen source codes and approaches on how to organize it on several different languages, platforms, frameworks and libraries. I’ve noticed some similarities and the differences here and there. All, at first look is complex – but the organization of source code is with ideas in mind that, once grasped and learned, make diving into new code base in whatever project or language and learning whatever new, just shifting to problem domain or/and the syntax sugar differences on the specific new place.
The core characteristics of the “better way” of structuring code bring:
High Cohesion – it is the “density” of the programming code. It is – how much some logic, some algorithm, state or whatever – belongs and should belong to the certain module inside the programming code.
Low Coupling – If the code is structured well enough – the references between the code modules and layers are very strict – there are few and very meaningful semantically. If several modules get involved in several other modules with and without any meaningful reason, the codes starts to turn into spaghetti.
Single Responsibility – Atomicity – a source code module should do only one thing and it should do it well. When the code has a good hierarchy, a module from one layer does not mess with code within the same layer and only uses code from the “below” (semantically speaking).
Testability – It is linked with the above. If a module does not depend on others, or on specific environments, user interfaces, and external specifics, a code test cases could be written and the code could become testable in the code level. When a lot of tests are written, any change will be verified immediately – if it breaks the old – legacy code.
Adaptability & Extensibility – They are linked to all above. If there are too many tests written, the code could become a little bit more time consuming to change because any change in the logic will require change in the test – which is OK. If a layer has dependencies only to lower level of the code – changes in the lower level will require changes probably up to the most top module that uses it. If everything is well designed – every layer above will not require additional change. If the functionality is well modularaized – for example in OOP terms – Strategy Design Pattern – a change of the functionality will not mess any dependent module and the new code will require just small plugging in, not rewriting everything. The same is true when using Listener Design Pattern.
All these words and features of the code – from the structural, organizational, architecture point of view – is what gives the magic of the Professional Enterprise Source Code.
I’ll enumerate the places where I’ve seen that kind of structure with several variations here and there.
- Java, Groovy
These are most of the languages I have worked with. Probably the same structure is applicable in all other types, kinds and variations of languages – so any new incoming member of a programming team could jump in right away.
In terms of SQL, it is tables, in other environments – plain old (Java) objects, Domain Classes or whatever name an organization or language developer puts into the language. The model holds the structure of the information in the application – The data models, data properties and their types, relationship between the models and more.
Data Access (CRUD and more)
In SQL – it is views, procedures/functions. If done this way, the underlying table structure could change, but while the interface of views, procedures and functions to the external world is not changed, no additional code updates may be required. The SQL Triggers are a helper that embeds the listener design pattern within the database and could also be used for some application logic, data integrity and more.
In general purpose languages – data access layer glues the service layer with the specifics of the storage layer – the different database requirements and maybe here could be included some caching optimizations and frameworks. The idea is the Service and beyond layers – to not know about specifics in the way data is saved so, if changes are required – to be in this and model and/or SQL layer.
In client side applications there could be several modules and layers that have this type of functionality. Mobile Applications and web sites developed as apps could store some data offline and could also hit the back-end systems for data and / or operations. According to business requirements and logic, some data may be loaded offline without any REST call, other information or request may be only from the servers, and there could be a mix – for example – depending on internet availability.
Service – The Service layers could have some business logic and mix up several data access operations – according to the application requirements.
SQL procedures and functions that use views, procedures and functions could be viewed as a service – and called from external application directly – making the requirement for using the app – a very thin external layer. In the code that I have viewed – this is the legacy and the old way of implementing database dependent systems.
In the front-end world the Service layer could also be named – ViewModel (from the MVVM pattern). In back-end systems it could be Controller. Also – in many cases the application logic is mixed between the Service and the Application layer – for example in HTTP Interfaces to execute the logic directly on the response, instead of loading and unloading bytes into memory.
The more recent code that I’ve seen puts a lot of code in the application language – data access, service and application layer for several reasons.
When logic is in the general purpose language code (Application Server) – new solutions may be plugged in. For example caching systems, Messaging Systems and even, for frequently used data – it may be kept in the RAM memory of the server. These open ended options for improvement – makes the back-end system more scalable horizontally as well as vertically.
While many database system also offer these types of improvements, they also come with price – in terms of dollars and in terms of options. When this option is chosen – the optimizations of the database systems are provider specific and cannot be moved onto another.
For example – a caching solution may be kept and be independent from the database system that stores the information on the hard disk. When code is in the application layer – also many other open source and closed source solutions may be embedded. And of course that brings integration issues very often, but – there is no perfect happiness.
Application and/or client layer
The application layer could be – for a back-end system – web (HTTP), plain socket, messaging system ( RMI, Kafka) and whatever is needed. In a Desktop app – it could be plain socket or a Desktop Graphical or Command Line User Interface. In a mobile world – the user interface may be graphical, voice, some Internet of Thing device – like the voice assistants (microphone with speaker), a car or whatever other hardware or software system.
For most of the systems – there are architectural need to structure separately the back-end and the front-end, but the same way for organizing code will make it more maintainable and easier to understand, learn and dive into the business logic specifics, instead of trying to understand, learn and handle – framework or custom source code modularizations.