DEV Community

Cover image for Assigning class responsibilities with GRASP
Bohdan Stupak
Bohdan Stupak

Posted on

Assigning class responsibilities with GRASP

This article was originally published at Codeproject

Toy example

Wandering through codebases I've encountered some examples of code where ReSharper issues warning "Method can be made static". Although fix seems straightforward the warning itself may hide more subtle issue connected to object responsibility assignment.If you've never used ReSharper still stay with me. I hope you'll find easy to catch up.
Let's take a look at the following code

public class EmailConstructor
    {
        private const string Signature = "Regards";

        public string Construct(User recipient, string body)
        {
            var builder = new StringBuilder();
            builder.Append($"Hello {GetNiceUserName(recipient)}");
            builder.Append(Environment.NewLine);
            builder.Append(body);
            builder.Append(Environment.NewLine);
            builder.Append(Signature);
            return builder.ToString();
        }

        private string GetNiceUserName(User user)
        {
            return $"{user.Name} {user.Surname}";
        }
    }

    public class User
    {
        public string Name { get; set; }
        public string Surname { get; set; }
    }
Enter fullscreen mode Exit fullscreen mode

Indeed ReSharper issues the warning.
ReSharper warning

Feature envy

Although things may seem obvious at the first glance actually the code above is the example of Feature envy. As the rule of thumb which would help you to spot such cases without using tools such as ReSharper, you may use one of the principles postulated by Craig Larman in his book "Applying UML and patterns".

Information expert will lead to placing the responsibility on the class with the most information required to fulfill it.
According to this principle, you can fix the warning my moving method inside the User class as follows as the User is the one who has more information to represent his name in one or another way

public class EmailConstructor
    {
        private const string Signature = "Regards";

        public string Construct(User recipient, string body)
        {
            var builder = new StringBuilder();
            builder.Append($"Hello {recipient.GetNiceUserName()}");
            builder.Append(Environment.NewLine);
            builder.Append(body);
            builder.Append(Environment.NewLine);
            builder.Append(Signature);
            return builder.ToString();
        }
    }

    public class User
    {
        public string Name { get; set; }
        public string Surname { get; set; }

        public string GetNiceUserName()
        {
            return $"{Name} {Surname}";
        }
    }
Enter fullscreen mode Exit fullscreen mode

High cohesion

Naturally, the question arises from the example above: "Won't this lead to bloating User class with lots of responsibilities such as, for example, working with persistent storage?". The answer is that Information expert principle should be used together with High Cohesion principle.

High cohesion is generally used in support of low coupling. High cohesion means that the responsibilities of a given element are strongly related and highly focused. Breaking programs into classes and subsystems is an example of activities that increase the cohesive properties of a system. Alternatively, low cohesion is a situation in which a given element has too many unrelated responsibilities. Elements with low cohesion often suffer from being hard to comprehend, hard to reuse, hard to maintain and averse to change.

Thus if we, for example, would like to extend our toy code with persistent storage interaction we would likely extract highly cohesive functions dedicates to that into some sort of Unit of Work pattern.

Conclusion

Static members have some disadvantages such as they complicate unit testing. That's why static should be considered with care. Craig Larman's GRASP patterns in combining with SOLID allow us to examine such cases in order to reduce support cost of our codebases.

Oldest comments (0)