Contemplating layering

This is going to a somewhat technical post, be warned :)

Currently I am working on a project where I have to build a web application that allows users to search a large database with user data (an LDAP database). This web application is actually composed of 2 separate applications that communicate with each other using a Web Service. One of them you can call a front-end application, which contains the web pages, the front-end logic (like sorting results) and a client for the Web Service. And you can call the other one the back-end application, which hosts the web service, the domain logic and the logic for communicating with LDAP. In this post I want to focus on layering in the back-end application.

layers

When I write software, there are always good software design principles in my head, like: keep methods short, make your code readable, seperation of concerns, minimize the side effects, etc. Now, in deciding how to package my back-end application into deployable components, I learned some great lessons from the design principles by Robert C. Martin (Uncle Bob). And especially the fact that different parts of the application may evolve at different speeds helped me to decide to define the components.

Now in this application I actually had 3 components:

  • a Web Service component that exposes the domain logic to the outside world
  • a domain component that contains all the domain logic of search for user data
  • an LDAP component that implements the domain logic using LDAP specifics

And to have maximum flexibility, I wired the dependencies like this:

  • the Web Service component only knows about the the domain component, since it’s only purpose is to expose domain logic to the outside world. The Web Service component doesn’t know anything about how the domain component does that, so it could be an LDAP database, a SQL database, text files, some over enthusiastic employee typing in responses in real-time, etc.
  • the domain component only knows about itself. It even doesn’t know anything about external frameworks
  • the LDAP component only know about the domain component, since the purpose of the LDAP component is to implement the domain logic using LDAP
  • all these components are wired using Dependency Injection, which means that these components are connected to each other by means of an external configuration file

This setup makes the design extremely flexible, and these components now can evolve separately from each other without breaking (or just re-deploying) the other components. It also allows for swapping components, like using a REST Web Service instead of a SOAP Web Service to expose the domain logic to the outside world without touching the other ones. And using a SQL database instead of the current LDAP database without touching the other components.

Though I am quite content with this separation of concerns, this flexibility, and this independence, yesterday I ran into a point where I decided to create another component, namely, a specific LDAP component. The reason for this is the following: the current LDAP database we’re using contains inconsistent data. There are many parties responsible for delivering their own data to this LDAP database, without complying to certain standards (at least they appear not to be strict enough). The result is that the LDAP database is cluttered with attributes that are filled for one person, and left out for another person. In order to deal with these inconsistencies, I had to write some logic that deals with this.

But the point is this: this logic that deals with these specific inconsistencies, is not representative for all LDAP implementations. You can see this kind of logic as some sort of anti-corruption layer. The general purpose LDAP logic is now located in the other LDAP component, and specifics for dealing with inconsistent data is now located in this new LDAP component. With regards to flexibility this decision means that you can swap from one LDAP implementation to another without touching the original LDAP component. Or it could also mean that if the organization manages to fix the data so that it is consistent again, this new LDAP component is the only one that needs to be modified (or it may even become obsolete).

Even though I am quite satisfied with this decision, more components also means a need for more decisions: “where should I put this piece of logic, is it general purpose LDAP or is it specific LDAP?”. The direction of my thinking is to make the general purpose LDAP component implement the domain logic as much as possible, and then only put the exceptions in the specific LDAP component.

Anyway, it’s really nice to think about layering, responsibilities and dependencies, and trying to make it as flexible and independent as possible.

  • Share/Save/Bookmark

Leave a Reply