3 buckets

How To Partition A System (Part 2 – The 3 Buckets)

3 buckets

 

Yesterday we started a new series on How To Partition A System. I want to explain the thinking process I use to split a system up into modules and components. When done well, a system partitioning renders the whole and its parts more understandable and more tolerant to change. The pieces of code will be more reusable as well. System partitioning is a big deal.

Today’s instalment is also available on YouTube.

OK, let’s get back to where we were with our Register() method: 

(If this looks unfamiliar you can read yesterday’s article here.)

 

  public Customer Register(CustomerRegistration registration)
  {
     Validate(registration);
     var customer = registration.ToCustomer();
     Repository.SaveCustomer(customer);
     
     // *** START - Send the new customer a Welcome email ***
     string welcomeEmailBody = BuildWelcomeEmailBody(customer);
     string welcomeEmailSubject = "Welcome to ABC Finance!";
     MailMessage email = new MailMessage("info@abcfinance.example.com", 
                                         customer.EmailAddress,
                                         welcomeEmailSubject,
                                         welcomeEmailBody);

     var smtpHost = ConfigurationManager.AppSettings["SmtpHost"];
     SmtpClient smtpClient = new SmtpClient(smtpHost);
     smtpClient.Send(email);
     // *** END - Send the new customer a Welcome email ***

     return customer;
  }

Note: I noticed that much of the new customer Welcome email code is concerned with building up the email body. I have extracted this into a separate helper method, BuildWelcomeEmailBody(), not shown here. 

The SOLID Single Responsibility Principle states that we should partition our software into classes that have only one responsibility. But how do we determine what these responsibilities are? 

I have an answer: The ‘3 Bucket’ Technique: For a method call in that originates in business logic and ends up making a call outside of the system, (e.g. database, remote service, file system, device, etc.) the involved responsibilities can usually be segregated into one of 3 buckets

  • A Bucket that contains the general business logic workflow, and
  • A Bucket that includes the general mechanisms, and
  • A Bucket that bridges the responsibilities of the first two buckets.

Bucket 1

Contains just the high-level workflow, the WHAT we are trying to do. In our Welcome email example, we haven’t reduced our code to this essential responsibility yet:

bucket 1

Bucket 3

There is a reason why we’ve skipped Bucket 2. Bucket 3 contains the code that is concerned with general mechanisms. In our example, this is the code that has to do with sending emails in general:

 bucket 3

Bucket 2

This bucket bridges the gap between the other responsibility buckets. It sits between Bucket 1 and Bucket 3. Here lives specific code connecting the general workflow to the general mechanism. What do I mean? Our example makes this clear: Bucket 2 contains the programming connecting up the general workflow, in Bucket 1, i.e. that we’re making a call to send a Welcome email, and Bucket 3, that we are using a generic emailer. Into Bucket 2 fall these responsibilities:

  • Formating of the customer Welcome email subject and body
  • Who the email will be from,
  • Packaging up the email message, so it’s ready for sending.

bucket 2And here is an image of how the Buckets fit together:

3 bucketsThe ‘3 Buckets’ Approach works in many other contexts too. For example, When saving the customer, we have in Bucket 1, the general call to save the customer in RegisterNewCustomerUseCase.Register():

  Repository.SaveCustomer(customer);

Assuming our database is, say, SQL Server, in Bucket 3, we will have a general data access library. Bucket 2 will bridge the gap. It provides code to convert the to-be-saved-customer into the database models utilised by the Bucket 3 general SQL Server data access code.

That’s it for today. I hope this made sense. Please let me know if there are parts where my explanations were lacking. Same if you didn’t understand something.

Next time we’ll look at ‘abstracting away’ the Bucket 3 generic emailing functionality. Such a move will allow us to plug in different generic emailing technologies. 

 

Continue with How To Partition A System (Part 3 – General Emailer)

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply