These may well be the notiest notes I’ve ever published, but just in case they’re of any use to anyone… if nothing else they may whet your appetite for the new edition of Martin Fowler’s Refactoring book.
I confess I never read it first time round (not on purpose, just there are so many books in the world and so little time…), so I’m looking forward to reading it this time. It hasn’t come out yet in the UK but should be some time in the next few weeks. Mine is already on order [drums fingers impatiently].
So anyway, Martin did a webinar today on the topic of his new book, and here are my notes:
Refactoring should be done via small changes
- v small semantics-preserving changes
- So small they’re not worth doing on their own
- String together small changes to make a big change
When adding new functionality:
- Alternate between refactoring and adding functionality
- Often it’s easier to add new functionality if you refactor first
- Balance between adding new functionality and refactoring – it’s a matter of judgement
V1 of Martin’s Refactoring book vs v2
- Some things that were included in the first book he decided not to include I the second
- Eg Unidirectional vs bidirectional – not important
- Some things he thought were too trivial for the first book, he has now changed his mind about and included
- Eg moving statements within a function
- Most notable changes = no longer centrally object-oriented
- “Extract function” used throughout instead of extract method
- One of the refactorings is around the choice between OO and non-OO
- The most visible thing here is the choice of language (javascript)
- But language is not necessarily relevant anyway
- OO vs functional
- He doesn’t see that as a huge shift
- OO should still have functional elements – referentially transparent
- They are overlapping paradigms, not distinct
Favourite refactorings?
- “Split phase”
- Hunk of computation which can sensibly be divided into two phases with a data structure communicating between them
- Eg parsing – separate the tokenising out – deal with a series of tokens instead of a stream of text
- But if you split a loop, what if you are introducing performance problems? See below…
Performance and refactoring
- Split loop is something people often worry about because it will run the loop through twice
- Most of the time it doesn’t matter – a push for clarity will not change the performance of the code
- Most of the time by refactoring you open up an opportunity for performance improvements you would never have noticed otherwise
- Then again you should run performance tests frequently
- Not necessarily with every build, but every day or two
- But most micro-changes have no impact on performance
- You will only find real performance impact by performance testing
Recommendations for other books?
- Scott Ambler and Pramod Sadalage, Refactoring Databases
- Automated migrations to allow us to modify a database as we go
- Working effectively with legacy Code, Michael Feathers
Refactoring architecture:
- Always have to ask, how do you make the smallest possible change?
- Eg extracting a data-intensive microservice from a larger system
- Most of the moves are happening within the monolith BEFORE you start firing up the external system
- Then you move stuff in really small pieces
- Things that change for similar reasons should be together – you need to see the relationship between them
Branching / trunk-based development
- Develop on a branch and merge at the end, with branch being long-lived – days, weeks or months
- Still a really common pattern
- But if something has been refactored, you don’t find out until you merge – this can blow up on you
- It means you become scared to refactor! There’s a disincentive.
- Continuous integration: Integrate with each other fully at regular intervals – at least once a day
- Every day you receive everyone else’s code changes and push your own changes back
- Removes the big painful merge problem – not saving up for a big horrible crunch
- Adage of Apollo – it hurts if you do it more often (?)
- Sorry, I wrote this down but I’ve since Googled it and I don’t really know what it’s about – I may have misheard!
- Open source development:
- Actually this CAN be a good place to use branches, because everyone working separately and you can’t guarantee all changes should be merged
- People call it trunk-based development but “continuous integration” is a better name because that’s what it’s really about
- People worry about continuous integration but it’s less painful than they think
- If you do integration every day it becomes easier and less painful until you stop even noticing
Responsibility
- Keep code base in healthy state
- If not you are stealing from colleagues, clients and employers!
- But no point saying you should do it for moral reasons, that won’t motivate people to do it
- It’s economic: Want to get more changes out more quickly
- It’s professional: We’re being paid to produce features rapidly
- It’s not up to managers or business: They don’t know how to keep code healthy – that’s what they pay us to do
Refactoring and design patterns – are they incompatible?
- With a lot of patterns, you shouldn’t introduce them right away cos they’re not appropriate and you don’t require the full strength of them yet, particularly the more complicated ones
- Introduce patterns as a result of refactoring: Refactor towards them
- This was recognised by the original Design Patterns authors (Gamma, Helm, Johnson, Vlissides)
- Also Josh Kerievsky: Refactoring to Patterns
Code smells
- Code smell of the week!
- “This week we will look at long methods” – whenever we find them we try to refactor them
When not to refactor!
- Code that is never touched
- Sitting behind an API, working quite happily, doesn’t need to change – doesn’t matter if it’s a mess!
- Don’t clean code all in one go – just a little bit more every time you go in
- Over time that will concentrate your efforts where they are most needed – ie areas modified most frequently
Refactor as a step in the red-green-refactor cycle
- You should only refactor when tests are green
- Sometimes that means you have to remove a failing test, refactor, then put the failing test back in again
- Ralph Johnson, John Brant, Don Roberts wrote the first Smalltalk refactoring book (A refactoring tool for smalltalk?)
If you don’t have tests you can’t refactor?
- “Probably safe” refactorings? Interesting route to go? Not a great thing for most people to focus on, requires a lot of expertise
- For most people you should have tests as well – after all, how do you know whether you’re breaking what’s currently there?
Final takeaway:
- Small steps, commit frequently.
- Then you can always roll back.