UML & SOLID — IN PRACTICE

Domain Modelling of an email client

In the last post, I explained the basics of class model diagram and relationships among them.

In this post, based on our previous knowledge, we will do the modeling of a simple email client

Email Client Requirements

  1. User should be able to give username and password for the account
  2. User should be able to send email through selected email service
  3. User should be able to receive email through selected email service

So basically, above requirements boiled down to this

  1. Initial email account configuration
  2. Send email functionality
  3. Receive email functionality

Now, pull out your UML designer and read through the requirements again to figure out which could be the entity in your domain model.
For the above requirements, having a Class MailClient looks like the most obvious model which could have initialConfiguration, sendEmail, receiveEmail methods.

Our first iteration of Class Diagram looks like this.

if you are wondering what are those relationships, please refer to my previous post basics of uml

  • initialConfiguration method will do the initial set up of email account
  • sendEmail will perform the action of sending email through registered service
  • receiveEmail will perform the action of receiving email through registered service

Above Class Diagram will transform to the JAVA pseudo code like this.

Its Review Time !!

Violation of “Single Responsibility Principle”

Violation of “Open-Closed Principle”

Violation of “Dependency Of Inversion”

Let’s understand this with an example, as per our design, we are creating the object of low-level email services directly in our high-level class Class MailClient.
In future, suppose we have to upgrade from GMailLowLevelClass to updated GMailLowLevelClassV2 class then developers have to make changes everywhere in high-level code wherever GmailLowLevelClass is being referred.

Did you realize, our whole discussion revolves around three terms

  • Better encapsulation i.e. Single Responsibility
  • High Cohesion class and low coupling within classes at same level
  • Abstraction between high-level class and low-level class hence low coupling

Let’s do it right !!

Fixing — Single Responsibility

So idea is to work like this

  • Class MailInit will initialize the account configurations and store it in Class MailAccountConfiguration
  • Class MailClient methods will use Class MailAccountConfiguration to connect to the appropriate email service.

After incorporating the above considerations, our domain model would look like this

Above Class Diagram will transform to JAVA pseudo code like this

Its Review Time Again!!

In our next design, we will fix the violation of Open-closed and Dependency of inversion principle.

Fixing — Open-closed and Dependency of Inversion

  • Create a new interface EmailServiceProvider and wrapper of google and yahoo email Service which implements this interface
  • Change data type of MailConfiguration.emailServiceProvider from String to EmailServiceProvider

After incorporating the above considerations, our domain model would look like this

We have created an aggregation relationship between MailConfiguration and EmailServiceProvider interface because MailConfiguration holds the reference of the EmailServiceProvider as one of its attributes. For more info refer basics of uml

Above Class Diagram will transform to JAVA pseudo code like this

P.S.: In the above code, I have kept variable names verbose to make it easy to understand the psuedo code.

Addition of HotMailEmailService

Here is the JAVA pseudo code of the above Domain model diagram.

Take a look carefully to add a brand new HotMailService, we have made the changes in existing code just at once place Class MailInit ( line: 19 ) in order to register this new class to the system.
Rest of the code is not modified but extended by new class HotMailService( line: 86 ).Hence our design follows Open-Closed Principle because the addition of new feature does not have cascading effects.
Our design also follows Dependency Of Inversion Principle as any changes in any low-level library are contained through EmailServiceProvider interface. Changes in low-level APIs does not have an effect on high-level class.

I hope it explains how thinking through the design of application through UML or equivalent can pave the way for developers to make their code really reliable, scalable, maintainable.

Product | Technology