Principles, including `SOLID`
- Do one thing well.
- Let someone else do the hard part.
- Don’t inventing the wheel.
Don't repeat yourselfcombined withRule of three.Composition over inheritance- An interface (especially one with default interface methods feature of dotnet 8.0) is preferable to an abstract class.- Principles are an expensive thing, and not everyone can afford them.
- To understand the abstraction layer, you need to understand the reason for its occurrence, go down to the layer below.
- Programmers work for themselves
- A programmer involuntarily wants to be asked for help, so he complicates the presentation of the service he provides.
- Any dependency leads to problems.
IDEis dependency also, to know СLI commands what generated by IDE buttons are almost necessary. Hence take the time to figure it out. There are must bemakefile, config, cli etc somewhere. - The more wrappers, the more difficult to test.
- The world model is more important than its details.
- Comparison is the most important tool of knowledge.
- The only way to learn a language is to read source code, and then to coding.
- There is never enough time to do it right, but there is always enough time to do it over.
- Work is what horses die of
Principle of least astonishment(like asLiskov substitution)
All SOLID principles are partly interconnected.
The
Single responsibiltyof classes is about not inflating a class.The smaller the class, the greater the possibility of reuse.
Probably so.
Disadvantage - since instead of one class, we have several, therefore, several memory allocation operations will be required, which reduces performance. In
dotnetthere is an opportunity to create a partial class and they are used. So there is a reason.Advantages - if there are several classes, therefore, the lifetime of each of them is shorter, the object becomes available for deletion from memory earlier.
There is rarely anything in nature with a single responsibility. It is an abstraction.
I would add
Single responsibilty of methodThe same idea - the smaller the method, the greater the probability of reusing a block of code. Small procedures are easier to manipulate, replace.
Although usually, naturally, they first write in a single method, then deal with permutations. Reminds me of writing texts, reports, where the sequence of information presentation is important, roughly speaking, the sequence of paragraphs.
Methods in
runtime, as a rule, are small in size, they are removed from the stack faster.But at the same time, to improve performance, the
inliningattribute is used, which leads to the implementation of the code of the called method into the code of the calling method. Time is saved on the call. A dilemma arises - to do it yourself, or assign it to someone. Control and distribution functions require resources.In
dotnet, the ability has appeared recently (I don’t know how long ago, in general it has not always been there) to describe a method inside another method, I often come across such code.1 2 3 4
internal A() { private B() private C() }
If one internal method calls several private methods, nothing changes for testability. If they were all internal, then each one could be tested.
The
open/closedis the same logic only in relation to libraries, the functionality should not be bloated.The smaller the library, the greater the opportunity for reuse. Using internal methods allows them to be tested from an external unittest project, at the same time they are closed from clients.
The less code is subject to be changed, the better.
The
Liskov substitutionis about continuity, stability of new implementations. I would move it to the end - SOIDL.The
Interface segregationis about the same, if a class implements several interfaces, it can be assumed that the object has different responsibilities. Don’t wear a railroad uniform, beach shoes and a Panama hat simultaneously.1 2 3
A :IB, IC IB b = A; IC c = A;
Links are created to a limited number of members of class A.
Dependency inversionin other words, use abstract classesUsing Interface allows:
- testing, replacing mock objects
- changing the library version without the need to make changes to the client code.
What reasons might there be for changing the code:
- Shortcomings are discovered.
- There is room for improvement - other logging, caching features, th additional side effects.
- Changing constructions, syntax, using classes with higher performance, proposed by new versions of the language,
runtime. For example, instead of or along withStringorArray, useStringSegment,StringValues,Segment,Pathstring,ArrayBuilderSegment<T>,Arraybuilder. Inventing a new algorithm.
For example:.\runtime\src\libraries\System.IO.Hashing\src\System\IO\Hashing**XxHash64.cs
based on xxhash_spec.md.\runtime\src\libraries\System.Private.CoreLib\src\System\SpanHelpers.Char.cs
based onhttp://www.0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simdAlgorithm 1: Generic SIMD by Wojciech Mula
General remarks
- I met the judgement that a method with multiple
ifbranches maybe is a candidate to refactoring. Then why are these methods a quite big? EventSource contains more than
4500lines even without comments. Does this exactly meet the requirement of single responsibility?- I have questions after I have glanced over an article class-too-large.html on the Martin Fowler’ site that described a refactirng experience.
The author presented herself as a teacher and consultant with 20 years of software development experience. If she knew so well who said what about refactoring principles, why did she make a mess of her library? Maybe she didn’t even know about SOLID principles before coding? Then why her article end up on the Fowler’s site? Why did he pick her article out of hundreds, maybe thousands of others? It doesn’t look like she was a newbie at the time of writing. Could not she figure out without some wise advices like “Make the change easy, then make the change easy”?