We have already seen SOLID Principles. We will see some more additional principles and best practices, and most of them may be again indirectly based on the SOLID Principles. Please also see the note ‘What to avoid in your design’.

    The additional principles and practices include, but are not limited to:

    1. Program to interfaces
      • Program to an interface, not an implementation, as it will prevent any dependency on any specific implementation.
      • The interface here mean and abstraction and can be either an interface or an abstract class.
    2. Don’t repeat yourself (DRY)
      • ​​Avoid duplicating code. Move it into a separate function or class.
    3. Low coupling, High Cohesion
      • Coupling is the degree to which one class knows about another class. If the knowledge is less, it is called loosely coupled. If knowledge is more, it is called tightly coupled.
        • Loose coupling is preferred as it allow us to build flexible OO systems that can handle change.
        • For instance, if the knowledge of one class about other class is only through exposed interfaces (data hiding), the system is loosely coupled and easier to change than a system where classes access data members directly.
      • Cohesion refers to the degree to which the elements inside a module or class belong together. It is a measure of the strength of relationship between the class’s methods and data themselves.
        • High cohesion is preferred. High cohesion means that the class is focused and attributes of a class are all related to a single responsibility. 
      • High cohesion often correlates with loose coupling, and vice versa.
    4. Encapsulate what varies (EWV)
      • Identify the aspects of your application that vary, encapsulate them and separate them from what stays the same.
      • Head first design patterns book gives Duck example to demonstrate this. Consider the parent Duck has a method fly(), but then there are many type of Ducks that doesn’t fly. One quick ineffective solution is to override this method in every subclass of Duck that does not fly, to do nothing. This will turn out to be nightmare when more and more Ducks are added. Instead, you can separate this fly behavior into a separate class backed by an interface and then every class that need this behavior can use this class.
    5. Prefer composition over inheritance
      • Classes may achieve polymorphic behavior and code reuse by containing other classes that implement the desired functionality instead of through inheritance.
      • You may have an abstract reference type (Program to Interfaces) and allow clients to change behavior at runtime by passing in any implementation. 
      • Using composition over inheritance also reduces code duplication.
      • Example 1: Stack class in Java is an example. It extends a List and exposes additional list methods which are not meant to be there for a stack. A better approach would have been to contain the list as a member and use it for storing the stack elements.
      • Example 2: In our previous Duck example (EWV), we can achieve this by having an interface reference for the fly behavior within Duck and based on the required fly behavior we can pass (or even inject) the correct implementation. Instead, if we had extended the Duck class with a fly behavior implementation, further extensions would have been difficult (against OCP). Also, if we had implemented an interface for fly behavior to allow further extensions, then every class would have had to overwrite it leading to code duplication (against DRY principle). 
    6. Keep it simple, stupid (KISS)
      • Simplicity should be a key goal in design and unnecessary complexity should be avoided. Many design patterns try to decompose the system into smaller sub systems to achieve this.
    7. Unit Testable
      • Every class should be testable independently without it invoking any other class.
      • If class A create and invoke another class B directly, then while unit testing class A, we will be also testing class B and hence technically it cannot be called unit test, but an integration test. If a class needs to create and invoke another class, we can use dependency injection to inject a constructed object (DIP) so that for unit testing you can pass in a dummy mock object.

    Recent Articles


    Why is refresh token needed when you have access token? Access tokens are usually short-lived and refresh tokens are...


    Sumo Logic Basics - Part 1 of 2 (link is external) (Sep 29, 2016)Sumo Logic Basics - Part 2 of 2...


    Discard all local changes, but save them for possible re-use later:  git stash Discarding local changes...


    Module 1 - INTRODUCTION Recorded Lecture - 1.1 Introduction Part I – Definition


    Whenever you add reviews for the book, please follow below rules. Write issues in an excel.Create an excel...

    Related Stories

    Leave A Reply

    Please enter your comment!
    Please enter your name here

    Stay on op - Ge the daily news in your inbox