Hot answers tagged

195

S = Single Responsibility Principle So I'd expect to see a well organised folder/file structure & Object Hierarchy. Each class/piece of functionality should be named that its functionality is very obvious, and it should only contain logic to perform that task. If you saw huge manager classes with thousand of lines of code, that would be a sign that ...


195

Basically we want things to behave sensibly. Consider the following problem: I am given a group of rectangles and I want to increase their area by 10%. So what I do is I set the length of the rectangle to 1.1 times what it was before. public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles) { foreach(var rectangle in ...


137

final expresses intent. It tells the user of a class, method or variable "This element is not supposed to change, and if you want to change it, you haven't understood the existing design." This is important because program architecture would be really, really hard if you had to anticipate that every class and every method you ever write might be changed to ...


122

Gosh, there are some weird misconceptions on what OCP and LSP and some are due to mismatch of some terminologies and confusing examples. Both principles are only the "same thing" if you implement them the same way. Patterns usually follow the principles in one way or another with few exceptions. The differences will be explained further down but first let ...


117

One way to wrap your head around this is to imagine potential requirements changes in future projects and ask yourself what you will need to do to make them happen. For example: New business requirement: Users located in California get a special discount. Example of "good" change: I need to modify code in a class that computes discounts. Example ...


104

These guidelines are a compass, not a map. They point you in a sensible direction. But they can't really tell you in absolute terms which solution is “best”. At some point, you need to stop walking into the direction your compass is pointing, because you have arrived at your destination. Clean Code encourages you to divide your code into very small, obvious ...


104

Now, to build a simple file saving application you have a class to check if the file already exists, a class to write the metadata, a class to abstract away DateTime.Now so you can inject times for unit testing, interfaces for every file containing logic, files to contain unit tests for each class out there, and one or more files to add everything to your DI ...


96

Classes should do 1 thing and do it well Yes, that is generally a good approach. but from the other hand they should represent real object we work with. No, that is a IMHO common misunderstanding. A good beginner's access to OOP is often "start with objects representing things from the real world", that is true. However, you should not stop with ...


92

In many cartoons or other media, the forces of good and evil are often illustrated by an angel and a demon sitting on the character's shoulders. In our story here, instead of good and evil, we have SOLID on one shoulder, and YAGNI (You ain't gonna need it!) sitting on the other. SOLID principles taken to the max are best suited for huge, complex, ultra-...


83

Your observation is correct, the SOLID principles are IMHO made with reusable libraries or framework code in mind. When you just follow all of them blindly, without asking if it makes sense or not, you are risking to overgeneralize and invest a lot more effort into your system than probably necessary. This is a trade-off, and it needs some experience to ...


77

Practically speaking, responsibilities are bounded by those things that are likely to change. Thus, there's no scientific or formulaic way to arrive at what constitutes a responsibility, unfortunately. It's a judgement call. It's about what, in your experience, is likely to change. We tend to apply the language of the principle in a hyperbolic, literal, ...


61

The ideal number of arguments for a function is zero (niladic) No! The ideal number of arguments for a function is one. If it's zero, then you are guaranteeing that the function has to access external information to be able to perform an action. "Uncle" Bob got this one very wrong. Regarding your code, your first example only has two lines in the block ...


60

It avoids the Fragile Base Class Problem. Every class comes with a set of implicit or explicit guarantees and invariants. The Liskov Substitution Principle mandates that all subtypes of that class must also provide all these guarantees. However, it is really easy to violate this if we don't use final. For example, let's have a password checker: public class ...


57

Modularity. Any decent language will give you the means to glue together pieces of code, but there's no general way to unglue a large piece of code without the programmer performing surgery on the source. By jamming a lot of tasks into one code construct, you rob yourself and others of the opportunity to combine its pieces in other ways, and introduce ...


53

The key here is scope, or, if you prefer, granularity. A part of functionality represented by a class can be further separated into parts of functionality, each part being a method. Here's an example. Imagine you need to create a CSV from a sequence. If you want to be compliant with RFC 4180, it would take quite some time to implement the algorithm and ...


50

This is not a God object. It seems like it is because there is so much here, but, in a way, it's doing nothing at all. There is no behavior code here. This isn't an omnipotent God that does everything. It just finds everything. It's less a true object at all and more of a data structure. This pattern has a more proper name: Service Locator. It strongly ...


49

From my experience, when writing an app, you have three choices: Write code solely to fulfil the requirements, Write generic code that anticipates future requirements, as well as fulfilling the current requirements, Write code that only fulfils the current requirements, but in a way that's easy to change later to meet other needs. In the first case, it's ...


43

Doc Brown is spot-on: classes don’t need to represent real-world objects. They just need to be useful. Classes are fundamentally merely additional types, and what does int or string correspond to in the real world? They are abstract descriptions, not concrete, tangible things. That said, your case is special. According to your description: And if ...


42

Yes This is the whole point of the term "cross-cutting concern" - it means something that does not fit neatly in the SOLID principle. This is where idealism meets up with reality. People semi-new to SOLID and cross-cutting often run into this mental challenge. It's OK, don't freak out. Strive to put everything into terms of SOLID, but there are a few ...


41

No. SOLID exists as guidelines to account for inevitable change. Are you really never going to change your logging library, or target, or filtering, or formatting, or...? Are you really not going to change your caching library, or target, or strategy, or scoping, or...? Of course you are. At the very least, you're going to want to mock these things in a ...


40

A user is someone who is registered and able to use the system. A chat room is a place people can chat. What happens when a user joins a chat room? What is that thing that represents a user who has joined a chat room? That is the abstraction you are missing. Other answers are hinting at this. You could say a user participates in a chat. You need a class that ...


38

But isn't the problem here caused by having Circle be the subtype of an Ellipse? Couldn't we reverse the relationship? The problem with this (and the square/rectangle problem) is falsely assuming a relationship in one domain (geometry) holds in another (behaviour) A circle and ellipse are related if you are viewing them through the prism of geometrical ...


36

I am just designing my application and I am not sure if I understand SOLID and OOP correctly. Been at this over 20 years and I'm not sure either. Classes should do 1 thing and do it well Hard to go wrong here. they should represent real objects we work with. Oh really? Let me introduce you to the single most popular and successful class of all ...


35

I'll go through your points numerically, but first, there's something you should be very careful of: don't conflate how a consumer uses a library with how the library is implemented. Good examples of this are Entity Framework (which you yourself cite as a good library) and ASP.NET's MVC. Both of these do an awful lot under the hood with, for example, ...


35

The classic example of square not being able to substitute for rectangle without violating LSP is a bit of a "trick question" and sophistic. The problem arises because of a conflation... i.e. an implementation of a rectangle is not really a rectangle. Having independently settable width and height is not an inherent property of a rectangle. A rectangle is ...


33

I'm surprised that no one has yet mentioned Effective Java, 2nd Edition by Joshua Bloch (which should be required reading for every Java developer at least). Item 17 in the book discusses this in detail, and is titled: "Design and document for inheritance or else prohibit it". I won't repeat all the good advice in the book, but these particular paragraphs ...


32

Now there is a class Stack that provides functionalities such as push(), pop(), peek() or top(), and to implement these methods it extends the LinkedList class methods. Is this a violation of Liskov Substitution Principle? No. It is perfectly fine to add methods in a subtype. For example, consider the case add_after() to add a node at the nth position of ...


32

The single responsibility might not be something that a single function can fulfill. class Location { public int getX() { return x; } public int getY() { return y; } } This class may break the single responsibility principle. Not because it has two functions, but if the code for getX() and getY() have to satisfy ...


31

[Note: I'm going to be talking about objects here. Objects is what object-oriented programming is about, after all, not classes.] What the responsibility of an object is depends mostly on your domain model. There are usually many ways to model the same domain, and you will choose one way or the other based on how the system is going to be used. As we all ...


31

There is absolutely nothing wrong with passing an entire User object as a parameter. In fact, it might help clarify your code, and make it more obvious to programmers what a method takes if the method signature requires a User. Passing simple data types is nice, until they mean something other than what they are. Consider this example: public class Foo { ...


Only top voted, non community-wiki answers of a minimum length are eligible