The SOLID principles have been created as pillars of creating flexible, understandable and maintainable code. They can add days onto your dev time to implement them properly, and most people don't care or worry much about code quality, so I created some better ones. The principles have been created as strong, secure pillars of architecting terrible code. DILOS I personally have implemented the principles for creating messy, obfuscated and bloated code. Let's introduce them: DILOS DILOS stands for: — Dependency Inversion inverted principle D — Interface bundling principle I — Liskov removal principle L — Open closed principle O — Several responsibilities principle S Dependency-Inversion inverted principle High level modules must depend on low level modules. Depend on concretions not abstractions. To abstract something away means to hide away the implementation details inside something, sometimes a prototype, sometimes a function. So when you call the function you don't have to understand exactly what it is doing. If you had to understand every single function in a big codebase you would never code anything. It would take months to finish reading. Here, we want to flip that. Don't abstract anything away. This means do as little as possible in smaller modular functions and do it all in one monolithic function. Make the person who calls into your function understand every single line of what you are doing if they want to use your work. Here's an example of clean code: { } hitAPI( , ); hitAPI( , ); ( ) function hitAPI url, httpMethods // Implementation example "https://www.kealanparr.com/retrieveData" "GET" "https://www.kealanparr.com/retrieveInitialData" "GET" Can you see how you don't have to worry about what does? We just pass a URL and a HTTP request and it's dealt with. hitAPI Now this is highly re-usable, and maintainable. This function can deal with all the different URL's in one place. We have done our best to let high level functions (functions we might put in a base prototype to share with lots of place below it) not depend on any low level functions. So let's invert the Dependency-Inversion principle How about the below? { ( initialLoad) { } ( navBar) { } { } } ( ) function hitDifferentAPI type, httpMethods if this instanceof // Implementation example else if this instanceof // Implementation example else // Implementation example We now have made our high level api request rely on lots of lower level type's. Mission accomplished, it's no longer cleanly generic & depends on types lower in it's inheritance chain. Interface bundling principle Clients should not be forced to depend upon [code] that they do not use. Interfaces in other languages are used to define method's and properties that different objects will have. Here what the principle is saying, is don't add code to objects it doesn't need. Don't bundle too much un-related functionality together. Which is total nonsense. We want to ensure we continually bundle loosely related code paths together all in one place. Essentially, depend on things you don't even need. We talk more about this later in the but remember this principle, and allow it to extend further and influence everything. Have you ever spent hours looking through hundreds of files trying to find your bug? Not anymore. Have one JS file called and put all of your code in there. Several responsibilities principle main.js Make your initial site load slower, by loading everything up-front, rather than lazily loading JS scripts as and when you need. Code for things you might need later down the line now, just in-case you do need them. If someone asks for a banana in your code, give them a gorilla holding a banana. Always over-deliver what the client needs, they will thank you for it. Do your best to keep your functions as few as possible. Do you think this might fit better by encapsulating this in a new function elsewhere and abstracting the logic away? No. Don't make this more confusing than it has to be. Just copy and paste the code where you need it. We ideally would only have 1 object for our code flow. In very, very big codebases we might have 2 objects. It's very often called the anti-pattern, where one object has to be used everywhere as it does much, but we'll talk more about that later. God object too Liskov segregation principle Build software out of parts where the children can't be swapped for the parents. A definite red flag here would be that you're even using inheritance in your code. Make sure you are copy-pasting the code instead of inheriting. This is explained beautifully by the anti-pattern, where you shouldn't be abstracting away the common features of your code into modular, re-usable functions but duplicating the code anywhere you need it. This will increase technical debt (code you have to go back and fix properly ) and ensure changing one piece of code, requires multiple searches to find every place it is used in the codebase. Copy-Paste later DRY code means on't epeat ourself. WET code is the opposite, and we rite verything wice. Multiple times if necessary. Fear inheritance and copy-paste as necessary. D R Y W E T But if you do need to make use of the , ensure object's prototypes lower in the inheritance chain (children) when swapped with something higher in their inheritance chain (parents) should not work as expected. Liskov segregation principle Why? Because if we don't follow the then we are starting to build accurate, robust inheritance chains. abstracting away logic away into encapsulated base prototypes/objects. We also are beginning to logically group the different methods in the prototype chain and their particular overrides making code paths more expected and discoverable. Liskov-segregation principle If you have accurately followed this principle, due to children not being usable where a parent is, you have completely made inheritance useless anyway. If your program blows up when trying to reference functions that don't exist in their children- you have completely killed any benefit inheritance would have given you - which is exactly our goal with this principle. Open closed principle Objects should be open for modification, but closed for extension. Good code normally extends object's code, to limit modifying a base prototype. So that the object that has done the extension can deal with it's own state and what new functionality it needs to do (deal with the little changes only the child needs to do.) This is nonsense, and what we really should be aiming for is: Open for modification— to make any changes, we have to change the base prototype/function. Closed for extension— if you extend, you are starting to modularise the code, stop and make sure is done in a base prototype/function. everything The above two steps will also promote heavy if branching as you deal with every scenario. So you end up with something like: { (animal == ) { ; } (animal == ) { ; } (animal == ) { ; } (animal == ) { ; } (animal == ) { ; } (animal == ) { ; } (animal == ) { ; } (animal == ) { ; } (animal == ) { ; } (animal == ) { ; } { ; } } ( ) function makeSound animal if "dog" return "bark" else if "duck" return "quack" else if "cat" return "meow" else if "crow" return "caw" else if "sheep" return "baa" else if "cow" return "moo" else if "pig" return "oink" else if "horse" return "neigh" else if "chicken" return "cluck" else if "owl" return "twit-twoo" else /// It has to be a human at this point return "hi" Now if you need to change something you just simply add another check. if This ties into the several responsibilities principle you will learn more about below, but the main thing is, have everything in a base function/prototype. This will help you promote the anti-pattern, where by changing the base function/prototype you end up with bugs in the other touch points where this function is called. Fragile Base Class For example, lets say human should no longer fall into the else, and you add the new animal wolf you will introduce bugs (unless you update the place where you're expecting human to be logged). Several responsibilities principle Ensure that your functions/objects have multiple responsibilities. Good coders too often separate out their code into multiple different objects or modules. My problem with this, is that it is confusing. I can't remember what they all do. Here's an example: godObject = { : {}, : {}, : {}, : {}, : {} }; const handleClicks ( ) function getUserName ( ) function handleLogin ( ) function logTransactionId ( ) function initialSiteLoad ( ) function is responsible for so many aspect of the site. Payments, log in, site load, logging transaction id's and all click functionality on the site. Great. If you have a bug, you know it can only be here. godObject Make sure everywhere in your codebase needs access to . Make it do everything. godObject What we really want in the code is (ensuring lots of parts of our system depend on each other) and (we puts lots of random bits and pieces together). high coupling low cohesion This anti-pattern is sometimes called the because you only really need it as scissors to cut something, but it also can be a nail file, saw, pair of tweezers, bottle opener and be a cork screw too. Swiss Army Knife What I am re-iterating over and over again here, is to keep everything together and bundle, bundle, bundle. Conclusion I hope this has eloquently described how software should be written to maximise time lost debugging, frustration and piling on technical debt. I post my articles on if you want to keep up to date with my writing. Twitter