6

Alright, let me shine some light on the ambiguous question. We have an analytics application written in Angular 2 and Scala that's used by quite a number of businesses. Some time last year there was an idea to use the apps' charts and features to display different type of data for a very limited number of customers for a higher price. Since time was of the essence we optimised the front-end code, abstracted the bunch of visualisations and it worked like a charm. One Angular 2 codebase powers two solutions.

Few months later the problems started. Since the business customers of the 2nd solution pay a lot of money and the solution needs to be slightly tailored to almost every one of them, they started asking for different features, custom add-ons etc. The app starts turning into a weird behemoth where 80% of the code is old analytics and 20% is custom if-checks to determine which of the 2nd solution's users it is and how we should change the behaviour of the component for him.

The 2nd solution was developed very quickly as a proof of concept/hack. I offered to split the codebase, because the current one is slowing the development of the core analytics platform and is a source of bugs occasionally. The argument against it is that the company wants to keep adding features to the later solution, so they want to keep in in one codebase.

Other option is to split the codebase and abstract all the common components into a module that is then injected into two apps, but it's a lot of work and the work on the analytics platform will suffer because of that. Also, since the product features tend to change a lot due to new ground we're breaking into, we would have to keep changing the abstracted modules every now and then which would then require making sure they still work in both applications, so the devs working on analytics would be still slowed down by requirement to maintain compatibility with the 2nd solution.

The front-end of both solutions looks very much alike but they serve similar, although different purpose. It doesn't feel right to have them in 1 polluted codebase.

What are your thoughts on that? What other solutions can we implement?

  • 1
    Welcome to SE stackexchange! Are these program alterations the same throughout each version? In other words, could you easily modularize the changes between each version? – Neil Jul 25 '17 at 9:51
  • Hi Neil, thanks for the reply earlier. Happy to be here too. Unfortunately program alterations are slightly different with certain Angular components only visible in one solution or another. If you ever worked with Angular, the business logic tends to be quite close to the surface, namely DOM elements. – codeepic Jul 25 '17 at 21:25
4

Library/project split

If the customizations for each client is something that can be easily modularized, you could simply write one or more classes with an abstract base defining these customized behaviors within the program. Find all the points in your project where you contain long if else chains for differing client behaviors and go through the trouble of A) providing a default behavior and B) allowing yourself to personalize that behavior. Then write projects for each client which provide their own implementation, ideally in its own individual project with reference to the base or perhaps the use of plugins to change behavior simply with the existence of an external library (Java has support for this for instance). In this way, the personalizations are in their own libraries, but the program is one and the same.

Code split

However as these things go, customizations are rarely so clean cut, so the alternative is to completely copy the code base. The main advantage in this is you eliminate the risk of creating cross-client bugs. Changing the behavior for one client is guaranteed not to have an impact on any other client. If this is a common problem, then this is a considerable advantage. That said, the major disadvantage to this approach is maintenance hell. Every change that must be made for one client must be applied to all other projects requiring testing for each and every other project. You could arguably just apply to one project, but you then risk that the list of features and/or bug fixes applied to each version becomes near impossible to keep track of.

Conclusion

Certainly the easy and quick solution is the code split, but I would strongly discourage that if you can help it. The smart thing would be to take the time to modularize your project. Take it from a programmer who's been through this before. No point taking the easy country road over the road less traveled if the easy country road eventually leads directly into an active volcano. If you can't get your boss to understand that it is best for the health of the project, explain it in terms of technical debt and maintenance costs that will almost certainly come afterwards.

  • I get what you're saying and we have been using abstract classes from which two solutions inherit modifying the behaviour. The cut between the two is not clean though. The application is reactive, user interactions in one part trigger changes in other components. Then depending on the version, we fetch different data, display different things. I am weighting all the options here and splitting the codebase, as naive as it sounds, still seems the best approach to me. In the coming months number of features that are only present in one app or another will increase with only some overlap. – codeepic Jul 25 '17 at 10:33
  • " you could simply write one or more classes with an abstract base defining these customized behaviors within the program" -> Abstracting customized behaviors from a legacy codebase is rarely simple, however. Extra care should be taken while doing this to not break stuff by accident. – T. Sar Jul 25 '17 at 11:31
  • @T.Sar You're right, not likely, but still, certainly preferable if there's the possibility. – Neil Jul 25 '17 at 13:36
4

You have two applications. These seem separate products which, while they have a common origin, are not developing in the same way.

From the looks of it, the applications share their data, maybe also their model, but not their views / viewmodels.

If it looks alike but behaves differently still means that there's different controllers involved. It seems that at the moment there's a divergent path for both applications. It really is a mix of software engineering and product strategy at this point. How much can you pull the extra features away from the original application? Is it feasible to set it up as an entirely different product?

So there's two routes you could go:

  1. Develop two applications and accept that they are separate applications. (and perhaps also change the name for the new application) This implies splitting the code base. Get the common data in one back-end to serve the data and then splitting the applications through an API. If there's real commonality, you can maybe inject the common parts into both applications where applicable through a shared library, but ultimately, there's going to be two applications each with their own backlog and codebase.

  2. Bring back the features into the fold of the main app and develop the primary application as an application with "premium features", and then enable these for your customers with some claims based mechanism which enables these extra functions. You might have to re-engineer your application so you can differentiate, which can be costly. The benefits are that you can continue sharing common code.

  • The duplication is on the front-end only, the API is already in good shape. I am trying to get my head around implementing feature toggles in Angular that will not be a liability. A feature toggle is supposed to be short lived, the way they will be working in our app means, that the list of feature toggles will be ever growing - so I am just swapping one shitty solution for another. – codeepic Jul 25 '17 at 10:38
  • You're right. A claims based approach would be a more appropriate way. – Onno Jul 25 '17 at 11:27
  • Unfortunately I can't use claims based approach on the front-end. – codeepic Jul 25 '17 at 13:48
  • Not one way to get the entitlements for a user? How do you recognise users at the moment then? – Onno Jul 25 '17 at 14:16
  • It's handled by the logic in Scala and then user information is passed as a JavaScript variable into Angular app. – codeepic Jul 25 '17 at 14:21
2

I would like to say that i highly recommend the modularization approach. Although more difficult to implement its a cleaner and reusable approach. A easy case to make with management for the extra work is that these modules can be re-sold across clients and eventually go back to the "original" app enhancing its market value

  • 1
    What do you mean by modularization approach? – codeepic Jul 25 '17 at 12:39
  • 1
    basically it's the "library/project split" proposed by Neil – Leonardo Jul 25 '17 at 14:52

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.