Last active
September 11, 2020 20:23
-
-
Save fourgates/db5168902b83284e48aa047467d9a54a to your computer and use it in GitHub Desktop.
Revisions
-
fourgates revised this gist
Sep 10, 2020 . 1 changed file with 150 additions and 10 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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, 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. 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 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: ``` public class Car{ private Engine engine; public void start(){ this.engine.start(); } } ``` 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. 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 - 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 - 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 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. -
fourgates revised this gist
Sep 9, 2020 . 1 changed file with 67 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1 +1,67 @@ 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 -
fourgates created this gist
Sep 9, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ # Test