Progressive refactoring

Lately I watched this video of Jim Weirich's refactoring video again.

I guess I could have watched it more carefuly the first time, because I'm missing a point when I refactor web applications to decouple business code from framework.

Usually I:

  • Look at the controller that call to the feature I want to extract
  • Complete the test harness if needed
  • Create an isolated business class that perform the feature, driven by pure unit tests
  • Create a repository service to store and fetch the data from the database
  • Integrate the class when I'm done in the contoller

This has some downsides:

  • It's not progressive enough in term of integration. The new class is wired or it is not.
  • It make me think about a lots of implementation details upfront
  • Iterate and go backward in case of error, if I miss a thing from intial feature

Look at his strategy

  • start with the controller and extract stuff with the goal of decoupling business logic from framework logic
  • refactor can be done in the green (tests passing) all the time
  • it can be progressive, changes can be deployed anytime. The system remains in an hybrid state though, but as the features are still working, this is just a developer concern.

This can prevent the fear of refactoring.

I like his usage of test doubles (mocks), to remain in the flow while writing tests. I'm not a fan of mocking framework, because I had experiences where they where hard to configure and their behaviour where not clear to me. But here (maybe thanks to rspec), it actually seem to facilitate test writing process.

The idea here is to mocking at boundaries to avoid lying (fantaisy) tests and remember not to mock things you don't own.

This approach remains controversial in 2020. The objective can be misunderstood. Okay, the business logic is extracted but does it worth the introduced complexity and the risk of regression? Web frameworks usually come with tooling to ease integration testing against a database, so what is the point?

To me, it's speed and allowing application to evolve beyond framework. Speed because pure unit tests run at the speed of light. You can write more of them and run them more often while staying in the flow, which is the goal of Test Driven Development. Patterns like repository allows to put all the calls to the storage infrastructure in one place, making it easier to tune and change.

Posted on 2020-11-15 at 23:00

Previous Back Next