Folks, if you think thousands of tests means one big run that breaks CI, you are actually doing it in a wrong way: I’ve seen teams panic, add more machines, and still wait hours for a green signal. The trick isn’t more raw compute, it’s smarter testing. What I do (practical, repeatable): 1. Decide what actually matters: Not every change needs a full E2E sweep. Smoke the critical paths on every push (login, payment, publish). Everything else runs later. 2. Shift left and move logic down the pyramid: Unit tests catch fast regressions. API/contract tests catch integration problems. Keep E2E lean and focused on user journeys that can’t be covered anywhere else. 3. Shard intelligently: Split suites into shards of manageable size (500–1,000 tests per shard is a good starting point). Run shards in parallel across workers. Don’t blast thousands of browsers per job, that just creates noise. 4. Use test impact / risk-based selection: If the change touched checkout code, run checkout + related integration tests. Save full-regression for nightly. Tools (or simple git-diff + mapping) cut the waste dramatically. 5. Be brutal about recordings & artifacts: Only capture video/screenshots on failures or when debugging a flaky. Turn off heavy artifacts for the normal run, they kill memory and IO. 6. Stabilize before you scale: Fix flakiness at the source: timeouts, stale locators, network mocks. A flaky test multiplied by 100 shards = chaos. 7. Make CI a scheduler, not an executor: Fast feedback (push): smoke + impacted tests. Medium feedback (merge): daily critical suite. Full feedback (nightly): complete regression. Align SLAs to business risk. Run less, run smart, run in parallel. Focus on high-value tests and let CI run the rest on a schedule. I’d rather get a meaningful 5-minute green than an irrelevant 3-hour “all-tests” pass. Follow Sahil kapoor for more !
How to Stabilize Fragile Codebases
Explore top LinkedIn content from expert professionals.
Summary
Stabilizing fragile codebases means making software systems easier to maintain and less prone to breaking, especially when changes are introduced or team members come and go. A fragile codebase is one that easily fails or becomes risky to update due to poor structure, lack of documentation, or unclear ownership.
- Prioritize clear documentation: Make sure system architecture, decisions, and operational knowledge are well-documented so everyone on the team can understand and safely update the code.
- Build with observability: Set up proper monitoring and logging so you can see what's happening in the system, spot bottlenecks, and prevent issues before they cause instability.
- Refactor complex logic: Simplify tangled code by breaking down large conditional statements and organizing rules into smaller, independent components, making changes less risky and easier to test.
-
-
After 10+ years of exposure in platform engineering, I have finally come to a conclusion. This is the number 1 problem of unstable system platforms: Applying fixes without understanding the root cause. You will probably see this happening in practice quite often: - patching performance issues without knowing baseline metrics - scaling infrastructure without understanding traffic patterns - adding redundancy without mapping failure points - deploying updates without a rollback strategy in place You understand the pattern: doing (system interventions) without (system visibility). Kind of like reinforcing walls while the foundation is still cracking. And all the instability problems stem from this lack of clarity. - how can you fix what you haven't properly measured? - why would your patches hold if you don't understand what's breaking them? - what will you optimize if you don't know where the bottlenecks actually are? But the fact is that the stability doesn't come from reacting faster. If you want stability, you need to start by building the right layers, one at a time. I suggest these 4 levels of platform stabilization tactics: 1. Always start from observability You can't stabilize what you can't see. Logs, metrics, and traces are not optional extras. They are the foundation on which everything else depends. 2. Build a reliability strategy Once you have visibility, define what 'stable' means for the system. This means setting SLOs, identifying critical failure paths, and deciding which risks are acceptable and which are not. 3. Choose stabilization tactics accordingly With a clear strategy, you can now act with intention. Circuit breakers, rate limiting, graceful degradation, blue green deployments. Each tactic must map directly to a risk you've identified. 4. Run Operations to sustain those tactics Focus on disciplined execution: runbooks, incident reviews, on-call rotations, and continuous iteration based on real system behavior. You need the right tooling, the right culture, and above all, clarity on what you're protecting.
-
Many systems fail long before the code stops working They fail when nobody understands them anymore A codebase can run perfectly in production but still be extremely fragile if all knowledge lives inside one developer’s head When that person leaves the team the system becomes a black box Every change feels risky Debugging takes longer New developers struggle to contribute Features slow down Confidence disappears This is why documentation is not optional in professional software engineering It is part of the system Good teams treat knowledge like shared infrastructure → Document architecture so developers understand how components interact → Explain why decisions were made not just what the code does → Write clear READMEs so new developers can onboard quickly → Maintain diagrams that show system boundaries and dependencies → Document APIs and contracts between services → Capture operational knowledge for debugging and incidents Documentation is not about writing essays It is about removing single points of failure in knowledge The most dangerous systems are not the ones with bugs They are the ones nobody understands well enough to safely change A strong engineering team builds software that multiple people can confidently maintain Not systems that depend on one hero developer Look at your current project If one key engineer disappeared tomorrow how difficult would it be for the team to maintain the system Share your experience below Follow Nelson Djalo for practical lessons that help developers build reliable and maintainable software systems #coding #programming #tech
-
Your code has too many if-else branches. Here is at least one way to fix it. I used to write methods with 10+ conditions stacked on top of each other. Discount rules, validation checks, and approval workflow, all crammed into one method. It worked. Until someone asked me to add a new rule. Every change meant touching the same fragile method. Every test covered an increasingly complex web of branches. Every PR review turned into "Can you also check edge case X?" Then I started using the Chain of Responsibility pattern. The idea is dead simple: → Break each condition into its own handler class → Link the handlers into a chain → Pass the request through the chain → Each handler either processes it or forwards it to the next one Here is what changed in my code: 𝗕𝗲𝗳𝗼𝗿𝗲: One method with nested if-else for every rule. 𝗔𝗳𝘁𝗲𝗿: Each rule is its own class. Adding a rule = adding a class. Zero changes to existing code. Where I use this pattern the most: • Validation pipelines - check format, then business rules, then permissions • Discount engines - VIP, regular, new customer, seasonal promos • Approval workflows - route requests through manager → director → VP based on thresholds The funny thing? If you have ever written ASP.NET Core middleware, you have already used this pattern. Every middleware component either handles the request or calls next(). That is Chain of Responsibility. 3 things to remember: 1. Always add a default handler at the end of the chain. Otherwise, unmatched requests silently disappear. 2. Keep each handler focused on one thing. The moment a handler does two checks, split it. 3. Start simple. If you have 2-3 stable conditions, if-else is fine. This pattern pays off when the rules grow. I wrote a full breakdown with C# code, a real-world validation example, and when to (and not to) use it. Read it here: https://lnkd.in/dvn5Kj9b __ 📌 Don't miss the next newsletter issue, 20,000 engineers will read it, join them: thecodeman.net ♻️ Repost to others. 📂 You can save this post for later, and you should do it. ➕ Follow me ( Stefan Đokić ) to learn .NET and Architecture every day.
-
🚀 Clean Code isn’t just about how it reads; it’s also about what it drags behind. Here's how to avoid "One line of code, ten tons of baggage" in your projects: 🔧 Use minimal dependencies Only add libraries when absolutely necessary. Every extra package increases the potential for bugs, conflicts, and maintenance overhead. 🛠️ Prefer standard libraries Modern programming languages offer powerful built-in tools. Relying on them boosts performance, portability, and reduces the risks associated with external libraries. 🔍 Audit dependencies regularly Utilize tools to check for outdated, insecure, or bloated packages. Clean up anything that’s unnecessary or risky to keep your code lean. 🚫 Avoid large libraries for small tasks Don't pull in massive libraries for a single function. For instance, use native map() or filter() instead of loading an entire utility library like lodash. 🧩 Modularize your code Break your code into small, self-contained units. This reduces dependencies and makes it easier to test and reuse. 🔒 Pin versions to ensure stability Lock dependency versions to avoid unexpected breaking changes when updating or deploying your project. 🧹 Clean up unused packages Regularly remove unused libraries to keep your codebase lightweight and secure. Tools like npm prune or pip uninstall are your friends. 🔍 Review each new dependency Before adding a new library, ask if it’s truly necessary. Consider the long-term cost in size, complexity, and maintenance. ⚙️ Automate updates carefully Leverage tools like Dependabot, but always review changes before accepting. Auto-updating without proper testing could break your code. Keep your codebase clean, lean, and secure! 💻✨ #CleanCode #SoftwareDevelopment #CodingBestPractices #TechTips #Programming #CodeQuality #DependencyManagement #DevTips #TechCommunity
-
🧠 𝗧𝗵𝗲 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲𝘀 𝗕𝗲𝗵𝗶𝗻𝗱 𝗦𝘂𝘀𝘁𝗮𝗶𝗻𝗮𝗯𝗹𝗲 𝗮𝗻𝗱 𝗦𝗰𝗮𝗹𝗮𝗯𝗹𝗲 𝗖𝗼𝗱𝗲 Writing code that works is just the beginning. As systems grow, the real challenge is to keep code understandable, testable, and maintainable, even years later. That’s where core programming principles come into play. 🔹 𝗦𝗢𝗟𝗜𝗗 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲𝘀 These five principles of object-oriented design help manage complexity as codebases scale. • Single Responsibility Principle A class should have only one reason to change. When a class handles multiple concerns, each change risks breaking unrelated logic. Focused responsibilities reduce fragility and improve clarity. • Open/Closed Principle Software should be open for extension, but closed for modification. Instead of altering existing code, we should extend it via abstraction. This protects stability while enabling growth. • Liskov Substitution Principle Subtypes must preserve the behavior of their base types. When this rule is violated, polymorphism breaks, and code becomes unpredictable. • Interface Segregation Principle Clients shouldn't be forced to depend on methods they don’t use. Prefer smaller, more focused interfaces to avoid bloated dependencies and unnecessary coupling. • Dependency Inversion Principle High-level modules should not depend on low-level ones. Both should depend on abstractions. This improves decoupling and allows components to evolve independently. 🔹 𝗞𝗜𝗦𝗦 (𝗞𝗲𝗲𝗽 𝗜𝘁 𝗦𝗶𝗺𝗽𝗹𝗲, 𝗦𝘁𝘂𝗽𝗶𝗱) Complexity is the enemy of maintainability. The simplest solution that solves the problem is usually the best. Simplicity leads to clarity, and clarity leads to fewer bugs. 🔹 𝗗𝗥𝗬 (𝗗𝗼𝗻’𝘁 𝗥𝗲𝗽𝗲𝗮𝘁 𝗬𝗼𝘂𝗿𝘀𝗲𝗹𝗳) Duplication increases maintenance costs and inconsistency. When a change is needed, every duplicated piece must be updated. Centralizing logic improves cohesion and reduces bugs. 🔹 𝗬𝗔𝗚𝗡𝗜 (𝗬𝗼𝘂 𝗔𝗿𝗲𝗻’𝘁 𝗚𝗼𝗻𝗻𝗮 𝗡𝗲𝗲𝗱 𝗜𝘁) Avoid building functionality based on speculation. Focus on current requirements. Overengineering wastes time, adds complexity, and often creates dead code. 🔹 𝗖𝗹𝗲𝗮𝗻 𝗖𝗼𝗱𝗲 Clean code is expressive. It uses meaningful names, small functions, consistent formatting, and minimal side effects. It favors readability over cleverness. The goal is to write code that everyone can easily understand and modify. 🔹 𝗦𝗲𝗽𝗮𝗿𝗮𝘁𝗶𝗼𝗻 𝗼𝗳 𝗖𝗼𝗻𝗰𝗲𝗿𝗻𝘀 Each part of the system should focus on a single aspect. For example, business logic, data access, and UI should be isolated. This makes systems easier to test, extend, and reason about. 🔹 𝗟𝗮𝘄 𝗼𝗳 𝗗𝗲𝗺𝗲𝘁𝗲𝗿 A component should only interact with its immediate collaborators. Don’t chain multiple method calls across different objects. This reduces coupling and protects against ripple effects of change.
-
I once looked at my early startup’s codebase and realised something uncomfortable… It wasn’t code. It was panic-driven typing disguised as progress. If you’ve ever hacked your way through a product deadline, you know this feeling. You move fast. You tape things together faster. And suddenly the whole system feels like a fragile Jenga tower held together by hope and coffee. The 6 rules I wish I had learned earlier, the ones that stop you from cleaning up your own chaos later. 1. Separation of Concerns When one function tries to do everything, it ends up doing nothing well. It’s like getting stock tips, relationship advice, and fitness routines from the same friend. Split responsibilities. Clean code starts with clean boundaries. 2. Document Your Code A comment today is a gift to your future self. Because your future self will have zero memory of the clever thing you wrote at 2am. Don’t make debugging a crime scene investigation. 3. Don’t Repeat Yourself (DRY) Copy-paste feels fast. It’s not. Every duplicate is a future bug waiting for its moment. Write once. Reuse everywhere. Let functions do the heavy lifting. 4. Keep It Simple Complex code looks impressive, until you’re the one maintaining it. The real flex is clarity. Readable > clever. Understandable > magical. 5. Test Driven Development (TDD) TDD is like writing the exam before studying. The test fails → you add logic → the test passes → you clean up. It forces discipline. It prevents surprises. It builds confidence you can’t get from vibes and manual testing alone. 6. YAGNI (You Ain’t Gonna Need It) Founders love planning for the future version of the product. Except most of those imagined features never ship. Focus on what users need now. Earn the right to build more later. So, treat your codebase like a campsite: Leave it cleaner than you found it. Your team and your roadmap will thank you. P.S. What’s the most chaotic codebase sin you’ve ever seen… that still haunts you to this day?
-
🚫 "But that's not consistent with our existing codebase!" After 10 years in software engineering, I've heard this phrase countless times when trying to introduce better design practices into legacy systems. Here's the uncomfortable truth: Consistency with bad design isn't actually valuable. It's just organised chaos. I've worked in codebases where technical debt runs deep, no polymorphism, code smells everywhere, violations of basic SOLID principles. When you try to introduce proper design patterns, you're often met with resistance disguised as a desire for "consistency." But here's what I've learned: If we keep doing things the wrong way just to maintain consistency, we never improve. The codebase becomes a monument to past mistakes rather than a foundation for future success. The real challenge isn't technical, it's cultural. Teams often resist change because: - They're unfamiliar with better design principles - They fear the learning curve - They mistake "familiar" for "maintainable" My approach: ✅ Start small with isolated improvements in new features ✅ Let results speak louder than theory ✅ Frame changes in business value, not engineering ideals ✅ Invest in team education about design principles Remember: Good design isn't about following trends, it's about writing code that's testable, maintainable, and adaptable to change. Sometimes breaking consistency is exactly what your codebase needs to heal. What's your experience with introducing design improvements in legacy systems? Have you faced similar resistance? #SoftwareEngineering #CleanCode #TechnicalDebt #SoftwareDesign #Programming
-
Forget bugs. Fragile dependencies are the real system killers. One tiny change shouldn’t break ten other parts of your system. Yet it happens all the time. Not because of bad code, but because of "bad connections". Here’s how to stop the silent sabotage. 1. Follow the Law of Demeter: objects talk only to their friends, never strangers. 2. Push logic to the right place. Let each class own its responsibility. 3. Rely on interfaces + dependency injection instead of hardcoding dependencies. This isn’t theory. It’s the difference between code you fear touching and code that’s safe to evolve. 👉 Read the article here: https://lnkd.in/eMVd9cRJ Question for you: What’s the worst dependency chain you’ve ever had to untangle?
Explore categories
- Hospitality & Tourism
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Healthcare
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Career
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development