Refactor Cheat Sheet (OOP)

_config.yml

These ideas are drawn from Martin Fowler’s book: Refactoring: Improving the Design of Existing Code and also from Uncle Bob’s book, Clean Code. You can get them from the Book Depository or Amazon or any good programming book store (if any exist anymore in this day and age).

If you are going to start Refactoring, here are some methods/techniques which you can start doing. In my opinion, I think it very helpful to keep in the back of your mind how you would like a design to be. Refactoring with no concept of how the class should look, and just blindly refactoring – while good and effective, is something that I believe one should avoid.

Refactor

  1. Extract and break down complicated bits. i.e. put them into their own methods. And if necessary, into separate classes. Name by what the method does, not how it does it. (because the how is unimportant and that can change).
  2. Rename variables to proper ones.
  3. Ask whether it actually belongs there? If not, extract and put it in the relevant class
  4. Get rid of any temporary variables and replace them with queries - yes there is performance but it helps improve the code.
  5. If you have to extract something that lives both inside and outside a loop – then recreate the loop in a separate method.
  6. Don’t reassign variables. E.g. using and re-using and re-assigning the variable x in a complex operation.
  7. Don’t assign to a parameter!
  8. Prefer to return only one result.
  9. (a) Extract to readable and simple methods, and if that is not possible then: (b) Replace method with method object. (practice this).
  10. You can extract methods and fields to their own class, and implode fields and methods back into another class.
  11. Hide Delegation: instead of this: c# employee.getDepartment().getManager() do this instead: c# employee.getManager() - hide the delegation within the employee object! This will make life a whole lot easier for you if you need to change something.
  12. Introduce Foreign method: You need to add a method to a foreign class which you don’t have access to. Simply create a new method in your current class and take pass the foreign class as the first parameter. Add a note to say it’s foreign – you can even make it a static method. Make sure you pass in everything as parameters so you can quickly take it out when required.
  13. Or adding additional functionality to a class you don’t own. You can: (a) use a wrapper, or (b) subclass the original - review caveats to doing so in Fowler pg. 134-137. Organising Data
  14. Use getting and setting fields.
  15. Don’t use arrays to hold different sets of data – convert it to a class instead.

Clean Code:

Goal: Code should be: (A) Easily readable – it should read like a novel or story. You should never have to think. (B) Should be easily modifyable without the creation of a million different bugs.

Naming

  • Avoid ambiguous names.
  • Consider against employing names descriptive of the data container: e.g. CustomerList
  • Names should be distinct and not too similar: e.g. CatDog and CatDag.
  • Use words that are meaningful, and not things like: BJDkejr322.
  • A class name should not be a verb.

Method Names:

  • Verbs, get/set, or Is
  • Use static factories with descriptions when you have multiple constructors. E.g. Complex fulcrumPoint = Complex.FromRealNumber(23.0); rather than ` Complex fulcrumPoint = new Complex(23.0);`
  • Be consistent. E.g. use get or retrieve or procure but never all three for the same thing.

Functions

  • Keep them small.
  • They should do only one thing. (if you cannot extract another function from it without restating its implementation then it’s only doing one thing): a. Change state or b. Return an answer. (not both).
  • Uncle Bob suggests a function should ideally have little to no arguments.
  • And it shouldn’t change anything in the processes – if it does anything sneaky, it should be obvious from the name.
  • If you have to check the header, after seeing the name of the function then the name is not good.
  • Methods shouldn’t do stuff and handle exceptions at the same time. Methods should do stuff, throw exceptions – and those exceptions should be handled in a wrapper.
  • Avoid error codes – because they need to be handled right away, whereas exceptions bubble up.

Comments

  • If you write your code clearly enough, then you shouldn’t need comments – everything should be apparent and discernible from the method and variable names.

Data Structures

  • Do not expose implementation, but you need to abstract out the representation of the underlying data.
  • Procedural or Objects? With objects if you want to add functionality, you’ll have to do it across the board. But you can easily add a method to procedural code – and the data structures need not know about it. With OOP code you can easily add new objects, but in procedural code, when you do this, you

The Law of Demeter

  • Data structures: you can expose their internals. But with objects: you shouldn’t expose their internals.
  • More Examples of this:

Exception Handling:

  • Start with try/catch exceptions. Then build around it.
  • Don’t return null! Either throw an exception or use the Special Case pattern.

Boundaries (i.e. using outside code):

  • Key point: Wrap! Wrap! Wrap!
  • If you are using outside packages, then you can compartmentalize it with wrappers so that if something changes, the changes have a limited impact on your code.
  • Testing: Test that the outside code does what you expect. If it doesn’t do what you expect then you will know immediately through your tests.
  • What about the Console.WriteLine() method. This is an outside class. Don’t we need to wrap this? Soon you’ll be wrapping everything, and that could make things difficult in and of itself. Be judicious about what you wrap. Wrap things that are highly susceptible to change – e.g. outside APIs that have just been released.

Tests

  • Write a test before code.
  • Don’t write more of a unit test that is sufficient to fail the test.
  • Don’t write any more code than is sufficient to pass the failing test.

Miscellaneous Rules:

  • You generally don’t want a situation where a low level method/function forces a change in a high level function.
Written on September 22, 2017