Should Design Patterns Be Avoided in Changing Projects?

agilechangesdesign-patterns

A friend of mine is working for a small company on a project every developer would hate: he's pressured to release as quickly as possible, he's the only one who seem to care about technical debt, the customer has no technical background, etc.

He told me a story which made me think about the appropriateness of design patterns in projects like this one. Here's the story.

We had to display products at different places on the website. For example, content managers could view the products, but also the end users or the partners through the API.

Sometimes, information was missing from the products: for example, a bunch of them didn't have any price when the product was just created, but the price wasn't specified yet. Some didn't have a description (the description being a complex object with modification histories, localized content, etc.). Some were lacking shipment information.

Inspired by my recent readings about design patterns, I thought this was an excellent opportunity to use the magical Null Object pattern. So I did it, and everything was smooth and clean. One just had to call product.Price.ToString("c") to display the price, or product.Description.Current to show the description; no conditional stuff required. Until, one day, the stakeholder asked to display it differently in the API, by having a null in JSON. And also differently for content managers by showing "Price unspecified [Change]". And I had to murder my beloved Null Object pattern, because there was no need for it any longer.

In the same way, I had to remove a few abstract factories and a few builders, I ended up replacing my beautiful Facade pattern by direct and ugly calls, because the underlying interfaces changed twice per day for three months, and even the Singleton left me when the requirements told that the concerned object had to be different depending on the context.

More than three weeks of work consisted of adding design patterns, then tearing them apart one month later, and my code finally became spaghetti enough to be impossible to maintain by anyone, including myself. Wouldn't it be better to never use those patterns in the first place?

Indeed, I had to work myself on those types of projects where the requirements are changing constantly, and are dictated by persons who don't really have in mind the cohesion or the coherence of the product. In this context, it doesn't matter how agile you are, you'll come with an elegant solution to a problem, and when you finally implement it, you learn that the requirements changed so drastically, that your elegant solution doesn't fit any longer.

What would be the solution in this case?

  • Not using any design patterns, stop thinking, and write code directly?

    It would be interesting to do an experience where a team is writing code directly, while another one is thinking twice before typing, taking the risk of having to throw away the original design a few days later: who knows, maybe both teams would have the same technical debt. In the absence of such data, I would only assert that it doesn't feel right to type code without prior thinking when working on a 20 man-month project.

  • Keep the design pattern which doesn't make sense any longer, and try to add more patterns for the newly created situation?

    This doesn't seem right neither. Patterns are used to simplify the understanding of the code; put too much patterns, and the code will become a mess.

  • Start thinking of a new design which encompasses the new requirements, then slowly refactor the old design into the new one?

    As a theoretician and the one who favors Agile, I'm totally into it. In practice, when you know that you'll have to get back to the whiteboard every week and redo the large part of the previous design and that the customer just doesn't have enough funds to pay you for that, nor enough time to wait, this probably won't work.

So, any suggestions?

Best Answer

I see some wrong assumptions in this question:

  • code with design patterns, though applied correctly, needs more time to be implemented than code without those patterns.

Design patterns are no end in itself, they should serve you, not vice versa. If a design pattern does not make the code easier to implement, or at least better evolvable (that means: easier to be adapted to changing requirements), then the pattern misses its purpose. Don't apply patterns when they don't make "life" easier for the team. If the new Null object pattern was serving your friend for the time he used it, then everything was fine. If it was to be eliminated later, then this could be also ok. If the Null object pattern slowed the (correct) implementation down, then its usage was wrong. Note, from this part of the story one cannot conclude any cause of "spaghetti code" so far.

  • the customer is to blame because he has no technical background and does not care about cohesion or the coherence of the product

That is neither his job nor his fault! Your job is to care about cohesion and coherence. When the requirements change twice a day, your solution should not be to sacrifice the code quality. Just tell the customer how long it takes, and if you think you need more time for getting the design "right", then add a big enough safety margin to any estimation. Especially when you have a customer trying to pressure you, use the "Scotty Principle". And when arguing with a non-technical customer about the effort, avoid terms like "refactoring", "unit-tests", "design patterns" or "code documentation" - that are things he does not understand and probably regards to be "unnecessary nonsense" because he sees no value in it. Always talk about things which are visible or at least understandable to the customer (features, sub-features, behaviour changes, user docs, error fixes, performance optimization, and so on).

  • the solution for rapid changing requirements is to rapidly change the code

Honestly, if "underlying interfaces change twice per day for three months", then the solution should not be to react by changing the code twice a day. The real solution is to ask why the requirements change so often and if it is possible to make a change at that part of the process. Maybe some more upfront-analysis will help. Maybe the interface is too broad because the boundary between components is chosen wrong. Sometimes it helps to ask for more information regarding which part of the requirements are stable, and which are still under discussion (and actually postpone the implementation for things under discussion). And sometimes some people just have to be "kicked in their asses" for not changing their minds twice a day.

Related Topic