
\ Vibe coding seems like an excellent choice in an ideal repository. We describe the application, after which AI coding Agent creates the frontend, backend, database model, and test cases. The application runs locally and does everything that it should do. At this stage, it seems like all software development problems have been solved. But when this solution is applied in a legacy environment, the artificial intelligence-generated code needs to cope with undocumented business logic, shared databases, legacy interfaces, fragile test cases, undeclared dependencies, and behavior in production that cannot be compromised. Here, vibe coding becomes more of a liability than a magic trick. The demo works because the system has no past There is undeniable value in the use of AI-based tools in the world of programming. These include scaffolding projects, providing boilerplate code, explaining code that is unknown, writing test cases, and enabling programmers to make headway through repetitive actions. In new projects, prototypes, internal tools, and one-off experimentation, the above tools can prove highly useful. And the reason for this is quite simple: There will be very little history involved in these kinds of projects. There is no legacy database structure. No consumer using some obscure attribute of the data. No compliance issue in the form of a deprecated requirement. No legacy process that goes wrong whenever a value changes from null to empty. In the absence of a legacy component, the tool can build the application. In a legacy environment, however, the tool would have to understand the legacy design first. The two represent completely different problems. Legacy systems punish missing context What tends to make working on legacy systems difficult is not necessarily the process of writing code; it is understanding why the code exists in the first place. The reason why an awkward validation check may be necessary is due to regulation. A field that may seem redundant may be required to perform an outdated report. A complex decision tree may be difficult to follow because of all the interdependencies that exist among the five teams it feeds into. A slow batch process may be critical to maintaining order in something that is not clearly outlined. AI coding software excels in answering such interpretive questions: “What code would normally solve this problem?” They are much weaker at answering: “What code should be written in this specific system, given its history, constraints, dependencies, and failure modes?” That difference matters. In a side project, normal code may be good enough. In a legacy system, normal code can break production. The codebase is not the whole system One misconception about AI-assisted programming is the belief that all truths are contained within the repository. Not so. In reality, the entire system comprises deploy scripts, database limitations, feature switches, monitors, support processes, API contracts, audits, bug histories, expectations, and institutional knowledge. Some of the most important behaviors of the system will not be documented in the code repository. They may be hidden in runbooks, stored collectively in the memory of the support staff, codified within data validation checks, or even buried deep within some application that hasn't been touched in years. As a result, the code produced by an AI tool that works only from what it can see in terms of files may seem correct, but be incorrect in its larger environment. Perhaps the API works perfectly but doesn't satisfy any pagination criteria; maybe the database migration looks good until it locks a table at peak time; or perhaps the refactoring reduces duplicated code but removes a workaround that would have prevented a production outage. This very thing explains why legacy code slows development down – not because developers are inefficient but because there is institutional knowledge that cannot be coded. AI increases output before it increases understanding AI coding tools allow for the fast generation of large amounts of code. But that is helpful only when taking into account the fact that not all engineering teams suffer from the problem of limited typing speeds but rather face the problem of unclear requirements, unstable development environments, lack of reviews, insufficient testing, dependency issues, security audits, release scheduling, and cross-team ownership. AI helps solve some of those problems, but it might make others worse through an increased amount of code to be reviewed, tested, integrated, and maintained. Take, for example, a developer capable of producing five versions of the solution within minutes. Nevertheless, there still exist multiple questions to ask: Does it fit into our architecture? Does it break any existing contracts? Is it deployable? Is it reliable on production data? Is it instrumented? Does it affect other teams? Can we provide out-of-hours support, say, at 2 a.m.? When the code generated by AI is created faster than most teams are able to verify it, there is a new kind of problem. The dangerous part is convincing code Bad code is nothing new – developers have been producing bad code all along. One other more critical threat posed by code generation based on AI is the tendency for such generated code to be plausibly good. The generated code could be properly formatted, use reasonable variable names, implement common design patterns, and contain enough commentary and tests. Plausibility does not imply correctness. Generated code could look good, follow best practices, pass some local tests, and still be wrong. This is especially threatening when working with an unfamiliar area of legacy code where the generated code could create the illusion of confidence in the developer to act faster than he or she should considering their understanding of the code. Where AI coding actually helps None of the above suggests that AI-powered coding doesn’t work in legacy systems. It’s extremely effective when the problem is bounded, reviewable, and tested empirically. More precisely, AI is excellent at explaining unfamiliar code, writing tests, documenting the code, performing minor refactoring, and migrating it. The critical idea is to use AI in conjunction with humans, not in lieu of them. The optimal approach would not be: “Ai, fix this system” But rather: “Ai, help me understand this system before I change it.” The difference is crucial. Instead of asking Ai to refactor some service, it’s better to ask about its dependencies and potential risks first. Instead of asking Ai to resolve some bug immediately, it would be more appropriate to ask to generate tests demonstrating the current behavior. Instead of asking AI to change an API, it would be better to make it compare contracts and their changes. In such ways, we involve AI into our engineering process, not bypass it. Where vibe coding becomes dangerous The risk associated with vibe coding rises if the activity is generic, vague, or highly coupled with production work. Examples include: changing the schema of a shared database changing authentication or authorization logic changing payment/billing/claims/financial calculations changing event schemas refactoring code that multiple teams use changing retry/error handling behavior changing batch jobs that have downstream dependants changing APIs without having contract tests in place adding new production dependancies without proper approval process None of these tasks are outside the realm of what AI could help with, but none of these would be considered vibe coding activities. Give AI a harness, not a blank check The better workflow is to constrain the AI before it writes code. A good harness includes acceptance criteria, existing architecture notes, coding standards, test commands, linting rules, API contracts, known anti-patterns, security requirements, and rollback expectations. The AI should know not only what to build, but what not to break. A safer workflow looks like this: Ask AI to explain the current behavior. Ask AI to identify dependencies and risks. Ask AI to generate or improve tests. Run the tests yourself. Ask AI to propose the smallest safe change. Review the change manually. Run linting, static analysis, and integration tests. Deploy carefully and monitor behavior. This is less exciting than a viral demo. It is also how real software survives. \ The common fear is that artificial intelligence will decrease the need for engineers. But in legacy applications, things work the other way round. Although artificial intelligence is capable of generating code, an engineer understands all the consequences of any alteration. He understands which changes are, seemingly minor, but actually complex. He recognizes the test suites that are worth something and those that just serve decoration purposes. An engineer knows which groups will be affected by changing data fields. Also, an engineer understands when a neat refactor is a real problem disguised as refactoring. Artificial intelligence replaces the part of the engineering effort from typing to reasoning. Therefore, reasoning skills become more important than ever. An engineer of the future will write less code on the keyboard, but his/her system understanding skills will be enhanced. Vibe coding is a prototype mode, not a production strategy The fact that vibe coding works well when speed is more important than reliability makes it an excellent choice for use cases in which prototyping, demonstration, learning, and product discovery take place. However, building a production system cannot be achieved through vibe coding alone. It requires testing, contracting, observability, security, documentation, ownership, and an engineering process marked by consistency and reliability. But this should not take away the thrill of working on something new. The next phase of development assisted by AI won't rely on figuring out who is capable of creating the most amount of code. It will focus more on the ability to implement AI within software distribution without causing a maintenance nightmare. Vibe coding works where the system has no history behind it. Legacy systems are by definition a thing of the past. This is the reason why the effectiveness is quickly compromised. Not because of the ineffectiveness of AI. But because any software comes with consequences. \
View original source — Hacker Noon ↗



