Refactor a 6K Line of Code Domain Class

I have been working on a legacy project. It is a complex and big system. Throughout the codebase, there is a big domain object class.

How big is it, man?

Not much dude. It is just 6k (6.000) line of C# code.

One day, I found out a way to improve it. So the story begins.

Once Upon a Time

Imagine that class is School. School will have a collection of Students, Teachers, Labors, Rooms, Chairs, … The School class is a root domain. Therefore, they decided that all the methods must go through it.

There are typical patterns related to a collection: Add, Edit, Remove. Such as Add Student, Update Student, Remove Student, ..

It is a typical pattern we have seen many places. Except, that class became a ghost with 6.000 (6K) Line of Code. There are so many problems with such a codebase. But it is out of the scope of this post.

Pre-conditions

  1. Legacy code written with .NETt 4.0 (and still must be in 4.0).
  2. NHibernate as ORM framework.
  3. Look like DDD with CQRS (even none of them are actually true).
    public class School
    {
        private readonly IList<Student> _students;
        private readonly IList<Teacher> _teachers;
        private readonly IList<Room> _rooms;
        private readonly IList<Chair> _chairs;

        public virtual void AddStudent(Student student)
        {

        }

        public virtual Student FindStudent(Guid id)
        {
            return new Student();
        }

        public virtual void Update(Student student)
        {

        }

        public virtual void Remove(Student student)
        {

        }
    }

    public class Student
    {
        
    }

    public class Teacher
    {
        
    }

    public class Room
    {
        
    }

    public class Chair
    {
        
    }

There are a couple of things to remember first

  1. It is a legacy codebase. Which mean we did not design it in the first place. We took it over.
  2. Time is limited. Documentation is a luxury to have. In short, we cannot just rewrite or redesign it.
  3. It is painful.

How to refactor?

The goals should be:

  1. Reduce the number of line of code. Kill the ghost.
  2. Keep the visibility protection at the domain level. In DDD, the setters are protected or private.
  3. Improve responsibilities management.

Sometimes, Visual Studio has problems with opening the class 🙁 Poor it!

Superstar Needs Managers

The idea is quite simple. I got the inspiration from Superstar Metaphor. A superstar has many things: Properties, Cash, Connection, Style, Contracts, … Everything is attached to them. However, there is no way they can manage by themselves. They need managers. They need a manager for each aspect.

  • Property Manager: Manage properties
  • Financial Manager: Manage finance
  • Style Manager: Manage style
  • And so on.

Apply Composite Pattern

With that Superstar Metaphor, we can apply on School class. It is quite easy with some simple steps

Identify Areas

First, we have to identify areas that need outsource to managers. This step depends on your project context.

In our silly example, they are Student, Teacher, Room, and Chair.

Hide Managers

In Visual Studio (code) it is simply creating new classes 😛

We have StudentManager, TeacherManager, RoomManager, and ChairManager.

Delegate Responsibilities to Managers

Move the logic to proper managers and keep the old interface for School.

Show Me the Code

Yes, Sir!

    public class School
    {
        protected internal readonly IList<Student> _students = new List<Student>();
        private readonly IList<Teacher> _teachers = new List<Teacher>();
        private readonly IList<Room> _rooms = new List<Room>();
        private readonly IList<Chair> _chairs = new List<Chair>();

        private readonly StudentManager _studentManager;

        public School()
        {
            _studentManager = new StudentManager(this);
        }

        public virtual void AddStudent(Student student)
        {
            _studentManager.Add(student);
        }

        public virtual Student FindStudent(Guid id)
        {
            return new Student();
        }

        public virtual void Update(Student student)
        {

        }

        public virtual void Remove(Student student)
        {

        }
    }

    public class StudentManager
    {
        private readonly School _school;

        public StudentManager(School school)
        {
            _school = school;
        }

        public void Add(Student student)
        {
            _school._students.Add(student);
        }
    }

I applied the manager approach for Student area. The same goes for other areas: Teacher, Room, and Chair.

Protected Internal Modifier

Instead of using private or protected, we use protected internal modifier. With this modifier, we protect the domain from outside assembly. That is we just moved from class level to assembly level.

This modifier level allows managers to access Superstar’s properties.

Hey Cool Man!

Yeah. Even I said so to myself. Some of the immediate result I got after 2-3 hours

  1. Reduce more than 1K LoC in the Ghost class.
  2. Create managers to handle correct responsibilities.
  3. Feel a better control of the codebase
  4. Stop the trend of adding more code into the Ghost.

The best part is that, as a developer, I feel rocked 🙂 (yes, till now)__the feeling of getting a cool thing done.

Do Not Trust Your Memory

Every day we come to work. We check out our schedule. We join our meetings. They are normal sequences, behaviors. We have done over and over again.

Meetings? There are many meetings during our work. Some of them are meaningful. While others are a waste of time. Some people hate meetings …

How many people remember what have been discussed in a meeting?

I have seen this pattern in my daily work

  1. People come to a meeting room. Some might even not know meeting’s topics. Sad but true.
  2. They sit on a chair, listen to the speaker.
  3. The meeting ends. They leave.

So far so good. A typical meeting. Except, many of them do not remember what being discussed, agreed in that meeting.

Why?

They had thought that they would remember.

Don’t Trust Your Memory

I, once, read from a book that statement. Don’t trust your memory. If you want to look in the “why”, then ask google.

Don't Trust Your Memory
Don’t Trust Your Memory

There are so many researches about it.

And here is my most favorite author, Mr. Jim Rohn.

Jim Rohn Quote
Jim Rohn Quote

Take Notes

There is an easy solution: Take notes. You can bring your paper/pencil or electronic devices to meetings; you take notes in ways you like most.

But there is an ugly truth. I still have not seen people taking notes in a meeting. They still come to meeting in bare hands. I kept asking myself, why do they not take notes? Maybe they do not see the values out of it.

Value. Yes, human works base on it. Let’s try to find values from my point of view.

A Tool to Remember and Review

Once we write things down, we increase the chance to remember them. That is an obvious fact. Think about the old days when you were in school. You wrote what teachers said. You took notes on your books.

Meetings might be boring. But with a notebook in our hands, we can review what we have noted down. We can jot down our new ideas, thoughts, or even drawing some fun images.

A Skill

Taking note is a crucial skill. However, it is not easy at all. People have to learn to master it.

Image we are in a meeting room, the speaker keeps talking, information flows, there are papers and a pencil in our hands, how will we start writing?

Professional

Not all meetings require taking notes. I do not mean that at all. We, as a professional, know what meetings are important. We, as a professional, must show our professionalism. We must try to put ourselves in the speaker’s shoes

We must try to put ourselves in the speaker’s shoes. One day, you are that speaker. You are the one who sends messages. And they just get lost. Feel that pain and show respect NOW.

How To Start?

Very simple folks!

  1. Buy a notebook (or some piece of paper) and a pencil.
  2. Bring them to every meeting you attend.
  3. Write something down. Do not care too much about what you write.
  4. If you do not know what to write, draw a circle, a face, a line. Just make sure it is different than before the meeting.

Soon you will know what to write. It is a skill. Skills are gained by practice.

Don’t you believe me? I was not born with the ability to write this post. I have been a terrible writer as well. Guess what? It does not matter. As far as I practice, I get better every day.

 

Improve Code with Static Factory Method instead of Constructor

Sometimes I have problems with my own code. I wrote a piece of code. Some months later, when I wanted to use them in other places, I had to look at their implementation. Other time, I had to dig deeply into my poor memory to find out why I wrote them.

Obviously, there is a need to improve the code quality__the communication. What? Code communicates?

I like to see code in this way

Code is a mean of communication.

When we write a piece of code, either a framework, a library, a class, a method, or even a line of code; it supplies a mean of communication between us and

  1. Compiler: We tell the compiler what and how to translate into binary code.
  2. Computer: The binary code will then instruct the computer does our business logic (our purposes)
  3. Developers: They consume our code, our API

The code does more than our initial thoughts.

Let’s improve our communication mean. A long road starts with the first step. Let’s start with improving constructor.

Note: I write in the context of C# (.NET) environment. You should find similar concepts in yours.

Constructor

As a developer, we have seen this code a lot

    /// <summary>
    /// A person with Name and Assigned To
    /// </summary>
    public class Person
    {
        /// <summary>
        /// Person name
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Assigned to (such as project name, task name).
        /// </summary>
        public string AssignedTo { get; set; }

        public Person()
        {
            
        }

        public Person(string name, string assignedTo)
        {
            this.Name = name;
            this.AssignedTo = assignedTo;
        }
    }

A very simple person class. Assuming that I want to use it in Project/Task

    public class Project
    {
        public string Name { get; set; }
        public IList<Person> People { get; set; }

        public void AddPerson(string name)
        {
            var person = new Person
            {
                Name = name,
                AssignedTo = this.Name
            };
            People.Add(person);
        }
    }

    public class Task
    {
        public string Name { get; set; }
        public Person Responsible { get; set; }

        public void AssignTo(string person)
        {
            var responsible = new Person
            {
                Name = person,
                AssignedTo = this.Name
            };
            Responsible = responsible;
        }
    }

A person is used for people involved in a project. And it is used as a responsible for a task.

So far so good. The Person class has 2 constructors to use. However, if we look a bit deeper, there is a small issue that I usually call

It does not communicate its purposes well.

How do you know what purposes, under what context the object is created for?

Static Factory Method

How about creating an object with a clear purpose? What do you think about this code?

    /// <summary>
    /// A person with Name and Assigned To
    /// </summary>
    public class Person
    {
        /// <summary>
        /// Person name
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Assigned to (such as project name, task name).
        /// </summary>
        public string AssignedTo { get; set; }

        public Person()
        {
            
        }

        public Person(string name, string assignedTo)
        {
            this.Name = name;
            this.AssignedTo = assignedTo;
        }

        public static Person CreatePersonOnProject(string person, string project)
        {
            return new Person(person, project);
        }

        public static Person CreateTaskResponsible(string person, string task)
        {
            return new Person(person, task);
        }
    }

    public class Project
    {
        public string Name { get; set; }
        public IList<Person> People { get; set; }

        public void AddPerson(string name)
        {
            People.Add(Person.CreatePersonOnProject(name, this.Name));
        }
    }

    public class Task
    {
        public string Name { get; set; }
        public Person Responsible { get; set; }

        public void AssignTo(string person)
        {
            Responsible = Person.CreateTaskResponsible(person, this.Name);
        }
    }

There are 2 explicit static factory methods:

  1. CreatePersonOnProject
  2. CreateTaskResponsible

Can you read the code again in Project.AddPerson and Task.AssignTo methods?

On the implementation side, we have not changed anything at all. We construct the same object in both cases. However, we have gained a huge benefit: Communicate the purpose explicitly.

  • Construct a new object (same as new approach)
  • Communicate exactly the purpose.
  • Consumers can use the code without confusion.

Which one should you choose? Both. As a developer, we should choose our tools wisely.

What should we do to improve our decision (decide when to use what)? One of a trick I usually use is that I ask this question

What do the other guys think? Is it clear for them to consume my code?

If the answer is “No”; no, they have to read my code to understand and use it; I will choose “Static Factory Method” approach.

 

There is no perfect code. But we can improve it over the time. When time comes, you will say thank you to yourself; other developers will say thank you to you.

You might find these posts interesting:

Give If Condition a name

Small things matter: Naming

 

Empower Your Reading with Kindle (Amazon Books)

I have been reading with my Kindle; with books bought from Amazon for 2 years. The original reasons were to improve my knowledge and English skill. However, there was a problem back then. As a reader, I highlighted and took notes while I read directly on Kindle books. The problem was that I could not find anywhere to look at them again. A bigger problem was that I had not dug deep enough into the problem.

There are always solutions to any problem. I have found out at least 2 ways to solve that problem. I hope that if anyone has the same problem. This post will save you a bit of time. If you have not started reading yet, I hope this will give you a small motivation to start.

Note: You have to have a Kindle, and buy books from Amazon.

Amazon Kindle Site

Amazon has a wonderful built-in site for your Kindle Amazon Kindle Highlights Let’s take a look at mine

Amazon Kindle Highlights
Amazon Kindle Highlights

Those are highlights and notes from the book “Grammar Girl’s Punctuation 911: Your Guide to Writing it Right (Quick & Dirty Tips)“. I just read it and I can review my notes anytime.

However, there is a small issue. It is a one-page for all highlights and notes. Which makes it very hard to look at an individual one. Of course, there is a way to find it.

You can use the search feature on the top right corner. After locating to the book you want to view, click on it. Here it is

Your Book Detail
Your Book Detail

Click on “View Your Notes & Highlights” button. Enjoy your notes and highlights

You Notes & Highlights
You Notes & Highlights

Goodreads

Many readers have been using Goodreads to manage their reading. Goodreads was acquired by Amazon. Therefore, it is another good option. Once you have an Amazon account, use it to log into Goodreads. The kindle also has Goodreads built-in. Make sure you activate Goodreads in your kindle as well. Once setup, let’s take a look at Goodreads.

Goodreads Notes & Highlights
Goodreads Notes & Highlights

In term of functionality and usage, they are identical. They offer

  • Review your notes and highlights
  • Allow you to add more notes, or add notes for your highlights, notes.
  • Encourage your reading. Empower your knowledge

 

Personally, I prefer to use Goodreads. Because it is also a reading social network site. However, the Amazon Kindle has a huge benefit with a “Popular Highlights” section for each book. That section gives you access to other readers’ mind. They read the book and thought those were important to them. You, as a reader, do the same; and enjoy the benefit they offer.

Have a good day and Enjoy your reading!