2

Suppose you've been hired to perform a major refactor/rewrite of a large project that is already in production and maintained by a very small team. The scope of this rewrite is to the point where you can't really do small, behavior-preserving transformations - there are simply too many long-chain interdependencies to keep it running smoothly from one commit to the next.

This team is constantly adding new features at the request of the client, racking up more technical debt even as you pay that debt down in your rewrite. At some point, you'll want to integrate these new features, but they will also have to be heavily modified to get them to work with your shiny new implementation.

When should these new features be integrated - as they are released, or at the end when your refactor is complete? What can the "feature developers" do to make this process more efficient? What can you the refactor leader do?

alexw
  • 329
  • 1
  • 10
  • 1
    Its dificult to say exactly what to do, as i belive this would be more of business strategy than a techinal question. Can you stop delevloping the old product and only focus on the new one? If yes maybe that should be the focus, if No, why? – Mr Zach Jun 30 '20 at 02:06
  • @MrZach it's a business problem in need of a technical solution, imo. The old product has been dragging along for years and only provides partial functionality, in part because of shifting requirements and a large amount of technical debt that makes it difficult to quickly adapt. The client is much more reasonable than most, but they still want to see some sign of progress that they can understand (new features). – alexw Jun 30 '20 at 04:38

1 Answers1

3

Don't do a Big Bang

The software that already exists has taken X developers * Y Man Years to develop to the state its already in. In which universe do you think that you can catch up to that and be equivalent/better?

Strangler Pattern

Release the brand new shiny implementation as part of the old mess. Have it strangle away slices of work.

Have the two implementations talk together to ensure that data is passed around correctly.

New features are always implemented in the new world. If necessary strangling off a piece of the old world in order to do it.

This way you don't need to perform small behaviour preserving transformations. You just need to be clear about where behaviour, and data is controlled from.

Shims

It may even pay to introduce a Shim at suitable layers in the old world, such as at the repository boundary, and at the UI boundary.

This way the Repository Boundary can ensure that data is correct accross both systems.

And the UI boundary allows the new world UI to be presented to the user, even though it is still using the old world implementation for actual work.

Ugly yes, but it may be the only way to start getting away from the old world.

Kain0_0
  • 15,888
  • 16
  • 37
  • Could you clarify what you mean by "strangle away slices of work"? – alexw Jun 30 '20 at 01:31
  • [Strangler Pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/strangler?). The idea is simple, create the new way of performing business behaviour X, or a set of business behaviours. Cut across to the new way of performing these behaviours. Remove/Disable the old world methods for performing this work (so that they you do not perform a Knight Capital). And adjust any old world behaviours reliant on these to use the new world implementation. – Kain0_0 Jun 30 '20 at 01:36
  • Hmm, this is sort of what I've been doing. But there are some aspects of the new and old systems that simply cannot co-exist, for example major restructuring of the database schema. – alexw Jun 30 '20 at 01:46
  • 2
    Which is the reason for the shim at the repository level. Even if data must be dual entered it can ensure consistency. Even better if it can adapt the data on the fly to either the new scheme, or the old scheme from one backing. Even if that means a sub optimal data-store in the short run. – Kain0_0 Jun 30 '20 at 01:49