Reduce reuse recycle comes to mind when I refactor code. Any code that is small does one useful thing that can be a candidate for a library. Catalog of useful library items should be well known within a code base so all code. When refactoring look out for things where the the current code may not be using existing library code and reinventing the wheel. Replace with code that does this with the library alternative. However if the current code has a fringe or divergent reason for not using the library function/method the library may need update to cover the fringe use case so there is no regression in the code your currently trying to refactor. Then also in the back of your mind be on the lookout for code that could be useful as a new library function, class or added to an existing class as a new method. When refactoring we want to reduce down as much as possible to useful reusable and code that can be well tested and well documented of its behavioral use cases.
The recycle is then to look at existing libraries to ensure they also follow the same rules as the current code which you are refactoring in the first place.
Then... you may still not be done. You need to then look at the pattern and structure of the code and look for code with bad smell (various levels of nested conditional statements, loops, etc...). Any thing you can do to remove layers of indented code, changing the structure if need be to be more linear top-down adding checks to short circuit, throw exceptions and then handle those exceptions. Basically anything you can do to improve the big-O of the code. This includes making sure all input parameters are validated and fail early if not. Then also output validation to ensure the return is sane. Then be on the lookout for security issues where the code may default to a true state, as you want to ensure if there is a problem you’re failing gracefully to a secure state so that there is not a hole or way to escalate security permissions, etc...
Then... look at unit tests, is there coverage of all of the code, is there well defined behavior documented in the unit tests, is there use cases you spotted not being covered by unit tests, is the code that rationally can’t be unit tested is that documented in the unit test code and then states this is end to end and logically can only be test through end to end testing, or other means (including documentation how those tests are run, if so).
When going through a process of refactoring, using reduce-reuse-recycle; you should develop a living document that is a check list of what to be on the look out for. Then when using the checklist, developers doing the refactoring process should start be taking notes of what the code does, intended use, and make observations based off what they are seeing. They can then later review those observations against code comments, api documentation, test frameworks, etc... to ensure that the code does what it says does against the previously existing documentation (if that even exists)
The other thing which is super important. Refactoring is not rewriting. You are not designing and implementing a solution or trying to change behavior. You are simply trying to make the code have a smaller cross section, and be more efficient be reducing it to common calls of library code. When you spot bad smell, questionable taste in design patterns you don’t fix it now, you document with code comments todo’s etc... and how to fix and open a new task to fix that section of code. Keep on going drilling down through the code layer to layer. Then you recycle again and start completely again when working those tasks just created. The goal is to create small easily worked rewrite tasks (at first) with sign posts to direct places in the code and what needs done. Then you will have a sense of scope needed to implement the refactor’s rewrite here, there, not using library here but should be, library is missing this feature move it from to there kinds of tasks.
Then risk management, and timeline management. Is it worth doing now, if so when do we do it and pencil it in?
Remember refactoring code is just math. Trying to reduce a complex equation down to its smallest form that can be easily understood.
[+] [-] iamNumber4|6 years ago|reply
The recycle is then to look at existing libraries to ensure they also follow the same rules as the current code which you are refactoring in the first place.
Then... you may still not be done. You need to then look at the pattern and structure of the code and look for code with bad smell (various levels of nested conditional statements, loops, etc...). Any thing you can do to remove layers of indented code, changing the structure if need be to be more linear top-down adding checks to short circuit, throw exceptions and then handle those exceptions. Basically anything you can do to improve the big-O of the code. This includes making sure all input parameters are validated and fail early if not. Then also output validation to ensure the return is sane. Then be on the lookout for security issues where the code may default to a true state, as you want to ensure if there is a problem you’re failing gracefully to a secure state so that there is not a hole or way to escalate security permissions, etc...
Then... look at unit tests, is there coverage of all of the code, is there well defined behavior documented in the unit tests, is there use cases you spotted not being covered by unit tests, is the code that rationally can’t be unit tested is that documented in the unit test code and then states this is end to end and logically can only be test through end to end testing, or other means (including documentation how those tests are run, if so).
When going through a process of refactoring, using reduce-reuse-recycle; you should develop a living document that is a check list of what to be on the look out for. Then when using the checklist, developers doing the refactoring process should start be taking notes of what the code does, intended use, and make observations based off what they are seeing. They can then later review those observations against code comments, api documentation, test frameworks, etc... to ensure that the code does what it says does against the previously existing documentation (if that even exists)
The other thing which is super important. Refactoring is not rewriting. You are not designing and implementing a solution or trying to change behavior. You are simply trying to make the code have a smaller cross section, and be more efficient be reducing it to common calls of library code. When you spot bad smell, questionable taste in design patterns you don’t fix it now, you document with code comments todo’s etc... and how to fix and open a new task to fix that section of code. Keep on going drilling down through the code layer to layer. Then you recycle again and start completely again when working those tasks just created. The goal is to create small easily worked rewrite tasks (at first) with sign posts to direct places in the code and what needs done. Then you will have a sense of scope needed to implement the refactor’s rewrite here, there, not using library here but should be, library is missing this feature move it from to there kinds of tasks.
Then risk management, and timeline management. Is it worth doing now, if so when do we do it and pencil it in?
Remember refactoring code is just math. Trying to reduce a complex equation down to its smallest form that can be easily understood.