For code to be self-documenting, I like to do any sort of business rule at the lowest level. If I have a business rule that says, "When the requested delivery date is less than 30 days, put a flag so a customer service representative can approve it," I have a matching method which might be called, "AddFlagIfShortLeadTime."
When you compose your system from these small components, you find you don't need state in order to accomplish work. In our example above, AddFlagIfShortLeadTime takes in the model it might operate on and returns a model of the same type with the transformations applied. If any information from a database is needed, we can pass it into this method as well. Let the something else worry about querying the database.
One interesting thing about this is that I rarely see this sort of pattern in a C# codebase. I can see it in other languages which primarily work in a functional paradigm, but I'm not sure why I don't see it in my main language. Below are some of my reasons for doing it. I'd love to hear if anyone has thoughts on why this is or isn't a good idea.
It's easier than DI and more DRY than multiple instantiations
There's still an argument about whether to use dependency injection. I've found that if I introduce a static class, neither side gets mad. A common argument for DI is that it's hard to instantiate classes. With static classes, you don't have to instantiate anything. An argument against DI is that it's hard to work with. With static classes, you don't have to work with DI at all.
Unit tests are easy
Of course, I'm not advocating for making private things public, but if you happen to need to expose your static class, zero properties and no instanciation means no mocking. You can focus on what you're really trying to test - your business rules.
It's better for your computer
I don't know a lot about this, but I do know that keeping an instanciated object takes processing power. Static classes can be called upon by the compiler at any time without instantiation, and so take up less processing power... Or something like that.
It encourages modular thinking
Usually you shouldn't just use static classes for everything. Static classes are great for documenting business rules and terrible for reading or writing to databases. By using static classes by default, we can separate our business logic by default.
Do you disagree with this approach? I have found it odd that I can't find many examples outside of my own code where people do this. Let me know what you think. 😀
Top comments (6)
In my opinion, classes Single Responsibility is to create instances.
Overloading them with librarish behavior is a smell
Code Smell 18 — Static Functions
Maxi Contieri ・ Nov 6 ・ 1 min read
Why don't you create stateless objects ?
Object creation is very efficient on modern Virtual machines
Just, please don't use Singletons
Code Smell 32 - Singletons
Maxi Contieri ・ Nov 23 ・ 2 min read
I totally agree that singletons are bad, even if it's just for the race conditions they can introduce.
Would you explain more about why static classes violate the single responsibility principle? I went to the post, but I'm still having a hard time seeing this. It appears to me that if the whole class is static, and the function encapsulates business logic, it is still one representation in the system even if the class isn't ever instantiated.
An object should do just one thing
Classes are objects. They define the creation of their instances.
In most languages you cannot manipulate classes and use them polymorphically , so you can't mock them or plug them on tests. therefore, you have a global reference too difficult too decouple.
Hmmm... I guess I'm still not convinced. What I'm talking about using these for, I would never want to mock or inherit from.
I could see your argument that this creates strong coupling, but I would only ever call this code in one place and I would want it to fail at the same time as the rest of my user flow. I'll have to think more about the nature of coupling though. That may win me over in the end.
Coupling is not obvious on small systems.
But it is the infection on larger ones
I'm using this in a 100,000+ line, enterprise scale code base and having great success 😁