"𝗪𝗲'𝗿𝗲 𝟵𝟬% 𝗱𝗼𝗻𝗲" 𝗶𝘀 𝘁𝗵𝗲 𝗺𝗼𝘀𝘁 𝗲𝘅𝗽𝗲𝗻𝘀𝗶𝘃𝗲 𝘀𝗲𝗻𝘁𝗲𝗻𝗰𝗲 𝗶𝗻 𝘀𝗼𝗳𝘁𝘄𝗮𝗿𝗲
It sounds like the finish line, but I find that it's usually the halfway mark
"The first 90% of the code accounts for the first 90% of the development time. The remaining 10% of the code accounts for the other 90% of the development time." Tom Cargill at Bell Labs coined it.
Jon Bentley printed it in his 1985 "Bumper-Sticker Computer Science" column for Communications of the ACM, and it stuck. The math is a joke. The lesson isn't.
The first 90% is the part you can see, the core features and the happy path, the stuff that demos well. You can plan it because you understand it. The last 10% is everything you couldn't predict from the outside: the error states nobody clicked through in the demo, the one customer whose data breaks an assumption you didn't know you'd made, the load test that surfaces an N+1 query, the accessibility pass, the rollback path you hope never to use. 𝗡𝗼𝗻𝗲 𝗼𝗳 𝗶𝘁 𝘄𝗮𝘀 𝘃𝗶𝘀𝗶𝗯𝗹𝗲 𝘄𝗵𝗲𝗻 𝘆𝗼𝘂 𝘄𝗿𝗼𝘁𝗲 𝘁𝗵𝗲 𝗲𝘀𝘁𝗶𝗺𝗮𝘁𝗲.
This is why the demo is so dangerous. It runs, and looks finished, and everyone relaxes. Then months disappear into the gap between "works in the demo" and "works in production." The team didn't slow down. They hit the part where the real work lived.
The damage isn't only the lost time but also the loss of optimism. When you tell stakeholders you're 90% done, they hear "𝗮𝗹𝗺𝗼𝘀𝘁 𝘀𝗵𝗶𝗽𝗽𝗲𝗱," and they plan around a date that was never real. The trust you lose when that date misses costs more than the miss itself.
So 𝘁𝗿𝗲𝗮𝘁 𝟵𝟬% 𝗱𝗼𝗻𝗲 𝗮𝘀 𝗵𝗮𝗹𝗳𝘄𝗮𝘆. Budget the finish as its own phase, with its own time and its own risk. The last 10% isn't where the project ends. It's where half the work was hiding the whole time.
Have you noticed this phenomenon in your projects?
At the top of the "are doomed to repeat it" category is the notion of "spec-driven development" (SDD). Though some claim that SDD is all about very tiny specs that encompass only a tiny amount of work, the vast majority of comments I see on the topic are hyping old-school waterfall big-up-front design as if that's a new, innovative idea. It's pushed by the most irresponsible of the vibe-coding crowd, who imagine that, if only the prompt were more detailed, they'd get better results. They won't.
We stopped working from big up-front specs decades ago for a reason—the approach fails in every context but the most boring ones: either the same program written over and over again, or something that effectively implements a mathematical formula of some sort. In that last case, a spec-driven approach will probably yield a UX so bad that it makes the formula implementation irrelevant.
People don't know what they need until they get something into their hands and try to use it. Any way of working that doesn't acknowledge that truth will fail.
I suppose, if the only thing you've ever experienced is chaos, SDD seems like an improvement, but believe me, it's not. In my experience, incremental feedback-driven approaches always yield better outcomes. Collaboratively develop a strategic goal. Collect enough information to start. Start. Get feedback as you work. Adjust. Works like a charm.
NEW POST
Thoughtworks internal IT use a workflow for agentic programming called Structured-Prompt-Driven Development (SPDD). @WeiZhang595190 and Jessie Jie Xia describe how this works with a simple example plus details in a github project.
https://t.co/6cHnSPWr6L
The past year has seen an explosion in coding *output*
Productivity would mean that more value is being created in one way or another. Easiest to measure e.g. in revenue that code/website/app generates
My suspicion is that eg most of those new apps don't generate anything
I’m seeing some hot takes that AI assisted coding means that you don’t have to be technical anymore. That’s only gonna last you until the first database migration, or the first security issue, or the first cloud migration, or the first scale out, or the first major regression, or the first refactor that ends in slop. I am finding that I’m learning more and I have to be as technical or more technical than ever before to get the kinds of high-quality output that I expect of any code, regardless of whether it comes from my fingertips or someone else’s - including an AI.
Whether your source comes from open source libraries, your own hands, or an AI via your clever prompt, there is exactly one responsible person for the output. That is you.
I never want to be accused of gatekeeping AI assisted programming, as non-technical people can get a lot of interesting work done. Until they hit a wall, and it’s gonna surprise them how quickly they either need to get technical, or get a technical person to help untangle the mess they’ve made.
The art and science of programming is taking intent and turning it into shipping products. I will never blame an AI - nor should you - for bad output. Own the code that you ship.
FAANG software engineer tells how they vibe code at FAANG
---
"You still always start with a technical design document. This is where a bulk of the work happens. The design doc starts off as a proposal doc. If you can get enough stakeholders to agree that your proposal has merit, you move on to developing out the system design itself. This includes the full architecture, integrations with other teams, etc.
Design review before launching into the development effort. This is where you have your teams design doc absolutely shredded by Senior Engineers. This is good. I think of it as front loading the pain.
If you pass review, you can now launch into the development effort. The first few weeks are spent doing more documentation on each subsystem that will be built by the individual dev teams.
Backlog development and sprint planning. This is where the devs work with the PMs and TPMs to hammer out discrete tasks that individual devs will work on and the order.
Software development. Finally, we can now get hands on keyboard and start crushing task tickets. This is where AI has been a force multiplier. We use Test Driven Development, so I have the AI coding agent write the tests first for the feature I’m going to build. Only then do I start using the agent to build out the feature.
Code submission review. We have a two dev approval process before code can get merged into man. AI is also showing great promise in assisting with the review.
Test in staging. If staging is good to go, we push to prod."
---
reddit. com/r/vibecoding/comments/1myakhd/how_we_vibe_code_at_a_faang/
Software engineering has radically changed in the last two years. The execution is less of a problem. Decision making and steering teams are the major new challenges.
Junior SWE: “Let’s just build one backend and one DB for everything”
Mid-level SWE: “We should move this into microservices with separate databases”
Senior SWE: “We need sharding, Kafka, CQRS, Redis, S3, and a global cache”
Principal SWE: “Can this just be a single service with a read replica”
What is the difference?
-> Junior chooses a simple setup because:
They just want it to work. One codebase, one DB, one deploy.
-> Mid-level pushes microservices because:
They just learned about scalability, patterns, queues, and want to use everything.
-> Senior pushes complex infra because:
They are anticipating scale, failures, and traffic patterns that may or may not come.
-> Principal comes back to simple because:
They have seen how much complexity costs in on-call pain, bugs, incidents, and slow teams.
The evolution in your system design thinking is not about tools.
It is about your sense of constraints.
If you are still learning system design, here is the direction I would give:
Note: This is not from an interview point of view, but general learning.
1. Start with the simplest thing that can actually work
– Single service, single database, clear API boundaries.
– Make sure you can monitor it, debug it, and deploy it safely.
2. Learn how systems fail before you learn how they scale
– Read postmortems.
– Study outages of big companies.
– Ask seniors why incidents happened and what they would do differently.
– You will understand why people are scared of unnecessary complexity.
3. Stop collecting tools, start collecting tradeoffs
– Do not just "learn Kafka".
– Learn when Kafka is useful and when it is overkill.
– Same for Redis, queues, microservices, event sourcing.
4. Always design with 3 time horizons in mind
– Today: Can we ship something reliable quickly
– 1 year: Can we change this system without rewriting everything
– 3 years: If this becomes 10x bigger, can we evolve it instead of replacing it
Your goal is not to design the fanciest system. Your goal is to design the smallest system that solves a problem and can grow when it actually needs to.
----------------
Check out my Java+Springboot+Microservices+Design Patterns+System design ebook curated for interviews from here https://t.co/iH4Ung369Y
@ChrisJBakke Probably accurate. Except its a Cava slop bowl. Apple will also go on to sell 3 million of those belts heading into the holiday season too.
One of my favorite lessons I’ve learnt from working with smart people:
Action produces information. If you’re unsure of what to do, just do anything, even if it’s the wrong thing. This will give you information about what you should actually be doing.
Sounds simple on the surface - the hard part is making it part of your every day working process.
This is officially my favorite tweet, ever.
@levelsio doing $248K/mo without knowing what state is.
It's proof that solving problems and execution is way more important than whatever you’re currently procrastinating on.
We ran a randomized controlled trial to see how much AI coding tools speed up experienced open-source developers.
The results surprised us: Developers thought they were 20% faster with AI tools, but they were actually 19% slower when they had access to AI than when they didn't.
"Fundamental" truths about software:
- Code is liability
- The more code you have, the more bugs you tend to have
- The more complex a system, the more important architecture becomes
- Writing maintainable code is a lot more effort than just getting it to work
𝗦𝗼𝗳𝘁𝘄𝗮𝗿𝗲 𝗘𝗻𝗴𝗶𝗻𝗲𝗲𝗿𝗶𝗻𝗴 𝗟𝗮𝘄𝘀 𝗬𝗼𝘂 𝗠𝘂𝘀𝘁 𝗞𝗻𝗼𝘄
Here is the list of the most crucial software engineering laws you should know:
𝟭. 𝗣𝗮𝗿𝗸𝗶𝗻𝘀𝗼𝗻’𝘀 𝗟𝗮𝘄 - "Work expands to fill the available time."
Tasks tend to take up as much time as allocated. Setting realistic deadlines helps avoid unnecessary scope and work expansions. Without clear boundaries, teams might spend more time than necessary, delaying project completion.
👉 Why it matters: Set precise deadlines to maintain focused effort and avoid wasted resources.
𝟮. 𝗛𝗼𝗳𝘀𝘁𝗮𝗱𝘁𝗲𝗿’𝘀 𝗟𝗮𝘄 - "It always takes longer than you expect, even when accounting for Hofstadter’s Law."
Software development estimates are often optimistic. Even when you factor in delays, unexpected complications arise. Adding generous buffers can mitigate unrealistic expectations.
👉 Why it matters: Always add buffers to your estimates to manage expectations and prevent burnout.
𝟯. 𝗕𝗿𝗼𝗼𝗸𝘀’ 𝗟𝗮𝘄 - "Adding manpower to a late software project makes it later."
Increasing team size late in a project adds overhead, as new members require a ramp-up period, and improved communication is necessary. This overhead can further slow down progress.
👉 Why it matters: Optimize your existing team's efficiency rather than expanding late in a project.
𝟰. 𝗖𝗼𝗻𝘄𝗮𝘆’𝘀 𝗟𝗮𝘄 - "Organizations design systems mirroring their communication structure."
The product architecture reflects team structures and communication patterns. Aligning your organizational structure with your desired system architecture ensures cohesive and efficient designs.
👉 Why it matters: Structure teams to reflect desired product outcomes, ensuring clear and effective communication.
𝟱. 𝗖𝘂𝗻𝗻𝗶𝗻𝗴𝗵𝗮𝗺’𝘀 𝗟𝗮𝘄 - "The best way to get the right answer is not asking a question, but posting the wrong answer."
People are quick to correct errors. By proactively engaging with imperfect solutions, you prompt rapid feedback and knowledge transfer, which resolves issues more quickly.
👉 Why it matters: Post imperfect solutions to prompt quicker feedback and knowledge sharing.
𝟲. 𝗦𝘁𝘂𝗿𝗴𝗲𝗼𝗻’𝘀 𝗟𝗮𝘄 - "90% of everything is crap."
Most ideas, code, or features add little value. Rigorous prioritization ensures efforts focus on high-impact areas, significantly benefiting overall productivity and project outcomes.
👉 Why it matters: Prioritize rigorously and focus efforts only on the most impactful features.
𝟳. 𝗭𝗮𝘄𝗶𝗻𝘀𝗸𝗶’𝘀 𝗟𝗮𝘄 - "Every program expands until it can read mail."
Software tends to grow unnecessarily complex by continuously adding features. Vigilance against feature creep helps maintain simplicity, clarity, and user satisfaction.
👉 Why it matters: Regularly review and cut unnecessary features to maintain simplicity and usability.
#softwareengineering #programming #coding
𝗪𝗵𝘆 𝘆𝗼𝘂 𝘀𝗵𝗼𝘂𝗹𝗱 𝗯𝘂𝗶𝗹𝗱 𝗮 (𝗺𝗼𝗱𝘂𝗹𝗮𝗿) 𝗺𝗼𝗻𝗼𝗹𝗶𝘁𝗵 𝗳𝗶𝗿𝘀𝘁?
In recent years, we have seen a significant increase in apps built using a microservices architecture. The main reason we select this approach is to have small teams working in isolation without tripping over each other.
Yet, this is an organizational problem, not a technical one. We can also build each service on a separate technology and scale independently.
With the 𝗺𝗶𝗰𝗿𝗼𝘀𝗲𝗿𝘃𝗶𝗰𝗲𝘀 𝗮𝗽𝗽𝗿𝗼𝗮𝗰𝗵, we also have a few disadvantages. The system is becoming increasingly complex to maintain and diagnose issues, such as logging and tracing, which are crucial when dealing with microservices.
So, 𝗯𝘂𝗶𝗹𝗱𝗶𝗻𝗴 𝗺𝗼𝗻𝗼𝗹𝗶𝘁𝗵𝘀 𝗱𝗼𝗲𝘀𝗻'𝘁 𝗺𝗲𝗮𝗻 𝘀𝗼𝗺𝗲𝘁𝗵𝗶𝗻𝗴 𝗯𝗲𝘁𝘁𝗲𝗿 𝗽𝗲𝗿 𝘀𝗲.
In recent years, we have often seen monoliths identified as big balls of mud architecture or purely built legacy codes, which are not intended to be. Yes, monoliths cannot scale or release independent pieces of the system separately, but those are mainly the most significant downsides.
Still, you can create excellent, high-quality code inside. 𝗠𝗼𝗻𝗼𝗹𝗶𝘁𝗵 𝗯𝗿𝗶𝗻𝗴𝘀 𝘂𝘀 𝗺𝘂𝗰𝗵 𝗹𝗲𝘀𝘀 𝗰𝗼𝗺𝗽𝗹𝗲𝘅𝗶𝘁𝘆, 𝗿𝗲𝗱𝘂𝗰𝗲𝗱 𝗻𝗲𝘁𝘄𝗼𝗿𝗸 𝗰𝗮𝗹𝗹𝘀, 𝘀𝗶𝗺𝗽𝗹𝗲𝗿 𝗹𝗼𝗴𝗴𝗶𝗻𝗴, 𝗲𝘁𝗰.
What could be one good solution, where we can still have separate modules and work on them, but maintain simplicity, is to 𝗯𝘂𝗶𝗹𝗱 𝗮 𝗺𝗼𝗱𝘂𝗹𝗮𝗿 𝗺𝗼𝗻𝗼𝗹𝗶𝘁𝗵. A properly built modular monolith can be a good step that can be easily transformed into a microservice solution tomorrow if needed.
When we want to build a modular monolith, it is crucial to 𝗳𝗶𝗿𝘀𝘁 𝗱𝗶𝘃𝗶𝗱𝗲 𝘁𝗵𝗲 𝘀𝘆𝘀𝘁𝗲𝗺 𝗶𝗻𝘁𝗼 𝗺𝗮𝗻𝗮𝗴𝗲𝗮𝗯𝗹𝗲 𝗺𝗼𝗱𝘂𝗹𝗲𝘀 before assembling those modules into a monolith for deployment.
As all communication between the modules might result in a cross-network call, high cohesion and low coupling are crucial if you decide to break it into services in the future.
This means that all inter-module communication must be abstracted, asynchronous, or based on messaging for the modules to handle calls that travel across the network in the future.
How can we implement such a system? 𝗪𝗲 𝗰𝗿𝗲𝗮𝘁𝗲 𝘀𝗲𝗽𝗮𝗿𝗮𝘁𝗲 𝗺𝗼𝗱𝘂𝗹𝗲𝘀, 𝘄𝗵𝗲𝗿𝗲 𝗲𝗮𝗰𝗵 𝗼𝗻𝗲 𝗰𝗮𝗻 𝗵𝗮𝘃𝗲 𝗶𝘁𝘀 𝗼𝘄𝗻 𝗮𝗿𝗰𝗵𝗶𝘁𝗲𝗰𝘁𝘂𝗿𝗲, and those modules are pulled together into a single API gateway.
This allows us to deploy the whole system as a monolith, enabling us to extract separate modules into services if needed.
#softwaredesign #softwareengineering #softwarearchitecture #programming