AI Can Write the Code. So What Are You Actually Good At? A developer argues that AI code generation tools make strong engineering fundamentals more important, not less, because understanding code becomes critical when AI-generated systems fail. The post emphasizes that abstraction layers require deep knowledge to debug effectively. There is a strange thing happening in software engineering. We have AI that can generate functions, explain stack traces, write SQL queries, scaffold APIs, refactor code, write tests, and even build entire applications from a single prompt. And somehow, this makes me more convinced than ever that software engineers need strong fundamentals . Not less. More. Because when writing code becomes cheap, understanding code becomes expensive . Let's say you ask an AI: "Build me a REST API for managing users." Five seconds later, you have controllers, models, routes, validation, authentication, tests, and probably a Docker configuration. Nice. But then something breaks. The database starts timing out. Your queue keeps retrying the same job. Memory usage slowly climbs. A race condition appears only under production traffic. Your API returns inconsistent data. The AI gives you three possible fixes. All three sound reasonable. Now what? This is where fundamentals suddenly become very expensive. If you don't understand HTTP, databases, concurrency, operating systems, networking, data structures, algorithms, application architecture, and the runtime you're working with, you don't really have an AI-assisted development workflow. You have an AI dependency . And that's a very different thing. We should acknowledge this. AI is incredibly useful. I use it. I experiment with it. I ask it stupid questions. I let it generate boring code. I let it explain unfamiliar APIs. I use it as a second pair of eyes. Sometimes I even let it write the first ugly version of something. That's fine. Software engineering has always been about using tools. Compilers replaced handwritten machine code. Frameworks replaced enormous amounts of boilerplate. Libraries replaced reinventing common algorithms. Cloud platforms replaced maintaining physical servers. AI is simply another abstraction layer. But abstraction has a price. You can only safely abstract away something you understand well enough to debug when the abstraction fails. That's the part people often forget. This is probably one of the most important distinctions for new engineers. A software system is not just source code. A system is a combination of: AI can generate the code. It cannot magically remove the complexity underneath it. You still need to understand what the generated code is doing. Otherwise, you're basically driving a race car while asking the passenger which pedal is the brake. One of the biggest advantages of learning fundamentals is that they give you a way to reason. Suppose an API suddenly becomes slow. A beginner might ask an AI: "Why is my API slow?" An engineer starts breaking the problem apart. Is the application slow? Is the database slow? Is the network slow? Are we making too many queries? Is there an N+1 query problem? Are we waiting on an external service? Is the CPU saturated? Is memory under pressure? Are connections exhausted? Is the queue backed up? Is the algorithm doing unnecessary work? This is not about memorizing solutions. It's about knowing where to look . Fundamentals turn debugging from guessing into investigation. "But I don't need to learn algorithms anymore. AI can generate them." Sure. And a calculator can calculate 927 × 381. You should still understand multiplication. The point of learning algorithms isn't to prove that you can manually implement a sorting algorithm during an interview. The deeper value is learning how to think about computational problems. You start asking: What happens when the dataset becomes 10x larger? What is the time complexity? What is the memory cost? Can this operation be indexed? Can this process be parallelized? Do I actually need to process all of this data? These questions matter even when AI writes the implementation. In fact, they matter more when AI writes the implementation. Because AI can produce code that is perfectly valid and completely unreasonable. This one hurts because I've seen it too many times. Someone asks AI to create a database schema. AI happily generates seventeen tables, twelve relationships, several indexes, some JSON columns, and a migration nobody understands. Everything works. Until production. Now suddenly: SELECT FROM users is running across millions of rows. The ORM is generating hundreds of queries. An index is missing. A transaction boundary is wrong. A foreign key relationship doesn't represent the actual business rule. The database becomes the bottleneck. The solution isn't another prompt. The solution is understanding databases. You don't need to become a database researcher. But you should understand: AI can help you write SQL. You still need to understand why the SQL is correct . Modern software is distributed by default. Your application talks to something. Maybe it's a database. Maybe it's Redis. Maybe it's an external API. Maybe it's object storage. Maybe it's another microservice. Maybe it's some random service running on a server you forgot existed. At some point, something goes through a network. Understanding basic networking gives you an entirely different perspective on software. HTTP isn't magic. DNS isn't magic. TCP isn't magic. TLS isn't magic. A timeout isn't just "the server is broken." Latency exists. Packets get lost. Connections get reused. Proxies exist. Load balancers exist. Caches exist. Once you understand these things, production errors become less mysterious. You don't need to become a kernel developer. But please learn what happens outside your editor. Processes. Threads. Memory. File descriptors. Signals. Permissions. Sockets. Environment variables. Processes getting killed. Logs. CPU usage. Memory pressure. Disk I/O. This knowledge becomes extremely useful the first time your application works perfectly on your laptop and behaves like a haunted machine in production. Your framework is not the operating system. Your framework is a layer on top of reality. And reality doesn't care how elegant your abstractions are. This is the part I worry about the most. AI makes it incredibly easy to appear productive. You can generate a lot of code without understanding much of it. That's dangerous because productivity can become an illusion. You create a repository. There are thousands of lines of code. The README looks beautiful. The tests are green. The UI works. Everything feels like engineering. Until someone asks: "Why did you design it this way?" And the answer is: "Because the AI suggested it." That's not engineering. That's delegation without accountability. An engineer can delegate implementation. An engineer cannot delegate responsibility for understanding the system. Prompting is useful. But I don't believe prompt engineering is the foundation of AI-era software engineering. The real skill is context engineering . Can you understand the problem? Can you define constraints? Can you provide the right context? Can you recognize incorrect assumptions? Can you evaluate the generated result? Can you test it? Can you observe it in production? Can you explain the trade-offs? Can you throw the generated solution away when it's wrong? That requires knowledge. A better prompt cannot compensate for a missing mental model. Think of AI as an extremely fast junior engineer who has read an absurd amount of documentation but doesn't actually have your production environment inside its head. It can be brilliant. It can also confidently produce nonsense. Your job is to build the filter. When AI gives you an answer, you should be able to think: "That sounds wrong because..." Or: "That's technically correct, but the trade-off is..." Or: "This works for 10,000 records, but it will become a problem at 100 million." Or: "This abstraction hides the exact thing I need to control." That little voice is engineering judgment. And engineering judgment comes from fundamentals plus experience. I think the role of the software engineer is changing. The ability to type syntax quickly is becoming less valuable. The ability to understand systems is becoming more valuable. The engineer of the future doesn't necessarily write more code. They might write less. They might spend more time: Ironically, AI might make good engineers look less productive on GitHub. Because sometimes the best engineering decision is: Don't build it. If you're starting your software engineering journey today, here's my unpopular advice: Don't spend all your time chasing the newest AI framework. Learn the boring stuff. Learn how a CPU executes instructions. Learn how memory works. Learn Linux. Learn networking. Learn HTTP. Learn databases. Learn algorithms. Learn data structures. Learn Git. Learn testing. Learn debugging. Learn how to read documentation. Learn how to read source code. Learn how to design an API. Learn how to model data. Learn how to observe a running system. Then use AI. Use it aggressively. Use it as a pair programmer. Use it as a teacher. Use it as a reviewer. Use it to generate the boring parts. Use it to challenge your assumptions. Just don't let it replace your ability to think. Here is the paradox I keep coming back to: The better AI becomes at writing software, the more important it becomes to understand software. Because generated code increases the amount of code we can produce. It doesn't automatically increase our ability to judge that code. And when the cost of producing code approaches zero, the bottleneck moves somewhere else. The bottleneck becomes: judgment. What should we build? Why? What should we not build? Is this architecture appropriate? Is this data model correct? Is this secure? Is this maintainable? What happens when it fails? What happens when traffic grows? What happens when the assumptions change? Those are not syntax questions. They're engineering questions. I'm not anti-AI. Quite the opposite. I'm interested in what happens when we combine human curiosity with machines that can generate software at ridiculous speed. But I don't want a generation of developers who know how to ask an AI for code but don't know how that code interacts with reality. That's backwards. Learn to think. Learn to investigate. Learn to build things from first principles. Break things. Read the error messages. Read the source code. Build the weird little tool nobody asked for. Build it again when you realize your first architecture was terrible. That's how you develop engineering intuition. AI can accelerate that journey. It cannot walk it for you. And maybe that's the most important thing to remember in this new era: Don't compete with AI at writing code. Become the person who knows what code should exist in the first place.