• About Blog

    What's Blog?

    A blog is a discussion or informational website published on the World Wide Web consisting of discrete, often informal diary-style text entries or posts.

  • About Cauvery Calling

    Cauvery Calling. Action Now!

    Cauvery Calling is a first of its kind campaign, setting the standard for how India’s rivers – the country’s lifelines – can be revitalized.

  • About Quinbay Publications

    Quinbay Publication

    We follow our passion for digital innovation. Our high performing team comprising of talented and committed engineers are building the future of business tech.

Showing posts with label Design Patterns. Show all posts
Showing posts with label Design Patterns. Show all posts

Monday, July 25, 2022

Understand Code Refactoring Techniques to Improve your Code Quality

Code Refactoring Techniques
Photo by Danial Igdery

Now a days, agile teams are under tremendous pressure to write code faster with enhanced functionality in short time. There would be some or the other functionality added at the last moment or just before the release. As engineers are under pressure, the functionality gets implemented in a sloppy manner, which may technically work but may lead to dirty code.

Dirty code usually results from a developer’s inexperience, shortcuts taken to meet increasingly tight deadlines, poor management of the project, several different developers working on a project over time, or some combination of all of the above.

Bad code comes at a price, and writing good code isn’t that complicated. Let's understand what's code refactoring.

Code Refactoring

In computer programming and software design, code refactoring is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. Refactoring is intended to improve the design, structure, and/or implementation of the software (its non-functional attributes), while preserving its functionality. 

Potential advantages of refactoring may include improved code readability and reduced complexity; these can improve the source code's maintainability and create a simpler, cleaner, or more expressive internal architecture or object model to improve extensibility. 

Another potential goal for refactoring is improved performance; software engineers face an ongoing challenge to write programs that perform faster or use less memory.

Code refactoring helps to change this dirty code into clean code and it helps to make it easier to extend the code and add new features easily in the future. Also, helps to improve the more objective attributes of code such as code length, code duplication, and coupling and cohesion, all of which correlate with ease of code maintenance and your code will use less memory and perform better and faster.

How to Perform Code Refactoring?

Now that you know the answer to the question of what is code refactoring, and you know many of its potential benefits, how exactly do you refactor code?

There are many approaches and techniques to refactor the code. Let’s discuss some popular ones.

Red-Green Refactor

Red-Green is the most popular and widely used code refactoring technique in the Agile software development process. This technique follows the test-first approach to design and implementation, this lays the foundation for all forms of refactoring.

Red - The first step starts with writing the failing red-test. You stop and check what needs to be developed.

Green - In the second step, you write the simplest enough code and get the development pass green testing.

Refactor - Find ways to improve the code and implement those improvements, without adding new functionality.

Refactoring by Abstraction

This technique is mostly used by developers when there is a need to do a large amount of refactoring. Mainly we use this technique to reduce the redundancy (duplication) in our code. This involves class inheritances, hierarchy, creating new classes and interfaces, extraction, replacing inheritance with the delegation, and vice versa.

Pull-Up Method - It pulls code parts into a superclass and helps in the elimination of code duplication.

Push-Down Method - It takes the code part from a superclass and moves it down into the subclasses.

Refactoring by abstraction allows you to make big changes to large chunks of code gradually. In this way, you can still release the system regularly, even with the change still in progress.

Composing Method

Code that is too long is difficult to understand and difficult to implement. The composing method is a code refactoring approach that helps to streamline code and remove any code duplications. This is done through extraction and inline techniques.

Extraction - We break the code into smaller chunks to find and extract fragmentation. After that, we create separate methods for these chunks, and then it is replaced with a call to this new method. Extraction involves class, interface, and local variables.

Inline - Refactoring also helps to create simpler, more streamlined code. It helps to remove unnecessary methods within the code and replaces them with the content of the method. After that, we delete the method from our program.

Simplifying Methods

As legacy code gets older and older, it tends to become more polluted and complex. In this sense, simplifying methods help to simplify the logic. These methods include adjusting the interaction between different classes, along with adding a new parameter or removing and replacing certain parameters with explicit methods.

Simplifying Conditional Expressions - Conditional statement in programming becomes more logical and complicated over time. You need to simplify the logic in your code to understand the whole program. There are so many ways to refactor the code and simplify the logic. Some of them are: consolidate conditional expression and duplicate conditional fragments, decompose conditional, replace conditional with polymorphism, remove control flag, replace nested conditional with guard clauses, etc.

Simplifying Method Calls - In this approach, we make method calls simpler and easier to understand. We work on the interaction between classes, and we simplify the interfaces for them. Examples are: adding, removing, and introducing new parameters, replacing the parameter with the explicit method and method call, parameterize method, making a separate query from modifier, preserve the whole object, remove setting method, etc.

Extract Method

The extract method is one of the techniques for code refactoring that helps to decrease complexity, while also increasing the overall readability of the code.

When you find that a class has so many responsibilities and too much thing is going on or when you find that a class is unnecessary and doing nothing in an application, you can move the code from this class to another class and remove it completely from the existing class. It involves the moving of a fragment or block of code from its existing method and into a newly created method, which is clearly named in order to explain its function.

Conclusion

Engineers are the only ones responsible for writing good and quality code. We should all make it a habit to write good code from the very beginning. Writing clean code isn’t complicated and doing so will help both you and your colleagues. A clean and well-organized code is always easy to change, easy to understand, and easy to maintain.

Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin

Even bad code can function. Every year, countless hours and significant resources are lost because of poorly written code but it doesn't have to be that way.

Refactoring: Improving the Design of Existing Code by Martin Fowler

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.


Quick Tips

  • Always perform code refactoring in small chunks by making your code slightly better and leaves the application in a working state. Run jUnit tests after making small changes in the refactoring process. Without running these tests, you create a risk of introducing new bugs.

  • Do not create any new features or functionality during the refactoring process. You should refactor the code before adding any updates or new features into your existing code.

  • Refactoring process always results in complete regression, don't forget to involve your QA team in the process.

Wednesday, August 4, 2021

Retry or Stability Pattern

Retry or Stability Pattern Image
Photo by Brett Jordan

One of the key characteristic of microservices architecture is inter-service communication. We can split a monolithic application into multiple smaller applications called microservices. Each microservice is responsible for a single feature or domain and can be deployed, scaled, and maintained independently.

Since microservices are distributed in nature, various things can go wrong at any point of time. The network over which we access other services or services themselves can fail. There can be intermittent network connectivity errors or firewall issues. Individual services can fail due to service unavailability, coding issue, out of memory errors, deployment failure, hardware failure and etc., to make our services resilient to these failures, we adopt the retry pattern which is also known as stability pattern.

Retry Pattern

The idea behind the retry pattern is quite simple. If service A makes a call to service B and receives an unexpected response for a request, then service A will send the same request to service B again hoping to get an expected response.

Retry Pattern Image
Retry Pattern Representation

There are several retry strategies that can be applied depending on the failure type or nature of the requirements.

Immediate Retry

This strategy is the basic one. In this approach, calling service handles the unexpected failure and immediately makes the request again. This strategy can be useful for unusual failures that occur intermittently. The chances of success are high by just retrying in these cases.

Retry After Delay

In this strategy, we introduce a delay before retrying service call again, hoping that the cause of the fault would have been rectified. Retry after delay is an appropriate strategy when a request timeout occurs due to busy or failures or network-related issue.

Sliding Retry

In this strategy, the service will continue to retry the service call by adding an incremental time delays on each subsequent attempts. For example, the first retry may wait 500 MS, the second will wait 1000 MS, the third will wait 1500 MS until the retry count has not been exceeded. By adding an increasing delay, we reduce the number of retries to the service and avoid adding any additional load to a service which is already overloaded.

Retry with Exponential Backoff

In this strategy, we take the Sliding Retry strategy and ramp up the retry delay exponentially. If we started with a 500 MS delay, we would retry again after 1500 MS, then 3000 MS. Here we are trying to give the service more time to recover before we try to invoke it again.

Abort Retry

As we understand, we can't have a retry process happening forever. We need to have a threshold on the maximum number of retry attempts, we try for a failed service call. We need to maintain the counter and when it reaches the threshold value, our best strategy is to abort the retry process and let the error propagate to the calling service.

Conclusion

The retry pattern allows the calling service to retry failed attempts with a hope that the service will respond within an acceptable time.

With the varying interval between retries we provide the dependent service more time to recover and respond for our request.

It is recommend that, we need to keep a track of failed operations as it will be very useful information to find recurring errors and also the required infrastructure like thread pool, thread strategy etc.

At some point, we just need to abort the retry and we must acknowledge that the service is not responding and notify the calling service with an error.

References

Thursday, June 24, 2021

Template Method Pattern - Skeleton is Defined in Base Class

Template Method Design Pattern
Photo Courtesy Unsplash

What is the Template Method Design Pattern?

The Template Method Design Pattern defines a sequence of steps of an algorithm and allows the subclasses to override the steps but do not allow to change the sequence. The Key to the Template Design Pattern is that we put the general logic in the abstract parent class and let the child classes define the specifics.

Template Method pattern falls under the behavioural design pattern, is one of the easiest to understand and implement. This design pattern is used popularly in framework development and also helps to avoid code duplication.

An abstract class contains the templateMethod which should be made final so that it cannot be overridden. This template method makes use of other operations available in order to run the algorithm but is decoupled for the actual implementation of these methods. Concrete class implements all the methods required by the templateMethod that were defined as abstract in the parent class.

Pattern Implementation

As am a coffee person, I will take an example of preparing the coffee using a template method pattern which should allow to understand the pattern easily instead of taking some framework implementations such as AbstractController, RequestProcessor, HttpServlet, InputStream, OutputStream etc.

public abstract class CoffeeMaker {
   protected boolean sugarFree = false;

   public void prepareCoffee() {
      boilWater();
      addMilk();
      if (!isSugarFree()) {
         addSugar();
      } else {
 System.out.println("- No Sugar")
      }
      addCoffeePowder();
      System.out.println("- Coffee is Ready!!!");
   }

   public final void boilWater() {
      System.out.println("- Boiling Water");
   }

   public boolean isSugarFree() {
      return sugarFree;
   }

   public void setSugarFree(boolean sugarFree) {
      this.sugarFree = sugarFree;
   }

   abstract void addMilk();
   abstract void addSugar();
   abstract void addCoffeePowder();
}

Now we will create 2 concrete classes which will provide different implementations.

public class CothasCoffeeMaker extends CoffeeMaker {
   @Override
   public void addMilk() {
      System.out.println("- Adding Milk");
   }

   @Override
   public void addSugar() {
      System.out.println("- Adding Sugar");
   }

   @Override
   public void addCoffeePowder() {
      System.out.println("- Adding Cothas Coffee Powder");
   }
}

public class BruCoffeeMaker extends CoffeeMaker {
   @Override
   public void addMilk() {
      System.out.println("- Adding Milk");
   }

   @Override
   public void addSugar() {
      System.out.println("- Adding Sugar");
   }

   @Override
   public void addCoffeePowder() {
      System.out.println("- Adding Bru Coffee Powder");
   }
}

Now it's time to write the main method to execute the above code and see the output of the two variations of the coffee.

public class CoffeeMakerExample {
   public static void main(String[] args) {
      System.out.println("Cothas Coffee Preparation")
      CoffeeMaker coffeeMaker = new CothasCoffeeMaker();
      coffeeMaker.prepareCoffee();

      System.out.println("Bru Coffee Preparation");
      coffeeMaker = new BruCoffeeMaker();
      coffeeMaker.setSugarFree(true);
      coffeeMaker.prepareCoffee();
   }

}

The CoffeeMaker class is an abstract class containing the algorithm skeleton. The prepareCoffee() is the method that contains the process steps. The boilWater() method is common step for the process of any coffee preparation and no customization is required, hence it has been made as final so the subclasses will not override and provide a different implementation. 

We have two subclasses CothasCoffeeMaker and BruCoffeeMaker which follows the same preparation process but implementation are given at each individual subclass.

If you execute the above program, you should see the following output.

Cothas Coffee Preparation
- Boiling Water
- Adding Milk
- Adding Sugar
- Adding Cothas Coffee Powder
- Coffee is Ready!!!

Bru Coffee Preparation
- Boiling Water
- Adding Milk
- No Sugar
- Adding Bru Coffee Powder
- Coffee is Ready!!!

Conclusion

  • The pattern promotes the code reusability and decoupling, but at the expense of using inheritance.
  • The pattern adhers to the Single Responsibility and Open/Closed principles of S.O.L.I.D - Design Principles.

Reference

Tuesday, May 25, 2021

Singleton Design Pattern - Build It, Break It and Fix It!

Singleton Design Pattern
Photo Courtesy Unsplash


Singleton pattern is one of the simplest design patterns and falls under creational pattern as this pattern provides one of the best ways to create an object. This pattern involves a single class which is responsible for creating an object while making sure that the instantiation of a class to only one object. This class provides a way to access its only object which can be accessed directly without instantiating the object of the class.

Let’s see various design options for implementing the pattern. If you have a good hold on static class variables and access modifiers this is not a difficult task.

Lazy Instantiation

public class Singleton implements Serializable {

  private static Singleton singletonObject;

  //Adding a private constructor so that no one creates object
  private Singleton() {
  }

  public static Singleton getInstance() {
    if (singletonObject == null) {
      singletonObject = new Singleton();
    }
    return singletonObject;
  }

}

Here we have declared getInstance() as static so that we can call it without instantiating the class. First time, when getInstance() method is called, it creates a new Singleton object and later it just returns the same object reference. Note that singletonObject is not created until we call the getInstance() method, as we are using the lazy instantiation of the object.

The main problem with the above method is that it is not thread safe. If we have two threads T1 and T2 which invokes the getInstance() method at the same time, the execution sequence creates two objects for Singleton.

The other option is to make getInstance() method as synchronized. Here, using synchronized keyword makes sure that only one thread is allowed at a time to execute getInstance() method. The main disadvantage of this is method is, that using synchronized every time while creating the Singleton object is expensive and may decrease the performance of your program. However if performance of getInstance() is not critical for the application this method provides a clean and simple solution.

Eager Instantiation

public class Singleton implements Serializable {

  private static Singleton singletonObject = new Singleton();

  //Adding a private constructor so that no one creates object
  private Singleton() {
  }

  public static Singleton getInstance() {
    return singletonObject;
  }
  
}


Here we have created instance of Singleton with the help of static initializer. JVM executes static initializer when the class is loaded and hence this is guaranteed to be thread safe. Use this method only when the Singleton class is light and is used throughout the execution of the program.

Double Check and Locking Instantiation

public class Singleton implements Serializable {

  private static volatile Singleton singletonObject;

  //Adding a private constructor so that no one creates object
  private Singleton() {
  }

  public static Singleton getInstance() {
    if (singletonObject == null) {
      // Making thread safe
      synchronized(Singleton.class) {
        // Check again as object is still null
        if (singletonObject == null) {
          singletonObject = new Singleton();
        }
      }
    }
    return singletonObject;
  }
    
}

In the above implementation, we have declared the singletonObject as volatile. Using volatile is yet another way (like synchronized, atomic wrapper) of making class thread safe. Thread safe means that a method or class instance can be used by multiple threads at the same time without any problem. This method drastically reduces the overhead of calling the synchronized method every time.

Now that we know how to implement a Singleton pattern in 3 different ways. Let’s see whether we can break the Singleton pattern ?

Reflection

Reflection is a feature in the Java programming language. It allows an executing Java program to examine or introspect upon itself, and manipulate internal properties of the program. For example, it’s possible for a Java class to obtain the names of all its members and display them.

We will use Reflection and see whether we can break the Singleton or not ?

class Singleton implements Serializable {

  private static Singleton singletonObject = new Singleton();

  //Adding a private constructor so that no one creates object
  private Singleton() {
  }

  public static Singleton getInstance() {
    return singletonObject;
  }
  
}

public class SingletonExample {
  
  public static void main(String[] args) {
    try {
        Singleton obj1 = Singleton.getInstance();
        System.out.println("Singleton.getInstance().hashCode: " + obj1.hashCode());

        Constructor constructor = Singleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton obj2 = (Singleton) constructor.newInstance();
        System.out.println("Reflection.newInstance().hashCode: " + obj2.hashCode());
    }
    catch (Exception e) {
        e.printStackTrace();
    }
  }
  
}

If you execute the above program, you should see in the output that the hashCode of both objects are different and it clearly violates Singleton pattern.

Singleton.getInstance().hashCode: 1418481495
Reflection.newInstance().hashCode: 303563356

Let’s fix this loop hole by making some simple code change in the Singleton constructor.

private Singleton() {
    if (singletonObject != null) {
        throw new IllegalStateException("Already Initialised!");
    }
}

Now if you execute the program with the above changes, the line 24 will call the constructor and it will throw an IllegalStateException. Thus prevents the creation of the second instance.

Caused by: java.lang.IllegalStateException: Already initialised!

What if I change the access level of the singleton field from private to public using the Reflection? Oops… it will allow me to set the singleton object to null and it will create a new object. Let’s modify our main method to hack the Singleton class.

public static void main(String[] args) {
    try {
        Singleton obj1 = Singleton.getInstance();
        System.out.println("Singleton.getInstance().hashCode: " + obj1.hashCode());

        Field field = Singleton.class.getDeclaredField("singletonObject");
        field.setAccessible(true);
        field.set(field, null);
        
        Constructor constructor = Singleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton obj2 = (Singleton) constructor.newInstance();
        System.out.println("Reflection.newInstance().hashCode: " + obj2.hashCode());
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

Using Reflection, we are changing the value of the instance field to NULL after the object gets created. When we invoke the constructor, the condition fails as singleton instance is null hence it will allow you to create another instance.

We can prevent it by declaring the singletonObject instance as FINAL so that it’s value can’t be changed once assigned.

private final static Singleton singletonObject = new Singleton();

Now if you execute the program, it will throw an IllegalAccessException. Reflection can’t convert final field to non-final field. Please note, this approach only works with Eager Instantiation method.

Serialization

Java provides a mechanism, called object serialization where an object can be represented as a sequence of bytes that includes the object’s data as well as information about the object’s type and the types of data stored in the object.

After a serialized object has been written into a file, it can be read from the file and deserialized, i.e., the type information and bytes that represent the object and its data can be used to recreate the object in memory.

Most impressive is that the entire process is JVM independent, meaning an object can be serialized on one platform and deserialized on an entirely different platform.

We will use Serialization and see whether we can break the Singleton or not ?

class Singleton implements Serializable {

  private final static Singleton singletonObject = new Singleton();

  //Adding a private constructor so that no one creates object
  private Singleton() {
    if (singletonObject != null) {
      throw new IllegalStateException("Already Initialised!");
    }
  }

  public static Singleton getInstance() {
    return singletonObject;
  }
  
}

public class SingletonExample {
  
  public static void main(String[] args) {
    try {
        Singleton obj1 = Singleton.getInstance();
        System.out.println("Singleton.getInstance().hashCode: " + obj1.hashCode());
      
        // Serialize the object to file
        ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream("file.txt"));
        objectOutput.writeObject(obj);
        objectOutput.close();

        // DeSerailize the object from file
        ObjectInput objectInput = new ObjectInputStream(new FileInputStream("file.txt"));
        Singleton obj2 = (Singleton) objectInput.readObject();
        in.close();

        System.out.println("Serialization.getInstance().hashCode: " + obj2.hashCode());
    }
    catch (Exception e) {
        e.printStackTrace();
    }
  }
  
}

If you execute the above program, you should see in the output that the hashCode of both objects are different and it clearly violates Singleton pattern.

Singleton.getInstance().hashCode: 1418481495
Serialization.getInstance().hashCode: 565760380

Let’s fix this loop hole by making some simple code change in the Singleton class. We have to implement readResolve() method and return the singletonObject reference.

protected Object readResolve() {
    return singletonObject;
}

Conclusion

  • We saw how to implement the Singleton Pattern in different ways like Lazy Instantiation, Eager Instantiation and Double Check and Locking Instantiation.
  • We saw how we can break the Singleton Pattern using the Reflection and Serialization methods.
  • Also, we saw how it can be prevented by making few code changes so the Singleton Pattern won’t allow you to create more than one instance.

References:




Monday, February 22, 2021

S.O.L.I.D — Design Principles

 

S.O.L.I.D — Design Principles Image

Software Design Principles

In today’s world, customer requirements keep changing at an unprecedented pace. It becomes essential for the technical teams to accommodate the new requirements and deliver those very quickly. To develop and deliver faster, it’s necessary to reduce software development and testing time.

At the same time, new technologies are introduced every few months. It’s common to experiment with more optimal and efficient technologies by replacing the existing ones. Thus, it’s important to write the code that is flexible and loosely coupled to introduce any changes.

Well written code is easy to grasp as new developer doesn’t have to spend more time reading the code. A well maintained software thus enhances developer’s and the team’s productivity. In addition, high test coverage increases the confidence to deploy a new change to the production.


Where do SOLID principles come from?

SOLID principles came from an essay written in 2000 by Robert Martin, known as Uncle Bob, where he discussed that a successful application will change and, without good design, can become rigid, fragile, immobile and viscous.

  • Rigid — Things are very fixed. You can’t move or change things without affecting other things, but it’s clear what will break if you make a change.
  • Fragile — Easy to move and change things but not obvious what else might break as a result.
  • Immobile — Code works fine but you can’t re-use code without duplicating or replicating it.
  • Viscous — Everything falls apart when you make a change, you quickly push it back together and get your change working. The same thing happens when somebody else comes along to make a change.

The principles that Robert Martin talks about to avoid the four design anti-patterns above have evolved to be known as the SOLID principles. Although he didn’t invent the principles, he pulled together some good coding practices that already existed around a central theme of managing dependencies and put forward a good argument for using those practices together.

In object-oriented world, S.O.L.I.D is a mnemonic acronym for five design principles intended to make software designs more understandable, flexible, and maintainable. Let’s go through all five principles.

Single Responsibility Principle

One of the simplest principles to understand. It states that, a class should only have one responsibility. Furthermore, it should only have one reason to change.

Open/Closed Principle

Simply put, classes should be open for extension, but closed for modification. In doing so, we stop ourselves from modifying existing code and causing potential new bugs.

Liskov Substitution Principle

The principle states that, objects of the same superclass should be able to substitute each other without breaking an existing code.

Interface Segregation Principle

According to this principle, the larger interfaces should be split into smaller ones. By doing so, we can ensure that implementing classes only need to be concerned about the methods that are of interest to them.

Dependency Inversion Principle

The principle of Dependency Inversion refers to the decoupling of software modules. This way, instead of high-level modules depending on low-level modules, both will depend on abstractions.

Conclusion

The above five principles form a foundation for the best practices followed in Software Engineering. Practicing the above principles in day to day work helps improve the readability, modularity, extensibility and testability of the software.

One thing you can guarantee with any application, if it’s successful and used extensively, it will change over the time. As it changes, the complexity factor gradually increases until you hit a tipping point where it becomes more difficult and takes longer time to ship new features on top of the poorly written code that was quickly shipped once.

I’ll leave you with following questions which I’ve found useful to ask myself while writing code:
  • Is the class DRY(Don’t Repeat Yourself)?
  • Does everything in a class change at the same rate?
  • Have I abstracted out something that is likely to change?
  • Have I abstracted out something that is not used in all classes that inherit it?

Featured Post

Your AI Sidekick: How Claude took over Pritee’s Repetitive tasks

  It was a classic Wednesday morning in our Bengaluru office . Pritee, one of our sharpest Project Managers, had just stepped out of a stake...