"I shipped code I don't understand and I bet you have too" – Jake Nations, Netflix

AAI Engineer
컴퓨터/소프트웨어경영/리더십AI/미래기술

Transcript

00:00:00[MUSIC]
00:00:21>> Hey everyone, good afternoon.
00:00:22I'm going to start my talk with a bit of a confession.
00:00:26Ship code, I didn't quite understand.
00:00:29Generated it, tested it, deployed it, couldn't explain how it worked.
00:00:33And here's the thing though, I'm willing to bet every one of you have too.
00:00:37>> [LAUGH]
00:00:40>> So now we can all admit that we all ship
00:00:41code that we don't understand anymore, I want to take a bit of a journey,
00:00:44see how this kind of has come to be.
00:00:46First, look back in history, we see that history tends to repeat itself.
00:00:50Second, we've fallen into a bit of a trap.
00:00:52We've confused easy with simple.
00:00:55Lastly, there is a fix, but it requires us not to outsource our thinking.
00:01:00So, I spent the last few years at Netflix helping drive adoption of AI tools.
00:01:05And I have to say the acceleration is absolutely real.
00:01:07Back log items that used to take days now take hours.
00:01:10And large refactors that have been on the books for years are finally being done.
00:01:15Here's the thing though.
00:01:16Large production systems always fail in unexpected ways.
00:01:19Like look what happened with Cloud Fair recently.
00:01:21When they do, you better understand the code you're debugging.
00:01:23And the problem is now we're generating code at such speed and such volume.
00:01:28Our understanding is having a hard time keeping up.
00:01:29Hell, I know, I've done it myself.
00:01:34I've generated a bunch of code, looked at it, thought, I have no idea what this does.
00:01:39But the test passed, it worked, so I shipped it.
00:01:41The thing here is this isn't really new.
00:01:44Every generation of software engineers has eventually hit a wall where software
00:01:48complexity has exceeded their ability to manage it.
00:01:50We're not the first to face a software crisis,
00:01:52we're the first to face it at this infinite scale of generation.
00:01:56So let's take a step back to see where this all started.
00:01:58In the late 60s, early 70s, a bunch of smart computer scientists at the time came
00:02:03together and said, hey, we're in a software crisis.
00:02:06We have this huge demand for software, and yet we're not really able to keep up.
00:02:11And projects are taking too long, and it's just really slow.
00:02:15We're not doing a good job.
00:02:16So Dijkstra came up with a really great quote.
00:02:20And he said, when we had a few weak computers, I mean to paraphrase a longer
00:02:23quote, when we had a few weak computers, programming was a mild problem.
00:02:26And now that we have gigantic computers, programming has become a gigantic problem.
00:02:31He was explaining as hardware power grew by a factor of 1,000,
00:02:34society's wants of software grew in proportion.
00:02:37And so it left us, the programmers, to figure out between the ways and the means,
00:02:41how do we support this much more software?
00:02:43So this kind of keeps happening in a cycle.
00:02:47In the 70s we get the C programming language, so we could write bigger systems.
00:02:50In the 80s we have personal computers now, everyone can write software.
00:02:53In the 90s we get object-oriented programming.
00:02:56Inherent hierarchies from hell, thanks Java for that.
00:03:00In the 2000s we get agile, and we have sprints and
00:03:03scrum masters telling us what to do, there's no more waterfall.
00:03:06In the 2010s we had cloud, mobile, DevOps, everything,
00:03:09the software truly ate the world.
00:03:10And today now we have AI, Co-Pilot, Cursor, Clod, Codex, Gemini, you name it.
00:03:17We could generate code as fast as we can describe it.
00:03:19The pattern continues, but the stale has really changed, it's infinite now.
00:03:23So Fred Brooks, you might know him from writing the Mythical Man month.
00:03:29He also wrote a paper in 1986 called No Silver Bullet.
00:03:32And in this he argued that there would be no single innovation that would give us
00:03:36an order of magnitude improvement in software productivity.
00:03:38Why?
00:03:40Because he said the hard part wasn't the mechanics of coding, the syntax,
00:03:44the typing, the boilerplate.
00:03:45It was about understanding the actual problem and designing the solution.
00:03:49No tool can eliminate that fundamental difficulty.
00:03:52Every tool and technique we've created up to this point makes the mechanics easier.
00:03:55The core challenge though,
00:03:57understanding what to build, how it should work, remains just as hard.
00:04:00So if the problem isn't in the mechanics, why do we keep optimizing for it?
00:04:06How do experienced engineers end up with code they don't understand now?
00:04:09The answer, I think, comes down to two words we tend to confuse, simple and easy.
00:04:14We tend to use them interchangeably, but
00:04:16they really mean completely different things.
00:04:18I was outed at the speaker dinner as being a Clojure guy, so
00:04:21this is kind of clear here.
00:04:23But Rich Hickey, the creator of the Clojure programming language,
00:04:25explained this in his talk from 2011 called Simple Made Easy.
00:04:29He defined simple meaning one fold, one braid, and no entanglement.
00:04:33Each piece does one thing and doesn't intertwine with others.
00:04:36He defines easy as meaning adjacent, what's within reach.
00:04:39What can you access without effort?
00:04:41Copy, paste, ship.
00:04:43Simple is about structure.
00:04:45Easy is about proximity.
00:04:48The thing is, we can't make something simple by wishing it so.
00:04:51Simplicity requires thought, design, and untangling.
00:04:54But we can always make something easier.
00:04:56You just put it closer.
00:04:57Install a package, generate it with AI, copy a solution off of Stack Overflow.
00:05:03It's human nature to take the easy path.
00:05:06We're wired for it.
00:05:07As I said, copy something from Stack Overflow, it's right there.
00:05:10Framework that handles everything for you with magic, install and go.
00:05:14But easy doesn't mean simple.
00:05:15Easy means you can add to your system quickly.
00:05:18Simple means you can understand the work that you've done.
00:05:20Every time we choose easy, we're choosing speed now, complexity later.
00:05:24And honestly, that trade-off really used to work.
00:05:27The complexity accumulated in our code base is slowly enough that we can
00:05:31refactor, rethink, and rebuild when needed.
00:05:34I think AI has destroyed that balance.
00:05:36Cuz it's the ultimate easy button.
00:05:37It makes the easy path so
00:05:38frictionless that we don't even consider the simple one anymore.
00:05:41Why think about architecture when code appears instantly?
00:05:44So let me show you how this happens.
00:05:47Now a simple task evolves into a mess of complexity
00:05:50through a conversational interface that we've all come to love.
00:05:52This is a contrived example, but say we have our app,
00:05:55we wanna add some authentication to it.
00:05:57Say add auth, so we get a nice clean auth.js file.
00:06:01Iterate it on a few times, it gives a message five.
00:06:02You're like, okay, cool, we're gonna add OAuth now too,
00:06:04because now we've got an auth.js and OAuth.js.
00:06:07We keep iterating, we find ourselves that sessions are broken.
00:06:11And we got a bunch of conflicts.
00:06:12And by the time we get to turn 20, you're not really having a discussion anymore.
00:06:15You're managing contexts that become so complex that even you don't remember
00:06:18all the constraints that you've added to it.
00:06:20Dead code from abandoned approaches.
00:06:22Tests that got fixed by just making them work.
00:06:25Fragments of three different solutions because you end up saying, wait, actually.
00:06:28Each new instruction is overwriting architectural patterns.
00:06:31We said make the auth work here, it did.
00:06:33When we said fix this error, it did.
00:06:35There's no resistance to bad architectural decisions.
00:06:38The code just morphs to satisfy your latest request.
00:06:40Each interaction is choosing easy over simple.
00:06:43And easy always means more complexity.
00:06:46We know better, but when the easy path is just this easy, we take it.
00:06:50And complexity is going to compound until it's too late.
00:06:52AI really takes easy to its logical extreme.
00:06:58Decide what you want, get code instantly.
00:07:00But here's the danger in that.
00:07:02The generated code treats every pattern in your code base the same.
00:07:06When an agent analyzes your code base, every line becomes a pattern to preserve.
00:07:10The authentication check on line 47, that's a pattern.
00:07:13That weird GRPC code that's acting like GraphQL that I may have added in 2019,
00:07:18that's also a pattern.
00:07:19Technical debt doesn't register as debt, it's just more code.
00:07:22The real problem here is complexity.
00:07:25I know I've been saying that word a bunch in this talk without really defining it.
00:07:29But the best way to think about it is it's the opposite of simplicity.
00:07:31It just means intertwined.
00:07:33And when things are complex, everything touches everything else.
00:07:36You can't change one thing without affecting ten others.
00:07:41So back to Fred Brooks' No Sober Bullet paper.
00:07:43In it, he identified that there's two main types of complexity in every system.
00:07:47There's the essential complexity, which is really the fundamental difficulty
00:07:51of the actual problem you're trying to solve.
00:07:53Users need to pay for things, orders must be fulfilled.
00:07:56This is the complexity of why your software system exists in the first place.
00:08:00And then second, there's this idea of accidental complexity.
00:08:03Everything else we've added along the way, workarounds, defensive code,
00:08:06frameworks, abstractions that made sense a while ago.
00:08:09It's all the stuff that we put together to make the code itself work.
00:08:11In a real code base, these two types of complexity are everywhere.
00:08:16And they get so tangled together that separating them requires context,
00:08:19history, and experience.
00:08:20The generated output makes no such distinction.
00:08:24And so every pattern keeps us getting preserved.
00:08:26So here's a real example from some work we're doing at Netflix.
00:08:32I have a system that has an abstraction layer sitting between our old
00:08:35authorization code we wrote, say five or so years ago, in a new centralized auth system.
00:08:41We didn't have time to rebuild our whole app, so
00:08:42we just kind of put a shim in between.
00:08:44So now we have AI, this is a great opportunity to refactor our code to use
00:08:47the new system directly, seems like a simple request, right?
00:08:50And no, it's like the old code was just so tightly coupled to its authorization
00:08:56patterns, like we had permission checks woven through business logic,
00:08:59role assumptions baked into data models, and auth calls scattered across hundreds of
00:09:03files, the agent would start refactoring, get a few files in, and
00:09:07hit a dependency it couldn't untangle, and just spiral out of control and give up.
00:09:10Or worse, it would try and preserve some existing logic from the old system and
00:09:16recreating it using the new system, which I think is not great too.
00:09:19The thing is, it couldn't see the scenes.
00:09:23It couldn't identify where the business logic ended and the auth logic began.
00:09:26Everything was so tangled together that even with perfect information,
00:09:30the AI couldn't find a clean path through.
00:09:33When your accidental complexity gets this tangled,
00:09:35AI is not the best help to actually make it any better.
00:09:38I found it only adds more layers on top.
00:09:40We can tell the difference, or at least we can when we slow down enough to think.
00:09:45We know which patterns are essential and
00:09:47which are just how someone solved it a few years ago.
00:09:50We carry the context that the AI can't infer, but
00:09:53only if we take time to make these distinctions before we start.
00:09:56So how do you actually do it?
00:10:01How do you separate the accidental and essential complexity, and
00:10:04you're staring at a huge code base?
00:10:07Code base I work on Netflix has around a million lines of Java, and
00:10:10the main service in it is about five million tokens last time I checked.
00:10:13No context window I have access to can hold it.
00:10:17So when I wanted to work with it, I first thought, hey,
00:10:19maybe I can just copy large swaths of this code base into the context and
00:10:23see if the patterns were merged,
00:10:24see if it would just be able to figure out what's happening.
00:10:26And just like the authorization refactor from previously,
00:10:29the output just got lost in its own complexity.
00:10:31So with this I was forced to do something different.
00:10:34I had to select what to include, design docs, architecture, diagrams,
00:10:37key interfaces, you name it.
00:10:39And take time writing out the requirements of how components should interact and
00:10:42what patterns to follow.
00:10:43See, I was writing a spec.
00:10:45Five million tokens became 2,000 words of specification.
00:10:49And then to take it even further, take that spec and
00:10:52create an exact set of steps of code to execute.
00:10:55No vague instructions, just a precise sequence of operations.
00:10:58I found this produced much cleaner and more focused code that I could understand.
00:11:02So I defined it first, and planned its own execution.
00:11:05This became the approach which I called context compression a while ago.
00:11:11But you call it context engineering, your spectra of in development,
00:11:13whatever you want.
00:11:15The name doesn't matter.
00:11:16What only matters here is that thinking and planning become a majority of the work.
00:11:20So let me walk you through how this works in practice.
00:11:22So you have step one, phase one, research.
00:11:26You know, I go and feed everything to it up front.
00:11:28Architecture diagrams, documentation, slack threads.
00:11:31I mean, we've been over this a bunch.
00:11:32But really just bring as much context as you can that's gonna be relevant to
00:11:35the changes you're making.
00:11:36And then use the agent to analyze the code base and
00:11:39map out the components and dependencies.
00:11:42This shouldn't be a one shot process.
00:11:43I like to probe, say like, what about the caching?
00:11:46How does this handle failures?
00:11:47And when its analysis is wrong, I'll correct it.
00:11:49And if it's missing context, I provide it.
00:11:51Each iteration refines its analysis.
00:11:55The output here is a single research document.
00:11:57Here's what exists, here's what connects to what, and
00:11:59here's what your change will affect.
00:12:01Hours of expiration are compressed into minutes of reading.
00:12:03I know Dex mentioned it this morning, but the human checkpoint here is critical.
00:12:09This is where you validate the analysis against reality,
00:12:12the highest leverage moment in the entire process.
00:12:15Catch errors here, prevent disasters later.
00:12:17On to phase two.
00:12:20Now that you have some valid research in hand,
00:12:22we create a detailed implementation plan, real code structure,
00:12:25function signatures, type definitions, data flow.
00:12:28You want this to be so any developer can follow it.
00:12:30I kind of liken it to paint by numbers.
00:12:32You should be able to hand it to your most junior engineer and say, go do this.
00:12:35And if they copy it line by line, it should just work.
00:12:38This step is where we make a lot of the important architectural decisions.
00:12:43Make sure complex logic is correct.
00:12:45Make sure business requirements are following good practice.
00:12:50Make sure there's good service boundaries, clean separation, and
00:12:52preventing any unnecessary coupling.
00:12:54We spot the problems before they happen because we've lived through them.
00:12:57AI doesn't have that option.
00:12:59It treats every pattern as a requirement.
00:13:01The real magic in this step is the review speed.
00:13:05We can validate this plan in minutes and know exactly what's going to be built.
00:13:10And in order to keep up with the speed at which we want to generate code,
00:13:13we need to be able to comprehend what we're doing just as fast.
00:13:18Lastly, we have implementation, and now that we have a clear plan and
00:13:22backed by clear research, this phase should be pretty simple.
00:13:26And that's the point.
00:13:28When AI has a clear specification to follow, the context remains clean and
00:13:31focused.
00:13:32We've prevented the complexity spiral of long conversations.
00:13:36And instead of 50 messages of evolutionary code,
00:13:38we have three focused outputs, each validated before proceeding.
00:13:41No abandoned approaches, no conflicting patterns,
00:13:44no wait actually moments that leave dead code everywhere.
00:13:48To me, what I see as a real payoff of this is that you can use a background agent to
00:13:52do a lot of this work, cuz you've done all the thinking and hard work ahead of time.
00:13:56It can just start the implementation, you can go work on something else, and
00:13:59come back to review.
00:14:01And you can review this quickly because you're just verifying that it's conforming
00:14:04to your plan, not trying to understand if anything got invented.
00:14:07The thing here is we're not using AI to think for us.
00:14:12We're using it to accelerate the mechanical parts
00:14:15while maintaining our ability to understand it.
00:14:17Research is faster, planning is more thorough, and the implementation is cleaner.
00:14:21The thinking, the synthesis, and the judgement, though, that remains with us.
00:14:26So, remember that authorization refactor I said that AI couldn't handle?
00:14:34The thing is now we're actually working on it now and
00:14:37starting to make some good progress on it.
00:14:39The thing is it's not because we found better prompts.
00:14:42We found we couldn't even jump into doing any sort of research planning and
00:14:45implementation.
00:14:46We actually had to go make this change ourself by hand.
00:14:49No AI, just reading the code, understanding the dependencies, and
00:14:52making changes to see what broke.
00:14:53That manual migration was, I'll be honest, was a pain, but it was crucial.
00:14:59It revealed all the hidden constraints, which invariance had to hold true, and
00:15:02which services would break if the auth changed.
00:15:05Things no amount of code analysis would have surfaced for us.
00:15:09And then we fed that pull request of the actual manual migration into our research
00:15:14process and had it use that as the seed for any sort of research going forward.
00:15:19The AI could then see what a clean migration looks like.
00:15:23The thing is, each of these entities are slightly different, so we have to go and
00:15:27interrogate it and say, hey, what do we do about this?
00:15:29Some things are encrypted, some things are not.
00:15:32We had to provide that extra context each time through a bunch of iteration.
00:15:35Then, and only then, we could generate a plan that might work in one shot.
00:15:41And the key word, and might's the key word here, is we're still validating,
00:15:45still adjusting, and still discovering edge cases.
00:15:47The three phase approach is not magic.
00:15:55It only works because we did this one migration by hand.
00:15:57We had to earn the understanding before we can encode into our process.
00:16:01I still think there's no silver bullet.
00:16:02I don't think there's better prompts, better models, or even writing better specs.
00:16:06Just the work of understanding your system deeply enough that you can make changes to
00:16:09it safely.
00:16:11So why go through with all this?
00:16:15Why not just iterate with AI until it works?
00:16:18Eventually, models get strong enough and it just works.
00:16:21The thing to me is, it works isn't enough.
00:16:24There's a difference between code that passes test and code that survives in
00:16:27production.
00:16:28Between systems that function today and
00:16:31systems that can be changed by someone else in the future.
00:16:34The real problem here is a knowledge gap.
00:16:38When AI can generate thousands of lines of code in seconds,
00:16:41understanding it could take you hours, maybe days if it's complex.
00:16:45Who knows, maybe never if it's really that tangled.
00:16:48Here's something that I don't think many people are even talking about at this
00:16:52point. Every time we skip thinking to keep up with generation speed,
00:16:56we're not just adding code that we don't understand.
00:16:58We're losing our ability to recognize problems.
00:17:00That instinct that says, hey, this is getting complex,
00:17:03it atrophies when you don't understand your own system.
00:17:09Pattern recognition comes from experience.
00:17:11When I spot a dangerous architecture,
00:17:12it's because I'm the one up at three in the morning dealing with it.
00:17:16When I push for simpler solutions,
00:17:17it's because I've had to maintain the alternative from someone else.
00:17:21AI generates what you ask it for.
00:17:23It doesn't encode lessons from past failures.
00:17:25The three phase approach bridges this gap.
00:17:29It compresses understanding into artifacts we can review at the speed of generation.
00:17:33Without it, we're just accumulating complexity faster than we can comprehend
00:17:37it.
00:17:39AI changes everything about how we write code, but honestly,
00:17:44I don't think it changes anything about why software itself fails.
00:17:47Every generation has faced their own software crisis.
00:17:50Dijkstra's generation faced it by creating the discipline of software engineering, and
00:17:54now we face ours with infinite code generation.
00:17:56I don't think the solution is another tool in methodology.
00:18:01It's remembering what we've always known, that software is a human endeavor.
00:18:05The hard part was never typing the code.
00:18:06It was knowing what to type in the first place.
00:18:09The developers who thrive won't just be the ones who generate the most code.
00:18:13They'll be the ones who understand what they're building,
00:18:15who can still see the seams, who can recognize that they're solving the wrong
00:18:18problem.
00:18:19That's still us.
00:18:20That will only be us.
00:18:21I want to leave on a question, and I don't think the question is whether or
00:18:25not we will use AI.
00:18:26That's a foregone conclusion.
00:18:28The ship has already sailed.
00:18:30To me, the question's going to be whether we will still understand our own systems
00:18:33when AI is writing most of our code.
00:18:35Thank you.
00:18:37>> [APPLAUSE]
00:18:39[MUSIC]

Description

In 1968, the term ""Software Crisis"" emerged when systems grew beyond what developers could manage. Every generation since has ""solved"" it with more powerful tools, only to create even bigger problems. Today, AI accelerates the pattern into the Infinite Software Crisis. AI-generated codebases mirror the meandering conversations that created them. Every clarification and pivot gets baked into your architecture. We're vibecoding our way to disaster. The solution: choose simple over easy. One long conversation is easy. Separate phases with clean boundaries are simple. This talk presents a three-phase methodology: - Research to understand the existing system - Planning to design the approach - Implementation with clean context While everyone races to generate code at machine speed, the engineers who thrive will be those who know when a system is getting tangled. In the age of infinite code generation, human judgment applied at the right moments becomes your competitive advantage. Speaker: Jake Nations | Engineering, Netflix https://www.linkedin.com/in/jakenations/ https://github.com/Nayshins Timestamps: 00:00 The Modern Confession: Shipping Code We Don’t Understand 01:53 The History of the Software Crisis (1968 to Present) 03:30 Fred Brooks and "No Silver Bullet" 04:12 Simple vs. Easy (Rich Hickey’s Definition) 05:40 The AI Trap: "Vibecoding" and Conversational Complexity 06:39 The problem with iterative AI chat interfaces 15:12 Implementation Phase: Using Manual Migration as a Seed 16:14 The Knowledge Gap: Code Generation vs. Code Understanding 17:40 Conclusion: Software is a Human Endeavor

Community Posts

No posts yet. Be the first to write about this video!

Write about this video