SOLID principles are key in object-oriented programming. But what does each principle actually mean, and why are they significant? 𝗦𝗢𝗟𝗜𝗗 𝗿𝗲𝗽𝗿𝗲𝘀𝗲𝗻𝘁𝘀 𝗳𝗶𝘃𝗲 𝗽𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲𝘀 𝗼𝗳 𝗼𝗯𝗷𝗲𝗰𝘁-𝗼𝗿𝗶𝗲𝗻𝘁𝗲𝗱 𝗽𝗿𝗼𝗴𝗿𝗮𝗺𝗺𝗶𝗻𝗴. Whether or not you use OOP, 𝗸𝗻𝗼𝘄𝗶𝗻𝗴 𝘁𝗵𝗲𝘀𝗲 𝗽𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲𝘀 𝗴𝗶𝘃𝗲𝘀 𝘆𝗼𝘂 𝗮 𝗹𝗲𝗻𝘀 𝗶𝗻𝘁𝗼 𝘁𝗵𝗲 𝗳𝗼𝘂𝗻𝗱𝗮𝘁𝗶𝗼𝗻𝘀 𝗼𝗳 𝗰𝗹𝗲𝗮𝗻 𝗰𝗼𝗱𝗲 which can be applied to many areas of programming. 𝗦 — Single Responsibility Principle 𝗢 — Open/Closed Principle 𝗟 — Liskov Substitution Principle 𝗜 — Interface Segregation Principle 𝗗 — Dependency Inversion Principle Let’s break down each principle ↓ 𝟭. 𝗦𝗶𝗻𝗴𝗹𝗲 𝗥𝗲𝘀𝗽𝗼𝗻𝘀𝗶𝗯𝗶𝗹𝗶𝘁𝘆 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗦𝗥𝗣) Each unit of code should only have one job or responsibility. A unit can be a class, module, function, or component. This keeps code modular and removes the risk of tight coupling. 𝟮. 𝗢𝗽𝗲𝗻-𝗖𝗹𝗼𝘀𝗲𝗱 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗢𝗖𝗣) Units of code should be open for extension but closed for modification. You should be able to extend functionality with additional code rather than modifying existing ones. This principle can be applied to component-based systems such as a React frontend. 𝟯. 𝗟𝗶𝘀𝗸𝗼𝘃 𝗦𝘂𝗯𝘀𝘁𝗶𝘁𝘂𝘁𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗟𝗦𝗣) You should be able to substitute a subclass with its base class. In other words, all functionality in the base class should be utilized by all of its subclasses. If it can’t, it shouldn’t be in the base class. An example of this is with a Bird base class. You might assume that it should have a fly method. But what about the birds that can’t fly? Like a Penguin. In this example, fly should not be in the base class as it does not apply to all subclasses. 𝟰. 𝗜𝗻𝘁𝗲𝗿𝗳𝗮𝗰𝗲 𝗦𝗲𝗴𝗿𝗲𝗴𝗮𝘁𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗜𝗦𝗣) Provide multiple interfaces with specific responsibilities rather than a small set of general-purpose interfaces. Clients shouldn’t need to know about the methods & properties that don't relate to their use case. Complexity ↓ Code flexibility ↑ 𝟱. 𝗗𝗲𝗽𝗲𝗻𝗱𝗲𝗻𝗰𝘆 𝗜𝗻𝘃𝗲𝗿𝘀𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗗𝗜𝗣) You should depend on abstractions, not on concrete classes. Use abstractions to decouple dependencies between different parts of the systems. Direct calls between units of code shouldn’t be done, instead interfaces or abstractions should be used. —— Want more engineering insights like this? Subscribe to our 𝗳𝗿𝗲𝗲 𝗻𝗲𝘄𝘀𝗹𝗲𝘁𝘁𝗲𝗿 for a 𝘄𝗲𝗲𝗸𝗹𝘆 𝗱𝗲𝗲𝗽-𝗱𝗶𝘃𝗲 and roundup of our best content: blog.levelupcoding.co #softwareengineering #webdevelopment #programming
Software Engineering Principles
Explore top LinkedIn content from expert professionals.
-
-
What are the SOLID principles? 🤔 As a .NET developer, I'm always looking for ways to improve the quality and maintainability of my code. I want to share my experiences using the SOLID principles and how they've helped me create better code. First, let's define what we mean by SOLID. The acronym 𝗦𝗢𝗟𝗜𝗗 stands for: - Single responsibility principle - Open/closed principle - Liskov substitution principle - Interface segregation principle - Dependency inversion principle Let's break them down. 🔬 1. 𝗦𝗶𝗻𝗴𝗹𝗲 𝗥𝗲𝘀𝗽𝗼𝗻𝘀𝗶𝗯𝗶𝗹𝗶𝘁𝘆 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗦𝗥𝗣) A class should have only one reason to change. In other words, a class should have a single, well-defined responsibility. That class should entirely encapsulate responsibility. 2. 𝗢𝗽𝗲𝗻/𝗖𝗹𝗼𝘀𝗲𝗱 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗢𝗖𝗣) Software entities (classes, functions, etc.) should be open for extension but closed for modification. You should be able to add new functionality to a class without changing its existing code, but you should not need to modify the class itself to do so. 3. 𝗟𝗶𝘀𝗸𝗼𝘃 𝗦𝘂𝗯𝘀𝘁𝗶𝘁𝘂𝘁𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗟𝗦𝗣) Subtypes must be substitutable for their base types. In other words, if a class is derived from another class, you should be able to use the derived class in the same way as the base class without any issues. 4. 𝗜𝗻𝘁𝗲𝗿𝗳𝗮𝗰𝗲 𝗦𝗲𝗴𝗿𝗲𝗴𝗮𝘁𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗜𝗦𝗣) Clients should not depend on interfaces they do not use. This means you should design your interfaces as specific and focused as possible. 5. 𝗗𝗲𝗽𝗲𝗻𝗱𝗲𝗻𝗰𝘆 𝗜𝗻𝘃𝗲𝗿𝘀𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗗𝗜𝗣) High-level modules should not depend on low-level modules. Both should depend on abstractions. Design your software so high-level modules depend on abstractions rather than concrete implementations. I struggled with creating code that was easy to understand and maintain, but the SOLID principles provided a clear set of guidelines to follow when designing software. One of the first principles I focused on was SRP. It encourages developers to design classes with a single, well-defined responsibility and to keep the code for that responsibility entirely encapsulated within the class. This makes it easier to understand a class's purpose and change its behavior without affecting other parts of the system. Imagine a class doing a few things, like performing calculations and interacting with the database. We could refactor the class to have a single responsibility of calculating the result and create separate classes for interacting with the database. This would make the code easier to understand and maintain. Hope that was helpful. :) P.S. If you enjoyed this post, repost it ♻️ to share it with your audience.
-
"How to think about agentic engineering autonomy" My latest free deep-dive article: https://lnkd.in/gtUdF-Xx ✏️ The frontier of software development is shifting: the action has changed from prompting to operating. We are stepping into a new era of software factories, background sessions, subagents, and manager agents. But as we scale these capabilities, how do we accurately measure trust and risk? A single-axis ladder is no longer enough to capture multi-agent skill. Most autonomy debates conflate two very different questions: - How far away from ourselves are we letting a single agent go? (Agency) - What is our skill at coordinating many agents? (Orchestration) In my latest piece, I introduce a working model of autonomy for agentic engineering, breaking down this shift into 6 distinct levels: Level 0: Assist - The agent makes suggestions; you always decide. Level 1: Supervised action - The agent edits or runs commands, asking for your approval first. Level 2: Scoped task delegation - You hand off a bounded task with clear constraints and a definition of "done." Level 3: Goal-driven autonomy - The agent cycles through plan ➔ act ➔ test ➔ review until success criteria are met. Level 4: Parallel delegation - work is sliced across many isolated agents running simultaneously. Level 5: Managed-by-exception orchestration - A manager agent runs a continuous factory, dispatching and verifying work - humans only step in when things fail. The forward posture for an engineering team isn't going to be blind delegation but will be calibrated autonomy. We simply cannot build agents we can't answer for. The level of autonomy we grant must follow our verification processes, not the task name. Ultimately, risk and reversibility set the ceiling. Read the full article to explore the four autonomy anti-patterns to avoid, the metrics that make the leap of faith more reliable and how to safely climb the rungs. #ai #programming #softwareengineering
-
In 1986, a programmer at Ericsson took on the hardest requirement in software: telephone switches that are never allowed to stop. No maintenance windows. No downtime. Ever. Joe Armstrong's answer sounded like surrender: let it crash. Instead of writing code that defends against every conceivable error, he built a system where processes are tiny, isolated, and expected to die. When one crashes, a supervisor restarts it in a known-good state. Error handling lives one level up from the code doing the work, where failure can actually be reasoned about. The language he co-created around this idea was Erlang. Ericsson's AXD301 switch, running on it, reported nine nines of availability. That is 31 milliseconds of downtime per year. Then, in 1998, Ericsson banned Erlang for new products. Corporate policy favored mainstream languages. The team got it open-sourced on the way out the door. Sixteen years later, WhatsApp was running messaging for 450 million people on Erlang, with roughly 35 engineers, when Facebook paid $19 billion for it. Supervision trees, circuit breakers, crash-only design: every resilience pattern your platform team debates today is downstream of one man deciding to treat failure as the normal case and design for it. The most reliable systems ever built were written by people who assumed their code would fail.
-
Code is the product. How do you prevent a 1M+ LoC Python library, built by thousands of contributors, from collapsing under its own weight? In transformers, we do it with a set of explicit software engineering tenets. With Pablo Montalvo, Lysandre Debut, Pedro Cuenca and Yoni Gozlan, we just published a deep dive on the principles that keep our codebase hackable at scale. What’s inside: – The Tenets We Enforce: From One Model, One File to Standardize, Don't Abstract, these are the rules that guide every PR. – "Modular Transformers": How we used visible inheritance to cut our effective maintenance surface by ~15× while keeping modeling code readable from top to bottom. – Pluggable Performance: A standard attention interface and config-driven tensor parallelism mean semantics stay in the model while speed (FlashAttention, community kernels, TP sharding) is a configurable add-on, not a code rewrite. This matters for anyone shipping models, contributing to OSS, or managing large-scale engineering projects. It’s how we ensure a contribution to transformers is immediately reusable across the ecosystem (vLLM, ggml, SGLang, etc.). Read more on the Hugging Face blog
-
The 10 Rules NASA Swears By to Write Bulletproof Code: 0. Restrict to simple control flow ↳ No goto, setjmp, longjmp, or recursion. Keep it linear and predictable. This ensures your code is easily verifiable and avoids infinite loops or unpredictable behavior. 1. Fixed loop bounds ↳ Every loop must have a statically provable upper bound. No infinite loops unless explicitly required (e.g., schedulers). This prevents runaway code and ensures bounded execution. 2. No dynamic memory allocation after initilization ↳ Say goodbye to malloc and free. Use pre-allocated memory only. This eliminates memory leaks, fragmentation, and unpredictable behavior. 3. Keep functions short ↳ No function should exceed 60 lines. Each function should be a single, logical unit that’s easy to understand and verify. 4. Assertion density: 2 per function ↳ Use assertions to catch anomalous conditions. They must be side-effect-free and trigger explicit recovery actions. This is your safety net for unexpected errors. 5. Declare data at the smallest scope ↳ Minimize variable scope to prevent misuse and simplify debugging. This enforces data hiding and reduces the risk of corruption. 6. Check all function returns and parameters ↳ Never ignore return values or skip parameter validation. This ensures error propagation and prevents silent failures. 7. Limit the preprocessor ↳ Use the preprocessor only for includes and simple macros. Avoid token pasting, recursion, and excessive conditional compilation. Keep your code clear and analyzable. 8. Restrict pointer use ↳ No more than one level of dereferencing. No function pointers. This reduces complexity and makes your code easier to analyze. 9. Compile with all warnings enabled ↳ Your code must be compiled with zero warnings in the most pedantic settings. Use static analyzers daily to catch issues early. Some of these rules can be seen as hard to follow, but you can't allow room for error when lives are at stake. Which ones are you still applying? #softwareengineering #systemdesign ~~~ 👉🏻 Join 46,001+ software engineers getting curated system design deep dives, trends, and tools (it's free): ➔ https://lnkd.in/dCuS8YAt ~~~ If you found this valuable: 👨🏼💻 Follow Alexandre Zajac 🔖 Bookmark this post for later ♻️ Repost to help someone in your network
-
SOLID Principles: The Bedrock of Clean, Maintainable Code As software engineers, we strive for code that's robust, flexible, and easy to maintain. Let's revisit SOLID principles - a set of guidelines that, when followed, lead to better software design. Let's break them down: 𝗦 - 𝗦𝗶𝗻𝗴𝗹𝗲 𝗥𝗲𝘀𝗽𝗼𝗻𝘀𝗶𝗯𝗶𝗹𝗶𝘁𝘆 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 • Each class should have one, and only one, reason to change • Keep your code simple, focused, and easier to understand • Think: "Does this class do too much?" 𝗢 - 𝗢𝗽𝗲𝗻-𝗖𝗹𝗼𝘀𝗲𝗱 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 • Software entities should be open for extension, but closed for modification • Add new features without altering existing code • Use abstractions and polymorphism to achieve this 𝗟 - 𝗟𝗶𝘀𝗸𝗼𝘃 𝗦𝘂𝗯𝘀𝘁𝗶𝘁𝘂𝘁𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 • Derived classes must be substitutable for their base classes • Subclasses should extend, not replace, the behavior of the base class • Ensures different parts of your code can work together seamlessly 𝗜 - 𝗜𝗻𝘁𝗲𝗿𝗳𝗮𝗰𝗲 𝗦𝗲𝗴𝗿𝗲𝗴𝗮𝘁𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 • Many client-specific interfaces are better than one general-purpose interface • Keep interfaces focused and lean • Prevents classes from implementing methods they don't need 𝗗 - 𝗗𝗲𝗽𝗲𝗻𝗱𝗲𝗻𝗰𝘆 𝗜𝗻𝘃𝗲𝗿𝘀𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 • Depend on abstractions, not concretions • High-level modules shouldn't depend on low-level modules; both should depend on abstractions • Promotes flexibility and easier testing through decoupling Implementing SOLID principles might seem challenging at first, but the long-term benefits are substantial: • Increased code maintainability • Easier testing and debugging • Enhanced scalability and flexibility How have you applied SOLID principles in your projects? What challenges did you face, and how did you overcome them?
-
Using unverified container images, over-permissioning service accounts, postponing network policy implementation, skipping regular image scans and running everything on default namespaces…. What do all these have in common ? Bad cybersecurity practices! It’s best to always do this instead; 1. Only use verified images, and scan them for vulnerabilities before deploying them in a Kubernetes cluster. 2. Assign the least amount of privilege required. Use tools like Open Policy Agent (OPA) and Kubernetes' native RBAC policies to define and enforce strict access controls. Avoid using the cluster-admin role unless absolutely necessary. 3. Network Policies should be implemented from the start to limit which pods can communicate with one another. This can prevent unauthorized access and reduce the impact of a potential breach. 4. Automate regular image scanning using tools integrated into the CI/CD pipeline to ensure that images are always up-to-date and free of known vulnerabilities before being deployed. 5. Always organize workloads into namespaces based on their function, environment (e.g., dev, staging, production), or team ownership. This helps in managing resources, applying security policies, and isolating workloads effectively. PS: If necessary, you can ask me in the comment section specific questions on why these bad practices are a problem. #cybersecurity #informationsecurity #softwareengineering
-
AI is a huge boost for software development, but there are different form factors for AI dev tools. What types of tools are available? Following the famous autonomy levels in self driving, I created levels for AI-enhanced dev tools, w/ examples for each: https://lnkd.in/gpjf6qTd For self-driving, self-driving cars are categorized into six levels of autonomy, as defined by the Society of Automotive Engineers: https://lnkd.in/gq6Pj-fp These levels range from no automation at all (Level 0) to full automation (Level 5). What would these look like in software? Level 1 - Code Completion: These systems have been around for a long time, even before the advent of AI-driven features, but LLMs have made rapid progress. Representative examples are: * Github copilot: https://lnkd.in/gCVJ4yeC * Cursor code completion: https://www.cursor.com/ Level 2 - Partial Autonomy: Next are systems that can work together with programmers to handle more complex editing tasks. Examples include: * Github Copilot Chat: https://lnkd.in/gNF9VXNA * Codium: https://www.codium.ai/ * Aider: https://aider.chat/ Level 3 - Conditional Autonomy: These systems perform full software engineering tasks with little to no human supervision in limited contexts: * Unit Test Generation * Documentation Writing * Code Review * Commit Message Generation * Code Migration Level 4 - High Autonomy: These are systems able to solve a wide variety of software development tasks. These include code editing, but also all of the other tasks in level 3. Some example: * Devin: https://lnkd.in/gxZGyTuP * OpenDevin: https://lnkd.in/gr8dJNaX Level 5 - Full Autonomy: This level entails fully autonomous software development. Before automatic systems can be given this level of authority and power, it is necessary to both improve their overall accuracy, and ensure that we have safety guardrails in place. Hope this was helpful and we’re happy to have comments! If you’d be interested in helping push forward AI dev tools at the higher levels of autonomy, please try OpenDevin out and join our open source communtiy (https://lnkd.in/gT6amxrH), or apply to join us at All Hands AI (https://lnkd.in/guF2gaSH)!
-
Some organisations are drowning in technical debt. - A "5-minute fix" turns into 3 days of effort. - Adding new features feels like playing with a house of cards. - That "quick fix" from 2 years ago? Now it runs your entire business. - Every team meeting is a battle: Feature vs. Quality - Your team is getting slower by the month. - A tiny change takes weeks to test It doesn't have to be like this. And 𝗶𝘁'𝘀 𝗰𝗲𝗿𝘁𝗮𝗶𝗻𝗹𝘆 𝗻𝗼𝘁 𝘁𝗵𝗲 𝗱𝗲𝘃𝗲𝗹𝗼𝗽𝗲𝗿𝘀' 𝗳𝗮𝘂𝗹𝘁𝗅 Usually, it's the result of 𝗺𝗶𝘀𝗽𝗹𝗮𝗰𝗲𝗱 𝗽𝗿𝗶𝗼𝗿𝗶𝘁𝗶𝗲𝘀 and a misguided organizational development culture. Some root causes: - "Just make it work for the demo" - Fixing technical debt rarely gets priority - Immediate deadlines trump long-term code health - Leaders are rewarded for short-term results - Sales teams promising features without consulting engineering - Career advancement based on visible new features - Business leaders don't trust engineering time estimates - Engineers don't trust management's promises to "fix it later" Here are 5 clear, actionable recommendations: 1. Make system health a product feature, not just a technical problem. 2. Measure and demonstrate how technical debt is slowing down your business. 3. Include clean-up time in all feature estimates - no exceptions. 4. Never bypass quality checks, even under pressure. 5. Reward teams for preventing problems, not just fixing them. When technical health becomes part of your product strategy, your teams move faster, your systems stay reliable, and your business grows stronger. Best of all? Your developers come to work - excited to build great things instead of dreading the next fire. - proud of their work instead of apologizing for it. - energized to create instead of stressed about breaking things. "When did technical debt hit your organization the hardest? Share your story below - whether it's a horror story or a success story. 👇 P.S. In Sophie's and my forthcoming book, we share our experiences of how to develop good software sustainably. #devops #technology #qualit