In recent years SOLID has replaced Design Patterns as the number one answer to "what should I be studying to learn software design?" Surprisingly, SOLID isn't one thing. It's simply an acronym grouping five different things. They're actually all pretty simple when you strip away the mystique. But there's a lot of mystique.
SOLID is older than Design Patterns, making it an odd choice as the next new thing. I mean, the five parts are older; but naming them S, O, L, I and D together as a word -- that part is newer. So the question is, if you release an album with a mix of Perry Como and Elvis songs, does it count as new?
Another odd thing is, the same as Design Patterns, SOLID is about Object Oriented programming. There's nothing wrong with that, but the all-OOP-all-the-time style is seen as awkward these days. So why is the most popular general advice about it?
These are also old enough that people argue about what they really mean. There's what they first meant. There's often an updated definition. Sometimes people have agreed on a new meaning that's just plain different. Computer terms don't usually have multiple meanings, so that's also odd.
Last, and maybe this may be nicky-picky, but "SOLID" as a mnemonic is odd. Computer people like to use fun names like stream or thread or zombie. Sure, we have the cool-sounding "RAID", but that's a real phrase for a single concept (Redundant Array of Inexpensive Disks). Actively trying to make a forceful word like "SOLID" is odd.
Since these are all about OOP, lets get a modern review of that. First is encapsulation and interfaces. That's the fancy way to say "use private variables and make outsiders call functions". A class should feel like a built-in type that does what the public functions say it does. Number two is how inheritance enables polymorphism: if you want several types which can mix∓match with either other, create them as subclasses of a common base class. Then third is the idea of an abstract interface. Inheriting from a class is two things: you get stuff from it, and you're required to have all of the interface functions. Often you get them all and may override some, but an abstract base class is where you get nothing -- you have to write all the required functions. You still get polymorphism, and don't have to deal with how the base class implements things if you don't want to.
That's just very basic introductory OOP.
Now onto the five things in SOLID.
The O: this means to write subclasses. It stands for "Open/Closed principle" which is "objects should be closed for modification but open for extension". That means you write a class, then, when you want to make an alternate version, create a subclass and override a few functions. That's one of the things subclasses are for, so, "O" says to write subclasses.
You might wonder, why call it Open/Closed? Back then people didn't just automatically know how to use subclassing. It was this new thing and Open/Close was a stab at describing it. Before OOP we'd make an Animal class with an animalType where 0=cat, 1=dog and so on. In the places where Cats did something different, our functions used "if animalType=0". To add the Pig animal, we grew the animal class -- we said animalType=2 is for Pigs and added Pig IF's as needed. That was normal programming, and it mostly worked fine.
But it turns out that adding to existing code is more trouble than you think. When we add Pig it seems like we just have to test the new stuff -- Pigs. But since we mucked around where the Cats and Dogs are, we have to retest those as well. We may have broken them by mistake. This is true in general. If we rewrite a normal function to add a new feature, we'll have to also retest everything it did before. This is standard programmer wisdom -- don't assume adding a few lines to old code will be fast and safe.
Back to that funny Open/Closed description -- it was aimed at old programmers. "Objects should be closed to modification" was telling them what they knew -- it sucks make changes to tested, working code. But you have to do it, right? That's when we hit them with "and open to extensions". Whoa! Extensions? How do I use them?
But today, "open for extension" is just an awkward way to say "make subclasses".
The S: this means to not make classes too big. Technically it stands for "single responsibility principle", which means to only have one responsibility. But no one can agree on what one responsibility means -- how big is a "responsibility"? Recently the person who made it up way back said it wasn't even about doing one thing -- it's about business logic in one place and the visual part in another, things like that. But today that's normal -- of course we seperate the Model from the View.
The "D": this stands for "Dependency Inversion". It means to make classes with private variables. Technically it says to use your class's public interfaces and not to look at the details, which is the same thing. An alternate version says to also make sure your base class is fully abstract. But that's still just standard OOP.
From the funny name, you can probably tell this is another one that made more sense way back. In the old days, because computers were small and slow, programming was all about being efficient. You had to know all of the details of how all your data was laid-out. Today we purposely hide that, so it's like the opposite, see? And Inversion is another word for opposite, so "Dependancy Inversion".
The "I": this stands for "Interface Segregation Principle". It says not to make your interfaces too big. In details it says if you have a big multi-user interface, split that into smaller ones where each user has one that does everything they need. But that's the same as saying not to make your interfaces too big.
Common internet examples of ISP violations are functions you'll always need to supply with dummy values. For example, an animal creation function requiring fur length, feather type, and frequency of shedding skin -- no one animal has them all. Maybe it's better to have makeBird, makeLizard and so on. That's what internet examples are like. I'm not sure they're the best.
The "L": this is the most specific one. Here's the set-up: subclasses give you polymorphism:
Button b1; could be pointing to any type of button subclass. Now suppose we call
b1.placeButton(x,y). Does the current subclass use x,y as the center, or as the upper-left corner? What does it do if the button would hang off the edge -- force it inside, shrink it, let it go?
"L" says to make sure every subclass is consistant with the way it does things -- same button corner, same rules for off-screen placement. Or a simpler example, you can't have Cats give their weight in ounces and Dog's in Kilos.
The official name is Liskov Substitution Principle. The description is very technical. It's from software engineering conferences in the 80's, when we were inventing Object Orient rules, so used lots of older math-sounding terms.
The internet only has one example of "LSP", and it's a weird one: a Rectangle class with a Square subclass. You can change the base rectangle's width and height; but in the square subclass, changing one has to automatically change the other. That's inconsistant, I suppose. But it's actually a classic example of why real-world rules ("a square is a type of rectangle") are bad to use when making classes.
To sum up: "D" means to use private variables, "I" and "S" mean to not make classes too big, "O" means to make subclasses, and "L" means all subclasses should follow the same rules. All-in-all, they're about how to do basic OOP.
In theory, these are useful today as a way to learn basic OOP. But they were never for that. Way back they were aimed at experienced programmers, doing things in a late '70's way, to motivate them into OOP. Now it's easier to read about encapsulation, then polymorphism through inheritance, and so on.
The other thing they could be good for is as reminders once you know OOP. But once you know it, do you need those reminders? Do you really need to remember to make variables private and to make a pubic interface? Making classes the right size is tricky, but how much good are the reminders "be sure to segregate them" and "don't make them do two completely different things"? I mean, if someone mutters to themselves "OK -- 3 second rule", do you think they're a good driver?
SOLID may have been great at convincing older programmers to think in terms of objects. At the time, ISP may have made lots of people think "OMG! I too have a giant interface in my code! Thanks!" I don't know. But that's what it was for. Today you'll have people telling you to read SOLID, or that you're violating LSP or something. They either really like history, or are being weird, or both. Or they heard about SOLID, tried to figure it out, and don't want to think it was a waste of time. If they were really trying to help you they'd use modern words.
Comments. or email adminATtaxesforcatses.com