This article contains links to some of my past articles, along with AI-generated historical facts and analysis that support it.
Being a Lazy Programmer
In “Code Complete (2nd edition)”, chapter 33.7:
33.7. Laziness
Laziness manifests itself in several ways: Laziness: The quality that makes you go to great effort to reduce overall energy expenditure. It makes you write labor-saving programs that other people will find useful, and document what you wrote so that you don't have to answer so many questions about it. , Larry Wall * Deferring an unpleasant task * Doing an unpleasant task quickly to get it out of the way * Writing a tool to do the unpleasant task so that you never have to do the task again Some of these manifestations of laziness are better than others. The first is hardly ever beneficial. You've probably had the experience of spending several hours futzing with jobs that didn't really need to be done so that you wouldn't have to face a relatively minor job that you couldn't avoid. I detest data entry, and many programs require a small amount of data entry. I've been known to delay working on a program for days just to delay the inevitable task of entering several pages of numbers by hand. This habit is "true laziness." It manifests itself again in the habit of compiling a class to see if it works so that you can avoid the exercise of checking the class with your mind. The small tasks are never as bad as they seem. If you develop the habit of doing them right away, you can avoid the procrastinating kind of laziness. This habit is "enlightened laziness", the second kind of laziness. You're still lazy, but you're getting around the problem by spending the smallest possible amount of time on something that's unpleasant. The third option is to write a tool to do the unpleasant task. This is "long-term laziness." It is undoubtedly the most productive kind of laziness (provided that you ultimately save time by having written the tool). In these contexts, a certain amount of laziness is beneficial. When you step through the looking glass, you see the other side of the laziness picture. "Hustle" or "making an effort" doesn't have the rosy glow it does in high-school physical education class. Hustle is extra, unnecessary effort. It shows that you're eager but not that you're getting your work done. It's easy to confuse motion with progress, busy-ness with being productive. The most important work in effective programming is thinking, and people tend not to look busy when they're thinking. If I worked with a programmer who looked busy all the time, I'd assume that he was not a good programmer because he wasn't using his most valuable tool, his brain.
Over the years, I have written a few non-trivial code generators, and the recent ones include:
- Strongly Typed Client API Generators (webapiclientgen) generate strongly typed client APIs in C# .NET and in TypeScript for jQuery and Angular 2+ from ASP.NET (Core) Web API.
- Strongly Typed OpenAPI Client Generators (openapiclientgen) generate strongly typed C# and TypeScript client codes from Open API / Swagger definitions supporting jQuery, Angular, AXIOS, Fetch API, Aurelia and Angular Strictly Typed Forms.
The driving force is that I want to deliver more business value through less work. I am a lazy programmer who easily gets tired of writing repetitive code, even if I’m paid to do so, particularly HttpClient code in C# and AJAX calls in JavaScript.
The code left by diligent programmers
I am weary of inheriting legacy codebases authored by diligent programmers but burdened with overly complex architecture and software designs. In many cases, the architects and developers did not fully appreciate the inherent capabilities of the underlying development platform, nor did they apply fundamental computer science principles such as high cohesion and loose coupling effectively.
In one notable example, designed by an A-list consultant firm in town, an XML transformation pipeline performed five rounds of XML DOM schema validation, despite the fact that XML serialization alone could have solved the problem far more cleanly and efficiently. .NET (Framework) can generate assemblies at runtime or build time for both XML readers and writers directly from XML schemas, making much of that validation logic redundant. And the performance of that part of the data transformation became at least 20X faster, with much less processing power and memory consumption. This was not the only example I had seen of using cutting-edge technologies the dirty way, though not entirely wrong, since the legacy, fresh, and dirty code was “working”.
These experiences put me in a good position to discuss how AI can assist software development, and where it falls short, grounded in the mid-term and long-term, and exploring real-world systems, tools, and trade-offs rather than abstract theory alone, even though I am not an AI expert. However, I look forward to becoming proficient in using AI to improve my overall productivity and ROI. Tools, 3rd-party libraries, code generators, and AI code agents are all good only when they help me reduce the consumption of my precious brain power and memory. If I have to consume more brain power and memory, this means either that this assistance is bad or that I have used it the dirty way.
These days, most programmers in the commercial world are still using 3GLs like C++, Java, C#, Python, Dart, Swift, and JavaScript, etc. Therefore, in the following chapters, I will mostly focus on examples of 3GL and general-purpose programming languages, and C# .NET. If you are a Java or C++ programmer, you may find similar examples through your own research.
The following is summaries of various technical resources that help lazy programmers.
Resources for Lazy Programmers before AI
This chapter provides quick highlights of the resources to help you review what you have learned or begin learning, with linked articles generated by AI.
Code Generators
- C++ Template
- In .NET, the runtime or the compiler could generate serialization assemblies for forward only non-cache serializers. And this is just one of many framework-managed code generators in .NET.
- Model-driven code generators.
- …
Hints:
- Java has similar categories of framework‑managed code generation features, but they are fewer, more fragmented, and architecturally different from .NET’s. Many are externalized.
Built-in Framework Modules
.NET Framework and .NET Core include a lot built-in framework modules that app programmers could utilize in most business applications:
- Middleware infrastructure
- ASP.NET Core MVC pipeline
- Model binding system
- Validation system
- Action / result / exception filters
- Routing and endpoint dispatch
- Formatters (JSON, XML, etc.)
- …
Utilizing those built-in module wisely could make your app code short and simple, so easy to maintain.
.NET and Java provide runtime optimization. And generally clean code can help the runtime to do better optimization.
Hints:
- Java has small amount of built-in framework modules, while most live outside the JDK, in standardized APIs (Jakarta EE) or third‑party frameworks (Spring, Quarkus, etc.).
Remarks:
- Python is a darling programming language in the AI landscape; however, it lacks framework-managed code generation and built-in framework modules, and this is a deliberate design choice. The overall design choices of Python contribute to it becoming the dominant language in the AI landscape, in particular for meta-programming mediated by AI.
App Generator
These days, when googling “Application Generator”, the top results are basically all AI app generator or builder. I remember seeing a lot of advertisements for application generators in the 1980s, generating business applications for DOS or Windows. For example, you would input a few business constraints, add some further configuration and optional customization, and the generator would then generate a Northwind-like application. Here’s a summary about app generators before LLMs AI becoming popular.
Model to Code
Rather than generating the whole app, “Model to Code” offers a more flexible and generic solution for application programmers: realizing implementation from a high-level design with UML or similar tools, and maintaining an “active model” where changes in the model instantly update the code, and vice versa f I have come across ModelMaker, and liked it for a while. ModelMaker was a UML‑style modeling and refactoring tool built specifically for Borland Delphi’s Object Pascal. It supported:
- Drawing UML‑style class diagrams
- Generating Delphi code from those diagrams
- Reverse‑engineering existing Delphi code into UML diagrams
- Refactoring and restructuring Delphi projects
ModelMaker has faded into history, and these days tools like Visual Paradigm support generating Java, C++, C#, etc. from UML diagrams.
Rather than starting from UML diagrams, Windows Workflow Foundation offers a form of “Model‑to‑Code”, more exactly, a model‑driven execution system where the model is the program. For some reason, MS discontinued WF. Nevertheless, there are still alternatives around for such classic Model-Driven Development (MDD).
4GL, DSL and 5GL
“The term 4GL was first used formally by James Martin in his 1981 book Application Development Without Programmers to refer to non-procedural, high-level specification languages. Some researchers state that 4GLs are a subset of domain-specific languages.”.
Application Development Without Programmers
Oh yeah, isn’t this literally the main intent behind why companies are pushing AI code agents nowadays?
Nevertheless, I happened to use dBase, Visual FoxPro, PowerBuilder, and Omnis Studio in the ’80s and ’90s. In my observations, 4GLs may reach bottlenecks as the business grows and changes:
- As the business needs to deal with more functional and technical domains, the 4GL environment can barely keep up, due to business growth and changes in the business and tech landscapes.
- The 4GL environment is discontinued by the vendor.
According to Wikipedia, Domain-specific language is a computer language specialized to a specific application domain. This is in contrast to a general-purpose language (GPL), which is broadly applicable across domains. There are a wide variety of DSLs, ranging from widely used languages for common domains, such as HTML for web pages, down to languages used by only one or a few pieces of software, such as MUSH soft code.
AI Code Agents
In the last 2 or 3 years, there has been a bombardment of academic papers, marketing materials, and criticism around AI code agents. I am at the consumer end of AI code agents, and here’s my observation: The output of traditional code generation is predictable and deterministic, and can be compiled and used immediately without modification, while AI-generated code, particularly through Python meta-programming mediated by AI, is not so predictable or deterministic, and often contains language syntax errors and other logic errors.
I asked M365 Copilot about my observation, and here’s the analysis returned about “Traditional Code Generators v.s. AI Code Agent”. And you are very welcome to ask a similar question to your favorite AI agents, or even better, ask real AI experts.
Keeping the shortfalls of AI code agents in mind, you as a programmer are in a better position to get the best from those agents and deliver more business value through less work.
You’ve probably heard: “Scrum: The Art of Doing Twice the Work in Half the Time.” In my observations, practices done in the name of Scrum have often resulted in doing twice the waste in half the time, since most of the work involved in value delivery is waste, due to various ScrumBut practices and factors. Overall, it’s not too bad if the waste is inevitable.
And if you’re not careful, mindful, and cautious enough, using an AI code agent could result in delivering 10 times the technical debt in 1/10 of the time, since the generated code could be severely overcomplex and overly lengthy.
Are you confident that AI is able to reduce the pure technical debts it created?
Are you sure you don’t need to care about technical debts in most real world business applications?
In my observations, AI code agents are generally good at doing “Plus”, adding tons of code that’s politically correct regarding SOLID and design patterns, etc., just like a junior developer armed with all the academic knowledge of software engineering but without the real-world experience to make trade-offs according to business context. And currently, these AI code agents have near zero capability of doing “Minus”, removing code and simplifying design.
How AI has been helping me?
There are reasons why I have listed many traditional codegen resources that predate LLM AI code agents. Before AI code agents became a thing, I often said the following statements or examples:
- Having a working solution won’t satisfy me or the business, and I aim to deliver twice the value through half the work.
- In software development, for one functional requirement there could be an unlimited number of working solutions, a few good, mostly dirty. Generally, the simplest one is the most suitable for the business.
- In software development, for one functional requirement, there could be an unlimited number of working designs, a few good, mostly dirty. And from one design, there could be a few working implementations, one or two good, the others dirty.
- The key to finding the most suitable solution for the business is to establish sufficient two-way communication with the business and to put significant effort into that communication.
- As a lead developer on a green-field project, I typically spend 1/3 down to 1/4 of my billable hours on coding (including testing), and the rest on thinking, studying, and researching, as well as talking to the business, clients, and end users. So the LoC is typically 1/2 to 1/5 of the LoC written by other developers on the same technical stack, and I often deliver a simpler design with fewer dependencies on 3rd-party components.
- As a lead developer on very legacy projects left by predecessors, I typically spend much more time cutting code than writing it. In one case of maintaining a legacy ERP system, after three and a half years, I had added 500 lines of code and removed 5,000 lines of code, resulting in far fewer bug reports every week and slightly better performance. Rather than spending most of my effort debugging, I tackled defects which are the nests of bugs.
- Technical debt is essentially management debt. A typical symptom is that both the tech people and the business people lack commitment to iterative two-way communication, and the end result is often over-complex architecture, over-complex software design, and overly lengthy code as well as long hours in debugging and fixing customer reported bugs.
How Visual Studio and alike with AI has been helping me?
- AI-generated DocComment. 80% hit rate.
- AI suggestion of the next paragraph of code. 40% hit rate for long code, depending on the subject, and 70% for short, repetitive code.
Remarks:
- The hit rate is based on my impression, not statistics. However, it represents how comfortable I feel with the AI’s correctness, overall, it’s subjective.
- I have been mostly developing complex business applications and development tools, so my comfort zones may be different from yours.
- I can’t help thinking the VS dev team is working on better scaffolding with AI. So in the next major release of VS, I may just say a few prompts, and VS could scaffold a comprehensive skeleton, or even a full app. VS AI scaffolding should outperform many AI code generators out there, because VS already has comprehensive and solid scaffolding logic built in, along with many IDE accessories that assist with technical correctness.
Hints:
- Visual Studio Code with plug-ins connecting to GitHub Copilot offers similar assistance.
- Visual Studio Code with a plug-in connecting to ChatGPT Codex helps too.
- Traditional IDE assistants, like syntax checking and IntelliSense for function prototypes and DocComments, are still the most deterministically helpful.
How AI compensates my poor memory
I have always had a poor memory and could barely remember technical details except those I use actively and repetitively, but I don’t enjoy doing repetitive technical work. Look at the bright side: the IT landscape keeps changing, basically reshuffled every 2 years since the early ’70s. Therefore, this disadvantage makes me forget legacy and obsolete technologies, while I’m good at understanding and remembering concepts.
Remarks:
- This poor capability for memorizing technical details has made me look bad in job interviews during technical screening, when the interview panels asked me questions that a junior developer or a new CS/SE graduate could outperform me on.
- In the past, I accumulated my own personal knowledge-base through:
- Directory with docs
- Google Notes (discontinued by Google)
- Evernote
-
Personal Wiki
-
Google search is my alcoholic friend.
Likewise, AI is your alcoholic friend. You might have experienced AI mixing up old and new technical items. And when questioned, AI will try to fix itself through further research or “imagination.” You have probably come across studies about AI hallucination.
However, you can only claim AI hallucinated if you provided the right prompt. “Garbage in, garbage out” (GIGO) applies to AI prompts, though occasionally AI might point out the incorrectness of the prompt. However, you still need foundational knowledge to understand the AI’s refinement attempt on an incorrect prompt.
AI dealing with simple ad-hoc data transformation
For example:
- JSON to CSV, and vice versa, in cases existing dedicated tools couldn’t cover. Hit rate: 95%.
- Given JSON data, generate POCO classes with JsonPropertyNameAttribute. Hit rate: 90%. Weak on data types like DateTime, DateOnly, and TimeOnly. Good with currency.
- Web content scraping. After CodeProject.com was discontinued, I saved local copies of what was cached at https://web.archive.org/. To create an index page, I asked ChatGPT Codex, plugged into VS Code, to retrieve the title from a certain XPath and format it. And here you are: https://zijianhuang.github.io/codeproject/
AI for refactoring
For example:
- Migrate the automatic tests of TypeScript projects from Karma or Jest to Vitest. Hit rate: 95%
AI for scripting
For example:
- Write simple JavaScript and PowerShell 7 code for CI/CD. Hit rate: 99%.
- Craft HTML templates, and CSS/SCSS for styles and animation. Hit rate: 90%.
AI providing advice for software design and architectural design
Hit rate: 80%.
Entry level understanding of old new tech before further research and study.
Old means that the tech has been around for years, new means that I am new to it. Hit rate: 95%.
Remarks:
- In contrast, the AI response to brand new tech is weak regarding correctness.
Common algorithms
Most algorithms you learn from university courses like “Data Structures and Algorithms” have been well packaged into many development platforms such as the .NET BCL and similar frameworks, as well as third‑party components and dedicated libraries like MATLAB.
For those that are included, AI is almost 100% correct nowadays. A typical technical screening question is, for example, a three‑elevator control system.
I basically failed every technical screening involving such algorithms during job interviews, even though I taught “Data Structures and Algorithms” at university as a lecturer in my early 20s. So what was the point of doing this kind of screening when recruiting a senior developer? And what is the point in an era when LLM‑based AI can outperform any developer in the world?
Nevertheless, it is still important for developers to have systematically studied data structures and algorithms to sharpen the human brain, so they can use AI tools more effectively and achieve better outcomes.
Analysis
Ask yourself some questions:
- Can AI read between the lines? Are you confident that AI can really understand your question or prompt? Even if you have degrees in English Literature and Computer Science, are you sure you can express every piece of business content and context through a prompt?
- Do you understand that one bit can kill through a Turing machine?
- Are you sure that AI is not biased on subjects of politics and technology?
- While the literal knowledge of AI is many magnitudes greater than that of any human being on Earth, how many aspects of intelligence is AI still missing compared to human intelligence?
- Who cares, and why, if the code is long or short, clean or dirty, as long as it runs, and as long as we have fast hardware?
Flashback about software engineering before LLMs AI
Based on Robert Glass’s “Facts and Fallacies of Software Engineering”, the industry is plagued by repeating old mistakes, prioritizing coding over design, and mismanagement. Key facts highlight that quality is expensive but saves money, smaller teams are more productive, and maintenance drives costs.
Key Facts (The Truth)
- Maintenance: The majority of software costs occur after delivery (maintenance phase).
- Quality: Quality does not cost more; it actually saves money by reducing rework.
- Teams: Smaller, experienced teams are far more productive than larger, junior ones.
- Development: Errors are most commonly found in the requirements phase, not during coding.
Key Fallacies (Common Mistakes)
- “We need better tools”: Tools are often purchased but rarely used effectively.
- “Coding is the main task”: It’s actually a small part of the overall engineering lifecycle.
- “Documentation is unnecessary”: Skipping documentation leads to high maintenance costs.
- “Adding more programmers to a late project makes it faster”: This actually makes it later.
- “Estimation happens once”: Software estimation must be continuous, not just at the start.
Ask yourself, how can LLMs AI alter the key facts? or help us to avoid those key fallacies?
Common Pitfalls of Code Generated by LLM AI Code Agents
As a programmer, I have benefited greatly from AI code agents, partly because I am poor at remembering trivial technical details. So far, I have found that once I ask AI code agents to implement a non-trivial feature, no matter how detailed, formal, or simple the prompt, the generated source code is usually over-bloated in design and implementation, and the line count is typically 3–5 times what it should be.
AI-Generated Source Code vs Hand-Crafted Code
“3–5 times” sounds like a magic number to me. In several commercial rewrite projects and one competitive rewrite of an open-source tool using the same technical stack and language:
- My codebase was around 1/3 down to 1/5 the LoC of the legacy versions, which were only a few months or a year older.
- My designs were much simpler, with fewer dependencies on third-party components and less fancy DI/IoC, SOLID, and design patterns.
- Runtime performance was 20% to 50% faster.
- The end products were more reliable and robust.
Regarding the legacy codebases:
- The author of one tool was enthusiastic about SOLID and DI/IoC but apparently misunderstood high cohesion and loose coupling, using DI/IoC in the wrong places.
- The authors of the legacy commercial programs knew SOLID and design patterns well, but still applied them in the wrong places, likely due to misunderstanding cohesion and coupling and introducing overly advanced designs too early and too proactively.
Basically, these legacy codebases looked “politically correct” with respect to SOLID, but were simply over-complicated and too lengthy, resulting in slowness and excessive consumption of computing resources.
Let’s review what Robert C. Martin said in “UML for Java Programmers”. After introducing SOLID, he states:
When should these principles be applied? At the first hint of pain. It is not wise to make all systems conform to all principles all the time. You will spend an eternity imagining possible environments for OCP or sources of change for SRP, create dozens of little interfaces for ISP, and invent many worthless abstractions for DIP. The best way to apply these principles is reactively rather than proactively. When you detect a structural problem or notice a module being affected by changes elsewhere, then consider whether one or more of these principles can help. A reactive approach also requires a proactive effort to create pressure early. If you want to react to pain, you must diligently search for sore spots.
AI code agents typically apply SOLID principles proactively even eagerly, just like many human developers would, resulting in overcomplex and overly lengthy code. And AI can barely see the first hint of pain, probably because of its limitless computing power.
The characteristic of AI generated code
According to “Traditional Code Generators v.s. AI Code Agent”, AI‑generated code (including Python‑mediated meta‑programming) is:
- Probabilistic
- Heuristic‑driven
- Context‑sensitive
- Statistically inferred
- Not formally constrained
As a developer or a business person, are you so sure that you would put your business interests in the hands of an AI code agent, while also expecting human developers to quickly fix the hidden problems or technical debt generated by AI?
One bit can kill through Turing machine
I have asked AI agents to collect and summarize 12 prominent historical examples, some of which have been mentioned in various software engineering textbooks:
- Written by M365 Copilot.
- Written by Claude AI, in Markdown and Docx.
- Written by Google AI Studio, in Markdown
Summary
During software development, there are a lot of artifacts created or updated:
- Source code, the primary artifact.
- Verbal conversations.
- Written conversations like user stories and comments in issue tracking.
- Doc comments.
- Documentations.
- Localization.
- …
AI can help a lot in the areas where LLM AI’s quality characteristics may well satisfy our needs, while our flesh-and-blood brains can review and refine the output from AI, because our literal expressions in words have similar characteristics.
But for generated source code that will be built into machine code and run on a Turing machine, this is a different landscape, one involving a much higher magnitude of operational risk and significant overhead during review and refinement.
Understand the advantage and the shortfalls of AI code agent:
Do use AI code agents for:
- Areas where you feel comfortable with an 70-80% hit rate.
- Domains where approximate results are acceptable, like UI design, layouts, styles, and animation effects.
- Generating the whole end products where approximate results are acceptable, like article generators, trends prediction, chatbot, and photo/video creation/refinements etc.
- Advice on software design and architectural design.
- Prior art.
Be cautious when using AI coding agents for:
- Areas where you are uncomfortable with a success rate below 70-80%, because the remaining 20-30% may ultimately require more effort from you.
- Areas where a single mistake can be catastrophic.
AI code agents + traditional code generators + framework‑managed code generation features are a decent combination for productivity, resulting in less stress.
One key factor to examine: Do you, as a senior software developer, have to use more brain power and memory every day in the short term, mid-term, and long term for a similar piece of product to deliver?