10

I'm the sole developer on a project that, like for any software project, may be taken by somebody else in the future.

Let's say I used the pattern X to implement feature A. After developing and finishing the feature, I realize I could implement the same feature using pattern Y, which I just learned about. But feature A is working nicely, and refactoring from X to Y is time-consuming and gives little benefit.

Then it's time to implement feature B. It's similar to A, but this time I want to take this opportunity to play with pattern Y. I'm happy about the end result, better than when doing feature A, but now my code uses two different patterns, X and Y, for similar features.

But there's no real reason to use different patterns, except for the fact that when building feature A I wasn't skilled enough to use the same pattern as for feature B.

Note that this question is not about choosing the right pattern for a given problem; it's about two patterns co-existing in the code base to solve similar problems, that could be reduced to one given enough time to refactor.

  • Is that code smell?
  • What are the disadvantages of keeping the source code like this?
  • Should I've sticked to using one pattern only? i.e. refactor A to use Y or keep using X when writing B?
  • How, in the source, can I communicate that the reason why there are two different patterns for similar features is essentially no reason?
  • Am I worrying too much about what the next developer thinks about my code?
7

If pattern X and Y solve the same problem and neither is objectively better, then you should decide on one and stick to it. If it is at all possible you should strive to solve the same problem the same way consistently.

You are not worrying too much, rather it is a serious code smell which you should definitely handle and clean up.

The downsides to having different solutions to the same problem in a codebase:

  • it will take twice as long to understand the code
  • it will take twice as long to modify code when you change some of the behavior which involves the pattern
  • you will have twice as many bugs
  • current and future colleagues will hate you
2

I agree with JacquesB's answer. I would add up, addressing other of your questions, that if right now you have the two patterns coexisting, and haven't had the time (yet) to refactor your application to use the one you found to be the best, you should put that in your comments in the "offending" class (the one to be refactored). This way, it's evident to the future developer (you or somebody else) that there's still some debt to be paid.

Finally, the main disadvantage of maintaining a code base like this is the added, but unnecessary, complexity. You definitively want to avoid unneeded complexity at all cost!

  • I'd rather see this in some sort of todo list or at least in addition to a note in the code. – JeffO Aug 30 '16 at 17:35
  • @JeffO I agree. Although relying only on todo lists is not without additional problems, as most of the times these are personal (not shared), opposite to the comment inside the shared code base. But again, I agree and it's probable a good idea to have both (when they definitively can't be avoided to begin with). – carlossierra Jan 26 '17 at 21:01
  • That's a good point. It should be something more than a plain Todo list to include sharing, collaboration, communication and all that other fun stuff; – JeffO Jan 31 '17 at 18:15
1

Don't play in the codebase. Write prototypes do that you can find the advantages and disavantages of one pattern/design over the other(s).

It may turn out that what intuitively feel can be reduced, may actually be more complex than having 2 different patterns.

Expect to throw a way much of the code developed for the prototype.

1

Whether or not this is a code smell is really dependent on just how similar problem A and problem B are. JacquesB's answer seems to assume they are very similar, and that if you change problem A (to fix a bug for instance) you will also have to change problem B at the same time. JaqueB could be right, but it could also be the case that A and B change independently because they aren't all that similar. In that situation you're unlikely to have the downsides described.

Based on your description it sounds like a bit of a code smell (Duplication) but it's hard to tell just how stinky the smell is. For instance if A uses Template Method and B uses Strategy the two problems could be very different despite the mirroring patterns being used. I would take a wait and see approach. In the event that problem C comes along and it's just like A and B, then I'd refactor A to be consistent with B and then creating C should be very simple. If there's a bug in A I'd also want to refactor it to match B, then fix the bug. In the event nothing changes then....it doesn't matter does it?

Having multiple ways of solving similar problems in a codebase is a fact of life. Even in the case where you're the sole developer you're going to learn new things and have new insights, so your solutions will change. As you correctly recognize you need to fix these imperfections while providing value. Redesigning (which is what you're really doing when you change a pattern) code that's never gonna change again doesn't provide value. The only real way to know it's gonna change is to actually have to make the change, which is why I'd wait for a problem C.

1

No, you can have multiple patterns used in a single code base.

However, if you are implementing a component and you are exposing a way of using it that follows a pattern, then it's probably best to stick to the one. Say, for example, I'm using the builder pattern for my REST query client, but then I implement one of the resources differently. That's going to confuse people.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.