Six months ago, I wrote this article. At the time, I made two assertions: although Claude Code wasn't getting much attention upon its release, its easily integrable agentic capabilities were crucial; and the future of software distribution and development would change significantly, with Library as a Service (LaaS) becoming an important new model. Over the past six months, I've been putting these ideas into practice, becoming a heavy user of Claude Code-like tools and developing our own LaaS product for our AI courses.
Looking back on a year of intensive AI development, I've noticed a counter-intuitive phenomenon: I haven't consciously avoided repetitive work. In fact, I've intentionally violated one of the core principles of software engineering—DRY (Don't Repeat Yourself). For instance, whenever I need to draw a flowchart or create a simple visualization, I ask an AI to write the code directly instead of abstracting it into a reusable library. Strangely, my development productivity hasn't decreased.
This way of working is a microcosm of the User-Generated Software (UGS) era. Our needs are no longer the general demands of the masses but are personalized, temporary requirements. The software we use is no longer pre-developed by large corporations but is written on the spot by AI. But in this era, what exactly is the product that a software company delivers? In the past, the answer was obvious: an Office installation package, the Gmail website—users could use these finished products to complete their tasks. But now, when users complete tasks by writing code through a conversation with an AI, what is it that software companies or platform providers are actually delivering?
I gradually realized that the reason I could violate the DRY principle is that the nature of the deliverable has fundamentally changed. We are no longer delivering a static, finished product that requires long-term maintenance and aims to minimize uncertainty. This article aims to clarify the nature of this new type of deliverable and to consider how we should build a new software engineering framework for the age of user-generated software.
The Shift in Scenarios - Why
Looking back at the software development process of the past few decades, it's very similar to how a television network produces a show. A product manager first identifies a large, commercially viable user base and gathers their diverse needs. Then, they prioritize, focusing on the most common demands and abstracting them logically to define development goals. This is abstraction at the product level. Next, the engineering team analyzes these requirements and performs engineering-level abstraction—designing a system that is as simple and elegant as possible to support these needs, ensuring that our limited development resources can be reused.
In contrast, software development in the AI era is very different in terms of scenarios. A new type of scenario has emerged where our goal is often not to create a long-lasting piece of software that serves many people for years, but rather a lightweight, temporary tool that might only serve me, and can be discarded after use. For example, checking the Pop Mart website daily for new arrivals and sending me a text notification if there are any, or simply renaming the thirty videos I have on hand according to a specific pattern.
Before AI, such scenarios seemed completely unrealistic. It was impossible to maintain an outsourcing team just to cater to one person's temporary needs, developing five disposable apps a day. But think about how TikTok creates a personalized app experience for each user based on their preferences—something that sounded absurd a decade ago but is commonplace today. The emergence of AI is similar to TikTok in that it makes software development, or more abstractly, the scheduling of computing power, an incredibly lightweight affair. We've already seen many examples where you can just say a sentence to an AI, and it will write a script to batch-rename those 30 videos for you, or even create a mini-plugin for the Pop Mart website in a few minutes.
Compared to the meticulously crafted programs on television, these pieces of software are like short videos on TikTok—they are cheap to produce and rarely have a lasting impact. But, similar to YouTube and TikTok, these AI-generated, disposable applications constitute a new category of software: User-Generated Software (UGS). UGS addresses the long-tail needs of users, allowing ordinary people who don't code and don't use existing commercial apps to freely harness the power of computing and enjoy the benefits of information automation. Its commercial potential is just as vast, if not greater.
This creates a clear contradiction: traditional software engineering was invented for heavyweight apps intended to serve thousands of users for several years. It emphasizes maintainability, scalability, and reusability. The core goal is to minimize uncertainty in both the delivered software and the development process. However, neither the goals nor the methods of this traditional approach are suited for these new scenarios, which instead emphasize maximizing "Generative Potential." If we want to move beyond the limitations of the DRY mindset and continue to build high-quality software in the new era of User-Generated Software, what principles should we follow, and what framework should guide our thinking?
The Shift in Deliverables - What
To answer this question, we first need to clarify what a software company actually delivers in the UGS era. My answer is a "Generative Kernel" that supports AI in code generation. The difference between this and traditional software delivery is like the difference between buying fully assembled furniture and buying from IKEA.
With traditional software, what the user gets is like a chair with a completely fixed form and function. It's ready to use out of the box, but the user can't easily change its height or color. To sell this chair to as many people as possible, its design must meet the needs of the general public, aiming for universality. Because this approach brings greater economic benefits, it is designed and manufactured by a team of experts.
In contrast, personalized software generated by AI follows a completely different playbook. It's like IKEA furniture: the user doesn't buy a ready-to-use chair, but a kit. This kit contains a few key components, such as a pre-drilled seat and legs. We can't make these parts ourselves at home, and their quality determines the quality of the final product. The kit also includes a detailed instruction manual to guide the user (or an AI) through the assembly, step by step. A user can follow the instructions to build a standard chair, or they can choose to modify it—change the color, saw the legs shorter, or even use only three legs to meet their personalized needs.
In this process, the user's role is no longer that of a pure consumer or "User," but a "Builder." Our role as a software company also changes. We are no longer making finished furniture, but rather these semi-finished kits. Our success is no longer determined by how many chairs we sell, but by how easily, efficiently, and creatively our kits enable users to assemble the diverse range of chairs they desire.
Therefore, from a more abstract perspective, the value of this basic kit lies in its "Generative Potential": its capacity, as a foundation for collaboration with AI, to generate a wide variety of high-quality, personalized applications. This can be viewed from three more specific dimensions:
- Expressive Range: Based on the capabilities provided, how rich a variety of applications can the user and AI build? Are they confined to a narrow set of functions, or are there components that support a wide range of use cases? This is a measure of breadth.
- Intent Fidelity: When a user has a clear intent, how closely does the final generated result match that initial intent? Are compromises necessary, or can it be perfectly realized? This is a measure of depth.
- Generation Efficiency: When the platform works with an AI, how "helpful" is the AI? Does it succeed on the first try, or does it require frequent manual intervention and extensive customization? This is a measure of efficiency.
The fundamental difference from traditional software is that the direct user shifts from a human to an AI, and the goal changes from supporting a wide range of needs out of the box to supporting flexible needs after customization. To maximize this generative potential, what we deliver is not a traditional, passive software library for developers to call, but a "Generative Kernel." It's a toolkit designed for an AI to use. Based on my firsthand experience, it generally includes the following three parts:
- Core Kit: This is the foundation of the generative kernel, providing irreplaceable core capabilities. For IKEA furniture, this would be the chair legs and seat mentioned earlier.
- Guiding Knowledge: Unlike traditional documentation written for humans, this is a knowledge system designed for an AI. It could even be a search engine itself (e.g., provided as an MCP tool for the AI to search documentation). When the AI is working, this knowledge is directly injected into its context window to guide code generation. This knowledge can be very detailed, including design philosophy, best practices, common pitfalls, and more. While it might take a human days to read a book, an AI can process it in seconds. For IKEA, this might be a 100-page instruction manual, not for a person, but for an assembly robot.
- Leverage Toolkit: For tasks that an AI can understand conceptually but finds tedious and error-prone to implement (like calculating coordinates for a complex UI layout), we don't require the AI to generate it from scratch. Instead, we can provide a high-level tool (like a layout engine similar to Mermaid). This essentially transforms uncertain, low-success-rate tasks into deterministic ones, boosting the AI's generation efficiency at critical bottlenecks. For IKEA, this would be the Allen key. A robot could use its arm to tighten screws, but a dedicated tool lets it do the job faster and better.
Let's look at a specific example: the payment platform Stripe. Anyone who has worked with payments knows how complex it is to integrate Stripe: business logic, security considerations, and front-end/back-end coordination all have to be taken into account, making the integration process painful. If Stripe wanted to create a development kit for UGS, its generative kernel would also need to include these three parts:
- Its Core Kit would be Stripe's current payment API. Its ability to handle bank settlements is irreplaceable and constitutes its core value.
- The Guiding Knowledge would be a set of engineering best practices, such as how to protect security and privacy and how to build a front-end that ensures a good user experience.
- The Leverage Toolkit could be a program where a user inputs their desired subscription plan in JSON, and it automatically creates and configures the SKU, guaranteeing 100% correctness.
With this foundation, a user could tell Cursor, "I want to integrate with XX Stripe account, implement a 7-day free trial, and then charge $30 per month." Cursor could then write the code, test and iterate on its own, and complete the Stripe integration. This is software delivery in the UGS era.
The Shift in Methodology - How
The fundamental difference in goals and form dictates that the software engineering for UGS will also differ from traditional software engineering in its implementation, even requiring a new set of design principles.
Traditional API design is geared towards human developers, with its core principle being abstraction for protection—hiding complexity, providing a clean interface, and preventing user error. In contrast, AI-native design is for AI, and its core idea is the opposite: Aggressive Transparency, or maximizing the information provided. This is because a human might be intimidated or overwhelmed by hundreds of lines of error messages, but an AI won't be. It can dive straight into the source code without any psychological burden, figure out the problem in seconds, and continue iterating. Sufficient error information is what allows the AI to self-correct.
Let me give three specific examples:
-
Provide Fine-Grained, Raw Feedback
Traditional APIs typically catch a low-level error and throw a high-level, abstract exception. This is fatal for an AI's agentic workflow. The effectiveness of an AI relies on a try-feedback-correct loop. Vague error messages like "Operation failed, please try again later" break this loop for both humans and AI, leaving them with no path forward.
Therefore, for AI-native software, we must provide raw error messages rich with technical details. When wrapping exceptions, preserve the full context. For example, it's better to rethrow a
ConnectTimeoutErrorwith a stack trace than to repackage it as a genericAPIFailureError. With the former, the AI knows immediately that a specific step timed out; with the latter, it has to infer the underlying cause from vague natural language, which is far less efficient. Fine-grained, raw feedback is fundamental to improving generation efficiency and intent fidelity. -
Expose Fine-Grained Control
To reduce the learning and misuse costs for humans, traditional API design often hides low-level, fine-grained interfaces. But this constraint doesn't apply to AI, which can read 100 pages of documentation in three seconds, making its learning cost almost zero. On the contrary, these low-level interfaces are what directly guarantee the expressive range of the generative kernel. When high-level abstractions fail to meet a user's long-tail needs, the AI can use these fine-grained interfaces to freely combine and fine-tune, creating solutions that standard interfaces cannot achieve.
-
Deliver Sufficiently Detailed Knowledge
Documentation for traditional software is written for humans; it's an external reference to the code, often seen as secondary. But the guiding knowledge within a generative kernel is written for an AI; it is part of the deliverable itself—a first-class citizen. This is because best practices and design philosophies that once took developers years of experience to internalize can now be systematically encoded into prompts and delivered as part of the kernel. Imagine the difference in code quality written by an AI that has "read" Effective C++ versus one that has not. This knowledge is a powerful lever for improving generation efficiency and intent fidelity.
Conclusion
So, back to the original question: should we abandon the DRY principle?
The answer is no, but its scope of application has fundamentally changed. We should still strive to avoid repeating ourselves in our core capabilities, but we allow, and even encourage, the AI to engage in meaningful repetition when generating the final application to meet personalized needs.
This paradigm shift to UGS will ultimately reshape the role and value of developers. Our core job will no longer be to exhaust all possible requirements and write a comprehensive, finished product. Instead, it will be to design an elegant, powerful, and transparent kernel that provides the broadest possible stage and the finest possible tools for the AI's creativity.
Of course, all of this is still in its very early stages. We need new tools to test and distribute these generative kernels. How do we systematically evaluate the generative potential of a kernel? What will the business models surrounding it look like? There are no ready-made answers to these questions, but they define the new frontiers that AI-native software engineering must explore.
We are moving from building software to building the potential for software.
Comments