
Ask HN: Diverging products: fork codebase, create config file or other option? - mettamage
Hello hello!<p>I was wondering about your experiences, since this problem is quite common.<p>You work at a company that has a flagship product. Suddenly they need a slightly diverging product from it (that&#x27;s how it starts out). For example, the B2B version gets a B2C version, and the B2C has some extra features that the B2B version doesn&#x27;t need (e.g. credit card payments, slight UI changes). Later on, the team finds out that the B2B version also has specific features that the B2C version doesn&#x27;t need to know about.<p>The team is at the beginning of all of this.<p>The team could:<p>- Split the codebase with a fork<p>- Add a configuration file and have checks inside your code<p>- Do something else<p>How would you go about this? And what have you experienced before?
======
akavel
IMO, try to avoid fork - you'll never be able to merge it back anymore, a fork
splits the product into 2; think what will happen when you get +1 more
"special" customer.

In the 2nd company where I encountered this challenge, I introduced a single
global cross-cutting interface, giving de facto hook points in the code.
Implementations were specialized per customer; the default behaviors went by
"vanilla" (90% were empty implementations). This still led to a mess and
complex indirections, but at least we were getting some isolation and
encapsulation (a.k.a. decoupling). In particular, in case we lost one
customer, we could quickly scrap all the specialized cruft with a single clean
cut. And let me tell you, they wanted crazy customizations sometimes, and we
were not in power to resist. _edit:_ Also, when analyzing, you could at least
keep in mind only the common core + single customer's tweaks; other customers
were completely off your mind. And you could try and see how this customer's
tweaks interact between them in one place. _edit 2:_ Note that some behaviors
were still kept in the main codebase if they looked reasonably useful for
future, and just the choice would be in the customizer then. Sorry if what I
wrote is too chaotic :/ _edit 3:_ Still, remember the "[refactoring] rule of
three" \- as applied here, first just hack your new behavior into a personal
fork as if it was the only codebase, and only when it works look where to
introduce decoupling points. You will 99% always see them _much_ better from
position of hindsight than when trying to predict them initially.

That said, I'm not yet aware if there's a way to reasonably mitigate a huge
increase in complexity when supporting multiple customers.

~~~
mettamage
> That said, I'm not yet aware if there's a way to reasonably mitigate a huge
> increase in complexity when supporting multiple customers.

This is what I'm thinking with every scenario that I'm thinking about. But at
least your experience shows what option was worse (forking).

------
mettamage
So based on the comments, I found out about the following approaches:

\- Feature flags

\- Configuration options / software product lines

(see a recently published article w.r.t. the difference [1])

\- One HN comment was about plugins, but when I Google *"feature flags" vs
"plugins" I'm not finding much. I have the feeling that hooks/plugin systems
are part of the feature flags idea (not sure about this).

[1]
[https://www.cs.cmu.edu/~ckaestne/pdf/icseseip20.pdf](https://www.cs.cmu.edu/~ckaestne/pdf/icseseip20.pdf)

------
elviejo
what you do, is stablish a kernel of libraries, that are common to both
systems.

this is called a "software product line" it has been studied for decades.

here are some studies from Carnegie Mellon on the topic.

[https://resources.sei.cmu.edu/library/asset-
view.cfm?assetid...](https://resources.sei.cmu.edu/library/asset-
view.cfm?assetid=513819#:~:text=A%20software%20product%20line%20is,assets%20in%20a%20prescribed%20way).

~~~
mettamage
Thanks for the tip! It looks like a fascinating rabbit hole and I want to read
all of it :D

------
adrianmsmith
In addition to the other comments about not forking, I will add this
disadvantage of forking:

I have thought in the past that if your forking technology is a branch in git,
you can still merge changes (or cherry-pick, etc.), so all is not lost in
terms of creating features or fixing bugs which should affect both platforms.
However...

The problem there becomes refactoring. If you're e.g. using Java, with e.g.
IntelliJ, you can e.g. rename methods and all usages will also get renamed.
That's good, and that feature doesn't just speed you up, it also encourages
you to do the refactoring at all, leading to better code long-term.

However, if you have n branches, IntelliJ is only going to refactor the branch
you're on. After you've merged the change into the other branch, all the
features custom-developed for that branch will still use the old e.g. method
name, you'll have to update those usages by hand, which is a lot of work.

If you keep the code in one codebase (e.g. feature flags, config file,
whatever), if you refactor something, all the usages (even in code hidden
behind the feature flags) will also get renamed.

------
simonw
Definitely feature flags.

Forking the codebase will lead to much regret further down the line as the two
forks continue to diverge and you spend most of your time trying to update
them simultaneously or building features twice.

Feature flags mean you can keep all of your functionality on your main branch
with the least amount of additional work.

This is a great guide to them: [https://martinfowler.com/articles/feature-
toggles.html](https://martinfowler.com/articles/feature-toggles.html)

~~~
simonw
The other technique that may be worth investing in is plugins.

These could work if the following are true:

\- Many customers get their own independently deployed build of the software

\- Many future customers will want (and pay for) custom features that don't
make sense for everyone else

With plugins you can keep your core codebase from being slowly messed up by
all of those custom one-off features, which is enormously valuable.

My current principle project Datasette is the first time I've implemented
plugin hooks and it's been working out really well for me:
[https://datasette.readthedocs.io/en/stable/plugins.html](https://datasette.readthedocs.io/en/stable/plugins.html)

------
thedevindevops
On the config options side can I recommend a decent Dependency Injection
framework will make your life a lot easier, as you can have everything
configured at startup without having lots of 'if's in the code checking the
flag state. Combined with good abstraction this can make the whole thing much
easier to manage and the whole config for a given client can be checked in one
place.

------
brudgers
Feature flags?

about, [https://www.martinfowler.com/articles/feature-
toggles.html](https://www.martinfowler.com/articles/feature-toggles.html)

a product (I have not used),
[https://www.optimizely.com/developers/](https://www.optimizely.com/developers/)

------
crazypython
Depends on your codebase. JetBrains use a fork and rebase model.

~~~
mettamage
I'm Googling for this everywhere, but I can't find a good blog post on what
they actually do.

------
dyeje
Hard to say without more detail, but this seems like a good use case for
feature flagging.

