A readable design is one of those things that every developer wants, most the developers probably think they already have, and the rest debates what it actually means.
Instead of joining that discussion, this post briefly describes the tools we have at our disposal to make something more readable or less readable, and then compares a widely adopted style prevalent in the Java Enterprise field, with a more object-oriented solution of the same problem. This comparison is based on the design and re-design of a real production application.
A design is more readable than another design if a person understands what it is doing and how more easily. This definition is dependent, of course, on the person doing the understanding. Although we can assume that that person is somewhat familiar with the business cases the application is supposed to cover and is at least to some degree versed in reading designs or code, it is still a subjective definition.
What concepts one person finds important might not be that relevant to somebody else. A concept is a piece of information about the design or application that can be virtually anything: “This application is about banking” is a concept, “it has Users” is a concept, “users can transfer money between accounts” is a concept, “a user has to be authenticated to transfer money” is a concept, “it uses Hibernate” is a concept, “it uses the MVC pattern” is also a concept.
Although it would be probably futile to try to discuss which concepts are objectively more important than others, what we can perhaps objectively discuss is how to make a concept more readable or less readable in a design. There are multiple levels you can express a concept on:
- Repository, Project, Module
- Method, Parameter
Not all levels are suitable for all concepts, but in general, the higher a concept on this list, the more readable it becomes. The first things we usually see are repository or project names, followed by package names, etc. The hardest to read, regardless how well written the code is inside the methods, because it just takes more time to read even one or two lines of code than a class or method name.
So, in general, we want to have concepts that we deem important higher on the list, and concepts that are not that important lower (so they don’t add noise to the more important ones).
The “Before” Picture
This is a simplified view of the business-relevant parts of an application that is supposed to allow registering IoT devices. Take your time and see what concepts you can spot.
The “After” Picture
Now try the same with this design (only if you finished the first picture, don’t cheat!):
The first design is based on a very common style, using beans (classes with mostly just setters and getters) and services (or controllers) where the actual logic resides. Let’s try to go through visually what concepts are recognizable in the order of apparent importance:
RegistrationControllerseems to be the central piece of the design. It takes a
RegistrationRequestwith a lot of parameters and produces a JAX-RS Response.
- One of the used functionalities for the registration is authentication of Users. Obviously the system has
- The system also has
Devices, both managed by the appropriate “Manager” objects, with all of those known by the
Devices have IDs, probably for persistence used by their relevant Managers.
From here on it gets arguably difficult. All of the beans have public accessors to their fields; it is difficult to know which ones are important which ones aren’t, some might even be optional. We don’t really know any details of the registration process, so we have to start reading code to understand how these supporting objects relate to each other.
The second design is more object-oriented, which emphasizes the business functionalities the application has to support instead of the data it has to have. Let’s see what we can determine from the diagram:
- There is no central piece that knows everything; instead, it seems to be composed of three things:
Customers can be found in the
CustomerRepository, based on a
Customerseems to be the entry point for both
Usercan register a device using some parameters, which gives back a
Devicecan generate a JAX-RS response based on a challenge.
With this design, one might even speculate what the registration process looks like, since all the ingredients seem to be there. Let’s see:
- For a “customerId” (and a
CustomerRepository) one can get a
- From there, a username and password would lead to a
- If all the parameters are known for the
registermethod, one can get a
Deviceobject from the
- After that, there is some sort of “challenge” the
Deviceobject apparently needs to answer.
One might also notice, that the
Device also seems to be capable of authenticating itself and getting a response for a challenge without a registration.
The Real Story
The application is about keeping a registry of IoT devices. The application is multi-tenant capable, that is, there are multiple customers who use this registry as software-as-a-service. This is the reason both users and devices are only meaningful in the context of a customer (a company who owns IoT devices).
To register a device, a user (a representative) of a customer (a company) has to log in. This user submits the relevant information for the registration, including a challenge. The server uses the challenge to cryptographically sign the response using the appropriate certificates to prove the server’s identity to the device directly.
The device then can log in with its own username and password (that it got during the registration), independently of any users, and can even challenge the server again to prove it is registered.
This post demonstrated a common Java style based on beans and services and compared it to a more object-oriented design. The two designs emphasize different aspects of the application; they make different concepts more readable.
While the more common beans and services design focuses on the data and information the application has to handle, emphasizing some technical details how this is done together with coarse-grained business-related functionality, the object-oriented style concentrates on the business-related functionality on a finer grained level to the detriment of details about data.
Which style is more readable to you? Which style tells more about the real story to you? You decide!