1

I'm looking for general advice regarding the structure of applications.

In applications I've been building recently, I've started to use a class (I'll refer to it as DataManager for the rest of the question) to hold all my individual objects, and all related methods. I make the DataManager accessible by all other classes and forms by making it Singleton, and fire events from DataManager that individual components can subscribe to. The components would then access the DataManager, and update their UI accordingly.

I do it this way, because then there is a central class that manages the data of the application and allows all UI elements to access the data they need at any time. I find it makes it much easier to debug, and remember how the application works (when I have to revisit it down the line).

My question is, is this good practice? And if not, what is good practice? I'm trying to improve my application design, so would appreciate any advice on this.

NB. I use this structure in C# winforms projects.

4
  • Requests for blog posts or references are off topic for this site, but I Shall Call It... SomethingManager might be an interesting read. Feb 4, 2020 at 11:41
  • 1
    See Understanding the Composition Root.
    – Theraot
    Feb 4, 2020 at 11:45
  • 1
    I've edited your questions to try and save it from the "trigger-happy" folk who read the word "links" and just vote to close it as off-topic.
    – David Arno
    Feb 4, 2020 at 13:23
  • 1
    Try not to use the phrases "good practice" or "best practice" in your questions. Those phrases are meaningless unless you're willing to define specifically what "good" or "best" means. No, they don't mean "most popular" or "most likely to win a beauty contest." Absent an adequate definition, "best practice" means the one that most effectively meets your specific needs. Feb 4, 2020 at 14:42

1 Answer 1

4

I'm the first one who usually jumps in to say that there isn't just one true way (TM) to organize software. The agile phrase to describe it is you have to build your Minimum Viable Product (MVP). From there you can build on what you have and refine it and adapt it to your full complete needs. Experience has taught me a few things along the way, like first impressions (both about people and design) are usually wrong.

There are several established patterns for constructing an application depending on your tech stack:

These patterns help you localize and isolate changes so that you are not chasing hard to find bugs or introducing fragility.

That said, if you are just building a small throwaway application then you really don't need to put any thought to it. Just make it work and throw it away when it is no longer needed.


My story of a singleton gone wrong

I inherited a Java Swing application, where the core logic of the application was all in a set of singletons. The problem is that when the user changed a value in a drop down on one page, or the back end updated the control, the application would freeze. As the team delved into triaging the problem we discovered that there was an event that fired when the drop down was changed. That event caused an update to one of the values managed by the singleton, which in turn set off another event, which updated a similar control on another page. That other page had a trigger which set off yet another event. Bottom line is that the event updated the backend which updated the controls which updated the backend which updated the controls... until there was a StackOverflowException.

There were several lessons to learn in this scenario:

  • Statically accessible Singletons rarely help your application
    • Since they are available everywhere, everywhere is coupled with the singleton
    • This is a major cause of fragile code, where fixing one bug breaks another (unrelated) part of the app
  • Events should be locally controlled, don't have events firing from your singleton
  • The more you can localize the frontend/backend interactions the more you can properly isolate code--binding is your friend

To solve the problem, we made changes so that the display code bound to the data model, and the backend handled storing the data. The binding only updated the controls when the information was actually different. We also introduced an interface for what each singleton needed to do and used dependency injection to provide the singleton to the front end code where necessary. By severing the static access, and formalizing the interface, that removed the temptation to just shove code in the Singleton because you can access it anywhere.

2
  • Coupling can always be remediated by adding another level of indirection like an interface, which I suppose is why a lot of folks use their DI container to create a normal class with Singleton scope. Feb 4, 2020 at 14:45
  • Thanks, that's given me a lot to think about. Definetly had the issue you describe in your Swing application.
    – Sandwich
    Feb 4, 2020 at 14:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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