Marco Nicolodi
Jan 22 · 5 min read
is responsible toPhoto by Mael BALLAND on Unsplash

At Qualyteam, we are continuously improving. Therefore, we love code refactoring. Identifying problems and improvement opportunities in code is an important skill every developer should have. This week I was reviewing code that had a small change in a legacy code base method. It was a small, long forgotten piece of code. We usually balance between the importance of the touched code and the quality it must have. If it’s something that we know that is barely going to be touched in the future, we just let it go and move forward to something our clients are really going to care about. But I wanted to play around. And to have something to write about.

The Code in question

The touched code is a 10 year old Webforms method that returns a CSS class name based on some parameters. I abstracted away the ASP.NET stuff and created some pseudo classes so you can focus on the subject, the GetClass method. Don’t bother about the code details, just focus on the method structure, specially the ifstatements:

I wanted to make this code more meaningful. You can notice that given some local variables created from the method parameters and some class properties (lines 9 to 13), which we wil call “request”, the code passes through a chain of conditional statements, which we will call “rules”, the first one being if(hasEvaluation) . This rule has the priority on the chain. If it can’t deal with it’s concerning slice of the request (evaluation), it passes the handling responsibility for returning the correct string to the next rule in the chain. The next rule gets another slice of the request (hasEffectiveness) and deals with it or passes the request to the next rule. So:

Given a request, a rule can choose either to handle the result, or pass this responsibility to the next rule.

There’s a design pattern for that.

Meet the Chain of Responsibility

From Wikipedia:

The chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.

From RefactoringGuru:

Chain of Responsibility is a behavioral design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.

Looks like what we need, right? But how would we implement this? Well, since it’s a Gang of Four’s, well documented, 30 years old design pattern, there are already a lot of examples out there! Here’s the UML diagram:

So we must create an abstract handler.

The abstract handler SetNextmethod will be responsible for setting the next handler on the chain.

Each rule will extend this handler and override the Handle method and decide if it should handle the request, or pass it to the next handler.

The abstract class Handler method calls the next handler Handle.

We don’t have a request object yet. Let’s create it. It’s the object that is going to be passed through the chain. It must contain all the data required by the handlers. In our case, it’s just a Data Transfer Object (DTO) that stores those GetClass local variables it created at lines 9 to 13:

The object that’s going to be handled by each rule

Now our GetClass method looks like this:

Before moving on, we should get rid of these repeating hardcoded strings, so our code responds easier to future changes by storing the string values in a single place. Let’s create a label class with some static factory methods :

Future proofing by keeping hard coded strings in a single place

Now we know that our chain of responsibility should handle a Request and return a Label . Let’s create our abstract handler based on that UML diagram:

The Runmethod is going to be overridden by each rule, which will decide if they should either yield the Labelto the client or delegate it to the next rule.

The SetNext method will not be overridden, but will be used in client code to set the chain in the right rule precedence order. It returns the next rule so we can set the chain using a fluent API. Now let’s create our first rule.

If you remember from the GetClass method, this is the first one:

We need to create a class that inherits from the abstract RuleHandler , overrides itsRun method and decides if it should return the proper Label or pass the request to the next handler.

Based on the stuff the conditional statement is checking, I’m going to call the rule CriteriaHasEvaluation :

Notice that I’ve used the Label class instead of the original code’s hard coded strings.

So, given the request, the rule checks if it should yield the result or delegate it to the next handler. This is the drill, and the next rules are going to follow the same structure. But let’s make another one just to get used to it. The next rule in the chain is:

I’m going to call it EffectivenessAssessmentPending :

I’m going to skip the creation of the IsNew and CriteriaEvaluated rules, so we can go straight to our client code.

Now we have a bunch of rules. We need to set the precedence of them, run the chain, and return the result.

We’re going to use the SetNext method to assemble the chain, respecting the rules precedence. Then we are going to Run the chain, and return the result. The client API surface is now so simple, that I’m going to show the final GetClass method after the refactoring:

So we set the chain using the abstract RuleHandler’s SetNext method. It sets the next rule to the current rule, so when we call Run we run the chain in the set order. It returns next rule, so we can set the chain… chaining methods!

It’s way more clean than the old code right? Take a look at it again:

We removed the hardcoded strings, moved the conditions to self documenting rules, and left the code cleaner

Generics

The client code is cleaner, but we created some boilerplate code, like the abstract RuleHandler . This abstract class can’t be reused, since it returns and handles only the types we needed for this particular use case(Request and Label ). We can reduce the amount of boilerplate code used to create a Chain of Responsibility by using C# Generics.

Making the rule handler generic

Now we can reuse this generic abstract rule handler in other chains. We just need to specify the types when creating a rule:

Extends RuleHandler<Request,Label>

Wrapping Up

Kinda over-the-top? Yeah, I just wanted to show a real world example of a design pattern use, because sometimes everything seems so abstract and academic. But there are plenty of other interesting use cases, like tax processing, ordering pipelines, and you’re probably using something similar like an API middleware. I have a login pipeline simulation in an open source repository here.

The Chain of Responsibility has another cool feature: It’s composable. You could reorder the chain’s rules precedence based on run time conditions. Pretty flexible right?

If you use an object oriented language like C#, PHP or Java it’s nice to play with some Design Patterns, because sometimes you can come up with an elegant solution to a hard solving problem, or at least have a lot of fun!

Qualyteam Engineering

Time de engenharia da Qualyteam.com

Marco Nicolodi

Written by

Software Engineer

Qualyteam Engineering

Time de engenharia da Qualyteam.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade