Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Organizing a solution, need tips

I'm organizing a solution and I need some tips on how to properly arrange the project's components.

Right now I have everything implemented on a single project, but I feel like it makes sense to isolate some of the components on their own projects. The main modules I have are categorzed by folders on the project, and are the Logic module, Database Access module and the Model module. It makes sense to me that these modules should be defined on their own project (maybe as a DLL).

Now, my question comes from the fact that during the application startup, the logic instantiates a configuration class which reads configurations from the app.config file and is known by these modules. Does it make sense to isolate the configuration into it's own project, to prevent the other modules from depending on the logic module? If so, should the configuration class implement from interfaces so that each module only has access to it's relevant configurations?

like image 659
EZ PZ Avatar asked Oct 21 '22 04:10

EZ PZ


1 Answers

"The main modules I have are categorzed by folders on the project, and are the Logic module, Database Access module and the Model module... the logic instantiates a configuration class which reads configurations from the app.config file and is known by these modules."

The picture this paints to me is that you've got a class or classes that either take the configuration class as a constructor parameter, or there's a global/ singleton instance of the configuration class that the other classes make use of.

But the configuration class can read configs, etc. Presumably, the other classes don't need something that can read configs. They just need some values* (that happen for now to be read from a config). Those other classes don't need to go out and ask anybody for those values**; they should just require those values as parameters in their constructors.

This way, those other classes do not need to have any knowledge of the configuration class. Someone just hands them the data that they need. But who?

The answer is the entry point(s)***. Each project in the solution that contains an entry point (console apps, web apps, and test projects) has the responsibility for interfacing with the environment; it knows the context that it wants the rest of the code to run in. So the entry points need to get configuration information by whatever means necessary (e.g. your configuration class or the autogenerated MyEntryPoint.Properties.Settings) and then supply that to the constructors of the other classes they need.

*If each class requires a great deal of configuration information (as your comment below implies), consider either breaking those classes up into something simpler (because needing a lot of configuration may point to an ill-defined responsibility) or grouping the necessary information into DTOs that represent coherent concepts. Those DTOs could then be placed in their own project that can be referenced by both consumers and producers of configuration information.

**This assumes that the values obtained from the configuration class are constant for the lifetime of the objects that would be constructed with them. If not, then instead of taking those values as constructor parameters, you should take an interface (or Func) that you can call for the info you need when you need it. Those interfaces could be defined in an otherwise-empty project which anybody can reference. This sounds like what you're getting at with

"should the configuration class implement from interfaces so that each module only has access to it's relevant configurations?"

When you say

"Does it make sense to isolate the configuration into it's own project, to prevent the other modules from depending on the logic module?"

the answer is yes and no. The Logic module does stuff; doing stuff implies a need for tests; tests want to configure whatever they are testing in whatever way suits the test. So Logic shouldn't be responsible for configuration; it should itself take in information from whoever does the configuration. Rather, configuration is the entry points' job.

***I'm using "entry point" a little loosely here. I'm not talking specifically about the .entrypoint IL directive, but just the first places in your code that can be given control by stuff outside of your control. This includes Main in C# console apps, HttpApplication.Application_Start in web apps, methods recognized as tests by the test runner of your choice, etc.

like image 119
Jerry Federspiel Avatar answered Oct 22 '22 18:10

Jerry Federspiel