Fixing a stubborn application?



  • Hi,

    I wrote about this in 2019: https://what.thedailywtf.com/topic/26795/stubbornness?_=1620023285426

    But now, I'm actually making an effort to finally go and fix the issues. The old adage goes "if it ain't broken, don't fix it", but the application is essentially unmaintainable. It's written as a Java Swing application, so no way that you can run it as a modern web-based application.

    What I'd like to do is throw away all the front-end code, and replace it with a Vue.js front-end with a REST-based Java/Spring Boot back-end. The business logic can stay largely the same, as can the entity classes which is important.

    The big problem is how the application is built. I've identified quite a few anti-patterns, and the most important are these:

    • Inner platform effect/not invented here/re-inventing the (square) wheel
    • Singleton pattern/God object
    • Inheritance over composition (can't touch one thing without affecting everything else)

    It's especially the Singleton pattern that's killing me. To give an example, this is a financial application that can work with different currencies. There's also a base currency, but the check to ensure that the correct currency is used for the area that the application runs in. For example, the application runs in Mexico and uses pesos. This check takes place in the entity class, which then makes a call to a static method in the Configuration singleton object. I'm all for a rich domain model, but this is just problematic.

    Rather than looking for a solution, what I'd like to know is whether somebody has been in a similar situation, what their approach was, and what they found worked, or didn't work so well. So that maybe I don't go down some rabbit hole.



  • @Severity_One said in Fixing a stubborn application?:

    Hi,

    I wrote about this in 2019: https://what.thedailywtf.com/topic/26795/stubbornness?_=1620023285426

    But now, I'm actually making an effort to finally go and fix the issues. The old adage goes "if it ain't broken, don't fix it", but the application is essentially unmaintainable. It's written as a Java Swing application, so no way that you can run it as a modern web-based application.

    What I'd like to do is throw away all the front-end code, and replace it with a Vue.js front-end with a REST-based Java/Spring Boot back-end. The business logic can stay largely the same, as can the entity classes which is important.

    The big problem is how the application is built. I've identified quite a few anti-patterns, and the most important are these:

    • Inner platform effect/not invented here/re-inventing the (square) wheel
    • Singleton pattern/God object
    • Inheritance over composition (can't touch one thing without affecting everything else)

    It's especially the Singleton pattern that's killing me. To give an example, this is a financial application that can work with different currencies. There's also a base currency, but the check to ensure that the correct currency is used for the area that the application runs in. For example, the application runs in Mexico and uses pesos. This check takes place in the entity class, which then makes a call to a static method in the Configuration singleton object. I'm all for a rich domain model, but this is just problematic.

    Rather than looking for a solution, what I'd like to know is whether somebody has been in a similar situation, what their approach was, and what they found worked, or didn't work so well. So that maybe I don't go down some rabbit hole.

    My suggestion would be to make a design draft of a new implementation, build it by reusing code from the old application but restructuring and rewriting where necessary.
    I've done that a few times now.
    If you're lucky there are even tests for important parts!


  • Discourse touched me in a no-no place

    @Severity_One said in Fixing a stubborn application?:

    It's especially the Singleton pattern that's killing me. To give an example, this is a financial application that can work with different currencies. There's also a base currency, but the check to ensure that the correct currency is used for the area that the application runs in. For example, the application runs in Mexico and uses pesos. This check takes place in the entity class, which then makes a call to a static method in the Configuration singleton object. I'm all for a rich domain model, but this is just problematic.
    Rather than looking for a solution, what I'd like to know is whether somebody has been in a similar situation, what their approach was, and what they found worked, or didn't work so well. So that maybe I don't go down some rabbit hole.

    I remember converting an application from being intensely Singleton-based to using injected services (so they could be managed by OSGi). It was a bunch of years ago, but it wasn't a fun experience.

    Since you're throwing a way the GUI parts, simply don't worry about them. For the business logic and model bits (the bits you sensibly describe as valuable) you need to identify where all the singleton assumptions are. You then need to change all of those so that they are handed in explicitly in constructors or via property setters (Spring is ever so good at those in beans it manages). That in turn means you need to think over and over “is this class ephemeral (when I should pass things in by constructor) or is it persistent (when it will become a bean associated with some definable application-relevant lifetime)?” Thinking about lifetimes is definitely one of the more productive ways to approach that. And you need to audit all the classes you are retaining this way to look for places that you need to fix. It's a big job. It's marginally easier if you can pull the rug out from things so that places that use singleton configs (etc.) at least show up as compile errors, but that doesn't always work. (In our case, we were getting rid of a class loader that pre-injected singleton services into private fields. Where it would pull the instantiations from JAR files loaded at runtime over the internet. Absolutely ghastly, and completely unmaintainable.)

    Once you've got the singletons cleaned out (or at least converted into being things that you expect to be singletons only because you've configured the app that way, not because you've hard-coded the fact in the bottom level of the model) then you can look to refactor what you have left.

    Good luck.


  • Considered Harmful

    @dkf said in Fixing a stubborn application?:

    @Severity_One said in Fixing a stubborn application?:

    It's especially the Singleton pattern that's killing me. To give an example, this is a financial application that can work with different currencies. There's also a base currency, but the check to ensure that the correct currency is used for the area that the application runs in. For example, the application runs in Mexico and uses pesos. This check takes place in the entity class, which then makes a call to a static method in the Configuration singleton object. I'm all for a rich domain model, but this is just problematic.
    Rather than looking for a solution, what I'd like to know is whether somebody has been in a similar situation, what their approach was, and what they found worked, or didn't work so well. So that maybe I don't go down some rabbit hole.

    I remember converting an application from being intensely Singleton-based to using injected services (so they could be managed by OSGi). It was a bunch of years ago, but it wasn't a fun experience.

    Since you're throwing a way the GUI parts, simply don't worry about them. For the business logic and model bits (the bits you sensibly describe as valuable) you need to identify where all the singleton assumptions are. You then need to change all of those so that they are handed in explicitly in constructors or via property setters (Spring is ever so good at those in beans it manages). That in turn means you need to think over and over “is this class ephemeral (when I should pass things in by constructor) or is it persistent (when it will become a bean associated with some definable application-relevant lifetime)?” Thinking about lifetimes is definitely one of the more productive ways to approach that. And you need to audit all the classes you are retaining this way to look for places that you need to fix. It's a big job. It's marginally easier if you can pull the rug out from things so that places that use singleton configs (etc.) at least show up as compile errors, but that doesn't always work. (In our case, we were getting rid of a class loader that pre-injected singleton services into private fields. Where it would pull the instantiations from JAR files loaded at runtime over the internet. Absolutely ghastly, and completely unmaintainable.)

    Once you've got the singletons cleaned out (or at least converted into being things that you expect to be singletons only because you've configured the app that way, not because you've hard-coded the fact in the bottom level of the model) then you can look to refactor what you have left.

    Good luck.

    I would add - rip the rich domain model if you can, and pull that stuff away from the classes onto interfaces with default methods. That'll help clarify where The Ancients mixed bounded contexts.



  • Thanks, everybody. It's given me some ideas and insights. It's a daunting task, but I now have a clearer picture of what I should be focussing on.


Log in to reply