Best Practices

Best Practices For Writing Classes

Writing a class is very similar to writing a book. When writing a book, you need to look on how to organize ideas into chapters. Then you'll need to organize a chapter into multiple headings. If a heading contains too much information, it would be important to add subheadings to keep readers on track. This organization fits perfectly when coding your next project. The chapters in a book represents the classes. The chapter  represent the methods; the subheadings can be supporting methods. Finally, the body paragraphs represent the code within a method.

Photo by Aaron Burden

When Should We Create a New Class

Determining when to write a new class is essential to the design of a project. Classes should be created when it falls under the following categories:

Create Class When it's a New Concept

If the code that is to be written is a new concept and is not related to any other part of the code it's a good indicator that a class needs to be created. For example, if you are writing a user registration class and you decide that you need to use a hashing function to store the password, it would be ideal that you create a hashing utility class for this hashing function.

If functions are highly related, it may be a good indicator that a class needs to be created to group these methods. For example, if you have multiple functions that relates to create a user, you need to group these functions together in a class.

Promote Reuse

Code reuse is one of the top reasons you may want to create classes. To make your classes highly reusable, it is very important that each class is targeted and small. Keep a lookout from unrelated functions. This can cause your class to become less reusable.

Reduce Complexity

When designing a highly targeted class, it reduces the complexity of business logic. It allows for solving a problem once and not have to worry about this specific problem again. For example, let's say you create a class for calculating SHA256 for strings, data, etc. After doing that, you would not need to worry about ever solving the problem for SHA256 again.

Clarify Parameters

When a function has more than 2 related parameters, it is a huge indicator that you need to create what we call a data class. A data class is a class with a sole responsibility of holding structured data. For example, if you want to create a function to register a user, it is better for you to accept a data class called User instead of passing a lot of user parameters.

/** Good Example **/
fun registerUser(user: User) {
	// Do input validation
	// Do user registration
}

/** Bad Example **/
fun registerUser(firstName: String, lastName: String, age: Date, ...) {

}

The reason the second example above is bad is because 1. the parameters may not be quickly recognizable and 2. adding new user attributes will require modifying the function signature as well as the functions that call it.

All Hands On Deck
Photo by Perry Grone

Principles Of Class Cohesion

It is very important that classes are very targeted to what they are conveying.

When class functions are strongly related it results in:

  1. Enhancing code readability.
  2. Increases the likeliness of being reused.
  3. Avoids attracting lazy developers who just want to shove a function where it's not related.

The following are some ways to determine whether functions do not belong to the same class:

  1. If one or more methods don't interact with the rest of the class, that can be an indicator that these methods don't belong. 
  2. If there are class fields that are used by only one method, it can also indicate that this method and field may not belong to this class.

  3. Finally, if classes change often, it is a good indicator that it is time to refactor the class to two or more targeted classes.

Example of Class Cohesion

An example of a class that has low cohesion.

Vehicle

  • Edit vehicle options
  • Update pricing
  • Schedule Maintenance
  • Send Maintenance Reminder
  • Select Financing
  • Calculate Monthly Payment

The above class has unrelated functions and is advisable to split into targeted classes such as the following:

Vehicle

  • Edit vehicle options
  • Update pricing

VehicleMaintenance

  • Schedule Maintenance
  • Send Maintenance Reminder

VehicleFinance

  • Select Financing
  • Calculate Monthly Payment

How To Detect Low Cohesion

You can detect low cohesive classes by checking for non targeted class names. Usually, if you find it hard to name a class, that means the class has low cohesion. The following classes are magnet classes that attracts lazy developers to add functions of unrelated code:

  • WebsiteBO
  • Utility
  • Common
  • MyFunctions
  • PanasonicObjects
  • *Manager
  • *Processor
  • *Info

You can also detect low cohesion by checking how many methods use a classes instance variables. Instance variables used only by few methods indicates that these methods may need to be refactored to another class.

Photo by Priscilla Du Preez

Principals of Proximity

It is important to keep code related to each other close to each other. The following are things to think of:

  1. Strive to make code read top to bottom when possible
  2. Keep related actions together.

For instance,

void validateRegistration()
{
    validateData();
    if (isValidUser() == false)
    {
        throw new Exception("Invalid user");
    }
    approveSession();
}

void validateData()
{
    // validate data here
}

bool isValidUser()
{
    // return if user is valid
}

void approveSession()
{
    // approve session here
}

As you can see from the above example, as you're reading the function validateRegistration(), you encounter the function validateData() which comes directly under it. Then you encounter isValidUser() which is under that as well. Then finally you see approveSession(), which comes after. This way the reader and the code reviewer is reading the code top to bottom.

Photo by Sven Mieke

How To Outline a Class

As discussed in the introduction of this article, it's important to model a class like a chapter in the book. Create methods that are focused on one task and if that task is huge, split the function into even smaller functions. Strive for the following structure for a class:

  • Class
  • Method 1
  • Method 1a
  • Method 1ai
  • Method 1aii
  • Method 1b
  • Method 1c
  • Method 2
  • Method 2a
  • Method 2b
  • Method 3
  • Method 3a

Conclusion

Writing a class is similar to structuring a chapter in the book. The chapter (class) should go over one main topic. The heading (method) should be strictly describing one topic, and finally sub-headings (sub-methods) can be used to split a large topic into smaller parts. If you have any inputs or questions about the content of the article please leave me a review and I'll be happy to reply.

Author image

About Rawad Hilal

Lead programmer with a track record of incorporating user and business requirements into cost-effective, secure and user-friendly solutions known for scalability and durability.
  • Orange County, California, USA