Clean Code and Code Smells

What I Want to Do More

In the chapter Bad Code Smells from the book Refactoring: Improving the Design of Existing Code, Martin Fowler recommends that if you feel the need to comment a block of code, you should just write a new method instead. Following this heuristic helps to make code cleaner as long methods often do too much, and cause us to duplicate messy code. My creating shorter methods, they become more readable and more reusable. As Bjorne Stroustrup suggests, “you want to make it hard for bugs to hide”. Shorter methods also help to improve readability as each method does what it’s name suggests, and can even improve developer efficiency. If the name is good enough, the developer won’t have to spend time looking at the method definition. 

Example of Long Methods

In this example function definition generateTestEmailLargeAsync below, the function generates a new email to test the email messaging service. 

Three obvious partitions in the code split the logic between creating the message, sending the message, and processing the response. In order to make these splits clear, we have to comment our code accordingly.

async function generateTestEmailLargeAsync() {
  // create the message
  const message = "This is a message to Email";
  const recipients = "test@oregonstate.edu";
  const email = new Email(message, recipients);


  // send the message
  const emailClient = new EmailClient();
  const response = await emailClient.SendEmailAsync(email);


  // process the response
  if (response.Code == 200) {
    return "Success!"
  }
  else {
    return "There was an issue sending the email."
  }
}

If we follow the heuristic mentioned in the previous section, then we would want to split this code into smaller methods. Each section will have it’s own method, with it’s own responsibilities which will help to clarify what each section of code does without having to comment it.

Example of Short Methods

This method generateTestEmailLittleAsync instead uses smaller methods to perform the same function as the previous long method. However, the function is made clearer by putting the other logic into their own smaller, discrete methods.

async function generateTestEmailLittleAsync() {
  const email = createEmail();
  const response = await sendEmailAsync(email);
  return processReponse(response);
}


function createEmail() {
  const message = "This is a message to Email";
  const recipients = "test@oregonstate.edu";
  const email = new Email(message, recipients);
  return email;
}


async function sendEmailAsync(email: Email) {
  const emailClient = new EmailClient();
  const response = await emailClient.SendEmailAsync(email);
  return response;
}


function processReponse(response: EmailResponse) {
  if (response.Code == 200) {
    return "Success!"
  }
  else {
    return "There was an issue sending the email."
  }
}

What I Want to Avoid

In line with the last section, one thing I want to avoid in future development work is creating duplicate code. Creating smaller methods helps to reduce the chances of having duplicate code because these components become easily reusable. For example, when dealing with large code bases with many methods and classes, as new development work is done, classes and methods need to be continuously refactored to keep the code clean. This process has to be done as soon as possible as it can get away from a developer very quickly if they assume they will make time for it later. As I learned in Chapter 1: Clean Code in the book Clean Code by Robert Martin, when it comes to development work “Later equals Never”. So, this is where the method of extracting and unifying becomes helpful.

Example of Duplicated Code

In the example below, there is a section of duplicated code that is shared between the methods generateReport and processRequest. Most of the time, I feel that duplicated code is not as obvious as this, and can actually be spread far across a code base. Meaning, it won’t show up in the same file of code.

async function generateReport(data: ReportData, recipients: string) {
  const reportFile = "test.xlsx";
  const processedReport = GenerateReport(data);
  const reportBytes = processedReport.ToBytes();

  // Duplicate code below
  const email = createEmail(reportBytes);
  const response = await sendEmailAsync(email, recipients);
  return processReponse(response);
}

async function processRequest(message: string, recipients: string) {
  messageBytes = message.toBytes();

  // Duplicate code below
  const email = createEmail();
  const response = await sendEmailAsync(email, recipients);
  return processReponse(response);
}

Example of Extracted Code

To reduce code duplication, you can perform an extraction of the shared code and create a shared function.

async function generateReport(data: ReportData, recipients: string) {
  const reportFile = "test.xlsx";
  const processedReport = GenerateReport(data);
  const reportBytes = processedReport.ToBytes();

  return generateEmailAsync(messageBytes);
}

async function processRequest(message: string, recipients: string) {
  messageBytes = message.toBytes();

  return generateEmailAsync(messageBytes);
}

async function generateEmailAsync(message: bytes[], recipients: string) {
  const email = createEmail();
  const response = await sendEmailAsync(email, recipients);
  return processReponse(response);
}

Now, both functions can use the same code to generate an email.

Print Friendly, PDF & Email

Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *