Skip to content

Instantly share code, notes, and snippets.

@fourgates
Last active September 11, 2020 20:23
Show Gist options
  • Select an option

  • Save fourgates/db5168902b83284e48aa047467d9a54a to your computer and use it in GitHub Desktop.

Select an option

Save fourgates/db5168902b83284e48aa047467d9a54a to your computer and use it in GitHub Desktop.

Revisions

  1. fourgates revised this gist Sep 10, 2020. 1 changed file with 150 additions and 10 deletions.
    160 changes: 150 additions & 10 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ SOLID is an acronym for several of the most useful [OOP](https://en.wikipedia.o
    - **I**nterface Segregation
    - **D**ependency Inversion

    In this post, I will cover the first principle, Single Responsibility. I hope these posts will give you an understanding of how these principles can improve the way you write code and maybe impress the next person that reviews your code!
    In this post, I will cover the first principle, the Single Responsibility Principle (SRP). I hope these posts will give you an understanding of how these principles can improve the way you write code and maybe impress the next person that reviews your code!

    ## Single Responsibility Principle

    @@ -18,37 +18,177 @@ In this post, I will cover the first principle, Single Responsibility. I hope th

    A class should encapsulate responsibility. A simple way to implement this is to group together code that is going to change for the same reason. This allows us to write modular code that is easily testable and maintainable.

    Another reason for learning this principle is to learn how and when to refactor code. Take a look at your source control and find the top five most touched files. There is a good chance these classes are breaking the Single Responsibility Principle (SRP). If these areas are constantly changing or, worse yet, frequently creating bugs this may be a great place to apply this principle.
    Another reason for learning this principle is to learn how and when to refactor code. Take a look at your source control and find the top five most touched files. There is a good chance these classes are breaking the Single Responsibility Principle. If these areas are constantly changing or, worse yet, frequently creating bugs this may be a great place to apply this principle.

    ```
    git log --pretty=format: --name-only | sort | uniq -c | sort -rg | head -10
    ```

    ## Single
    What does "single" mean? Stop right there. This does not mean you should be writing one method classes! This simply means all the code in a module should generally have the same theme or reason to change. Let's review an example.
    What does "single" mean? Stop right there. This does not mean you should write one method classes! This simply means all the code in a module should generally have the same theme or reason to change. Let's review a simple example:

    `// TODO i don't think I like this example`
    ```
    public class Car{
    private Engine engine;
    public void start(){
    this.engine.start();
    }
    }
    ```

    Accounting software may have many different calculations based on inputs from different forms. At a high level, it may make sense to keep all of these calculations encapsulated into one class, but this can become quite cumbersome. It may make more sense to break down each calculation into a class for a given form; you can have one class responsible for calculating a W-2, while another handles a W-4 form. This way the only reason a class would have to change is if it's corresponding form changes. Separating these actions into their own class can reduce complexity, increase ease of use, and result in a SOLID design.
    This is an excellent demonstration of the SRP. We can start the `Car` without having to know anything about the `Engine`. Starting the `Engine` is abstracted to its own class. We should be able to make changes to the `Engine` class without changing how the `Car` starts.

    ## Code Smell - Overly Coupled Classes
    ```
    // Good
    public Class A{
    @Autowired
    public A(B bService){
    }
    }
    // Potentially Bad
    public Class A{
    @Autowired
    public A(B serviceB, C serviceC, ... Z serviceZ){
    }
    }
    ```
    If a class has an abundance of dependencies it can't possibly have a single responsibility! A common symptom of "single" is having common dependencies. If you have class B and class A requires class B to do work these classes are considered **coupled**. Now say class A needs classes B-Z to do all its work, this could be a potential **problem**. This is often a red flag, so keep an eye out!


    ## Code Smell - God Classes
    >
    A "God Class" is an object that controls too many other objects in a system and has grown beyond all logic to become, The Class That Does Everything.

    A common symptom of "single" is having common dependencies (`@Autowired or Parameterized). If you have class B and class A requires class B to do work these classes are considered **coupled**. Now say class A needs classes B-Z to do all its work, this is now considered a **problem**. If a class has an abundance of dependencies it can't possibly be doing a single action! This is often a red flag, so keep an eye out!

    If a class is several thousand lines long this is often a terrible code smell. This often indicates that the class is overly complex. However, keep in mind this can sometimes be justified. It is recommended to split these classes apart to become more object-oriented. Breaking apart these classes will not only reduce complexity but make your code more maintainable and testable. This is an implicit side effect of using SRP!

    >
    Pro Tip: When refactoring a God Class start with abstracting dependencies to a new class and take the dependent code with it!

    ## Bad Example
    ## Bad Example - God Class
    ```
    /**
    * this is a short example of what a "God" class CAN look like.
    * this is not always the case but in enterprise applications, the business logic
    * for different operations can grow out of hand. This can lead to coupled code
    * that becomes a commonplace for broken tests and bugs
    */
    public class TeamGodClass{
    // create team
    public ResponseObj createTeam(){...}
    public ResponseObj validateForCreate(){...}
    public ResponseObj createBusinessLogic1(){...}
    public ResponseObj createBusinessLogic2(){...}
    public ResponseObj createBusinessLogic3(){...}
    public ResponseObj createBusinessLogic4(){...}
    // update team
    public ResponseObj updateTeam(){...}
    public ResponseObj validateForUpdate(){...}
    public ResponseObj updateBusinessLogic1(){...}
    public ResponseObj updateBusinessLogic2(){...}
    public ResponseObj updateBusinessLogic3(){...}
    public ResponseObj updateBusinessLogic4(){...}
    // mix / match
    // isNewObj -- this is a code smell!
    public ResponseObj createOrUpdateBusinessLogic(Boolean isNewObj){...}
    }
    ```

    ## Good Example
    ## Good Example - No God Class
    ```
    /**
    * base class
    * this could also be a static helper class
    */
    public class GoodTeamClass{
    // common logic needed in update and create
    protected ResponseObj commonBusinessLogic(){...}
    }
    /**
    * Class responsible for creating teams.
    */
    public class GoodCreateTeamClass extends GoodTeamClass{
    // create team
    public ResponseObj createTeam(){...}
    public ResponseObj validateForCreate(){...}
    public ResponseObj createBusinessLogic1(){...}
    public ResponseObj createBusinessLogic2(){...}
    public ResponseObj createBusinessLogic3(){...}
    public ResponseObj createBusinessLogic4(){...}
    }
    /**
    * Class responsible for updating teams
    */
    public class GoodUpdateTeamClass extends GoodTeamClass{
    // update team
    public ResponseObj updateTeam(){...}
    public ResponseObj validateForUpdate(){...}
    public ResponseObj updateBusinessLogic1(){...}
    public ResponseObj updateBusinessLogic2(){...}
    public ResponseObj updateBusinessLogic3(){...}
    public ResponseObj updateBusinessLogic4(){...}
    }
    ```

    ## Bad Example - Coupled DAO Service
    ```
    /**
    * This is an example of a class doing more than it needs to
    * This class should handle Team DAO logic
    * Another class should handle TeamPlaer DAO logic
    */
    public class BadTeamService{
    public ResponseObject saveTeam(Team team, List<TeamPlayers> teamPlayers){
    validateTeam(team); // throw TeamValidationException extends RuntimeException if invalid
    validateTeamPlayers(teamPlayers);
    // business logic for updating team and its players
    insertOrUpdateTeam(team);
    insertOrUpdateTeamPlayers(teamPlayers);
    }
    }
    ```

    ## Good Example - Decoupled DAO Service
    ```
    /**
    * This is a better implementation to maintain single responsibility between DAO entities
    */
    public class GoodTeamService{
    GoodTeamPlayerService goodTeamPlayerService = new GoodTeamPlayerService();
    public ResponseObject saveTeam(Team team, List<TeamPlayers> teamPlayers){
    validateTeam(team); // TeamValidationException extends RuntimeException
    // business logic for updating team and its players
    insertOrUpdateTeam(team);
    goodTeamPlayerService.saveTeamPlayers(teamPlayers);
    }
    }
    public class GoodTeamPlayerService{
    public ResponseObject saveTeamPlayers(List<TeamPlayers> teamPlayers){
    validateTeamPlayers(teamPlayers); // TeamValidationException extends RuntimeException
    // business logic for updating team and its players
    insertOrUpdateTeamPlayers(teamPlayers);
    }
    }
    ```

    ## Conclusion
    Once you are done refactoring, make sure you take time to reflect and ensure these changes are an improvement to maintainability. You should design your classes to be easily manageable and encourage ease of use. While God classes also have their place in software development, they typically do not have either trait.

    Writing code is an art form. It’s very similar to how a musician writes music or how an artist paints a portrait. Becoming a great artist takes time and practice. It takes making mistakes, learning what doesn’t work, and how to go about solving problems. Learning from blunders and being able to recognize when you’ve faced a problem you have already solved or having the ability to model similar problems. Sometimes you need to think outside the box, while other-times keeping things simple is often the best solution.
    Writing code is a true art form. It’s very similar to how a musician writes music or how an artist paints a portrait. Becoming a great artist takes time and practice. It takes making mistakes, learning what doesn’t work, and how to go about solving problems. You need to learn from blunders and be able to recognize when you’ve faced a problem you have already solved. You should be able to model solutions based on these problems. Sometimes you need to think outside the box, while other-times keeping things simple is often the best solution.

    If you liked this post feel free to follow me! I would like to take you on a journey of becoming the best you can possibly be.

  2. fourgates revised this gist Sep 9, 2020. 1 changed file with 67 additions and 1 deletion.
    68 changes: 67 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,67 @@
    # Test
    SOLID is an acronym for several of the most useful [OOP](https://en.wikipedia.org/wiki/Object-oriented_programming) design principles:

    - [**S**ingle Responsibility](https://en.wikipedia.org/wiki/Single_responsibility_principle)
    - **O**pen/Closed
    - **L**iskov Substitution
    - **I**nterface Segregation
    - **D**ependency Inversion

    In this post, I will cover the first principle, Single Responsibility. I hope these posts will give you an understanding of how these principles can improve the way you write code and maybe impress the next person that reviews your code!

    ## Single Responsibility Principle

    >
    "*A class should have only one reason to change*"

    >
    -*Robert C. Martin*

    A class should encapsulate responsibility. A simple way to implement this is to group together code that is going to change for the same reason. This allows us to write modular code that is easily testable and maintainable.

    Another reason for learning this principle is to learn how and when to refactor code. Take a look at your source control and find the top five most touched files. There is a good chance these classes are breaking the Single Responsibility Principle (SRP). If these areas are constantly changing or, worse yet, frequently creating bugs this may be a great place to apply this principle.

    ```
    git log --pretty=format: --name-only | sort | uniq -c | sort -rg | head -10
    ```

    ## Single
    What does "single" mean? Stop right there. This does not mean you should be writing one method classes! This simply means all the code in a module should generally have the same theme or reason to change. Let's review an example.

    `// TODO i don't think I like this example`

    Accounting software may have many different calculations based on inputs from different forms. At a high level, it may make sense to keep all of these calculations encapsulated into one class, but this can become quite cumbersome. It may make more sense to break down each calculation into a class for a given form; you can have one class responsible for calculating a W-2, while another handles a W-4 form. This way the only reason a class would have to change is if it's corresponding form changes. Separating these actions into their own class can reduce complexity, increase ease of use, and result in a SOLID design.


    >
    A "God Class" is an object that controls too many other objects in a system and has grown beyond all logic to become, The Class That Does Everything.

    A common symptom of "single" is having common dependencies (`@Autowired or Parameterized). If you have class B and class A requires class B to do work these classes are considered **coupled**. Now say class A needs classes B-Z to do all its work, this is now considered a **problem**. If a class has an abundance of dependencies it can't possibly be doing a single action! This is often a red flag, so keep an eye out!


    >
    Pro Tip: When refactoring a God Class start with abstracting dependencies to a new class and take the dependent code with it!

    ## Bad Example

    ## Good Example

    ## Conclusion
    Once you are done refactoring, make sure you take time to reflect and ensure these changes are an improvement to maintainability. You should design your classes to be easily manageable and encourage ease of use. While God classes also have their place in software development, they typically do not have either trait.

    Writing code is an art form. It’s very similar to how a musician writes music or how an artist paints a portrait. Becoming a great artist takes time and practice. It takes making mistakes, learning what doesn’t work, and how to go about solving problems. Learning from blunders and being able to recognize when you’ve faced a problem you have already solved or having the ability to model similar problems. Sometimes you need to think outside the box, while other-times keeping things simple is often the best solution.

    If you liked this post feel free to follow me! I would like to take you on a journey of becoming the best you can possibly be.

    ## Resources

    https://stackify.com/solid-design-principles/

    https://www.toptal.com/software/single-responsibility-principle

    https://hackernoon.com/you-dont-understand-the-single-responsibility-principle-abfdd005b137

    https://en.wikipedia.org/wiki/Active_record_pattern

    https://softwareengineering.stackexchange.com/questions/150760/single-responsibility-principle-how-can-i-avoid-code-fragmentation

    https://codeburst.io/understanding-solid-principles-single-responsibility-b7c7ec0bf80
  3. fourgates created this gist Sep 9, 2020.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    # Test