In my normal programming work, I use AI tools in a very focused way that I've been told is "wrong," even though I'm more productive, but there we are. I'm not spewing out 20x my previous output, so maybe that's it. I'm an engineer, so when I work with an LLM, I do engineering. Shocking, I know.
I work incrementally, in small batches, with a well-defined architecture guiding the process. (People talk nebulously about "guardrails." Having a coherent AI-friendly architecture is an important one.) I do not let the AI design the program for me. I build thin vertical slices with domain value, not random features. I focus on quality, not output volume.
I tell the LLM what the code should do, of course, but I also tell it how to structure the code—how it fits into the architecture, what the APIs or messaging looks like, etc. I don't simply describe the surface behavior of a "feature" and expect the AI to do all the work under the covers. Instead, I ask the AI to write small, manageable, focused, black-box testable components that fit into an overall system architecture that it does not control. The architecture comes first, and then I tell the LLM to implement it one component at a time. (I should add that some architectures work better than others in this context. DDD nested aggregates and entities have worked pretty well for me, as have message-based components with hardened perimeters.)
I'll admit that I often don't give the output more than a cursory glance, but I'm a fanatic about testing. (There's another "guardrail.") I don't let the AI write my tests. When I first started doing this, I found that the AI would modify the tests so that the incorrect code it generated would pass. That's not testing. Also, the AI-generated tests tested the wrong things—e.g., small implementation details, not domain-level behavior.
I'm a big TDD guy, so I write my tests first and then tell the AI that the code it creates must pass them. When I do use the LLM, I'll specify the test in Gherkin format, and the results are small enough to review manually. To me, manual review of the tests is essential. There's no room for AI ambiguity in a test.
I've been told that I'm not leveraging the full capabilities of the AI by working this way, that I should just describe features or modifications and have the AI do all the work. I am, nonetheless, more productive than when I don't use the LLM, and don't seem to have the problems (e.g., lurking bugs, fragility in the face of scaling, overwhelming complexity, etc.) that seem commonplace with other approaches.
My measure for productivity is time to complete a story, which has gone down. I couldn't care less about output volume. When working in the small like this, with the work constrained by component boundaries, the LLM cannot break existing code when it makes unrelated changes. I'm not overwhelmed by a pile of code so vast that I can't understand it.
So, maybe I am doing it "wrong," but I'm happy with what I'm doing.
I have been doing software development for nearly forty years and there is one common pattern I have seen on all successful software projects.
You get to a point near the end of the project where the number of files that need to be modified for a given change get smaller and smaller.
If your AI is modifying large number of files for small changes near the end of a project, you have a serious problem.
As the cool kids say, you are NGMI.
Juniors entering the field will still need to understand what code is. But they won't need most of the philosophy that we've been used to. The emphasis will all be on pragmatics and engineering. So they won't need to know OOP, but they will definitely need to know dependency inversion. They won't need to know functional programming, but they'll definitely need to understand purity and the costs of mutability. They won't need to know about structured programming, but they will need to understand modularity.
Situation: A web app has no end-to-end (E2E) tests.
Solution: Consider writing E2E tests in phases.
Phase 1: Smoke test - Write E2E tests that merely visit each page and assure it loads.
Phase 2: Happy path - Write E2E tests for each feature's "happy path" (the expected, common use case).
Phase 3: Unhappy path - Write E2E tests for edge cases.
Phase 1 is generally easy and provides basic confidence that the app won't blow up when simply navigated. Consider phase 2 or 3 as the team matures.
The untold history of web development:
1990: HTML invented
1994: CSS invented to fix HTML
1995: JS invented to fix HTML/CSS
2006: jQuery invented to fix JS
2010: AngularJS invented to fix jQuery
2013: React invented to fix AngularJS
2014: Vue invented to fix React & Angular
2016: Angular 2 invented to fix AngularJS & React
2019: Svelte 3 invented to fix React, Angular, Vue
2019: React hooks invented to fix React
2020: Vue 3 invented to fix React hooks
2020: Solid invented to fix React, Angular, Svelte, Vue
2020: HTMX 1.0 invented to fix React, Angular, Svelte, Vue, Solid
2021: React suspense invented to fix React, again
2023: Svelte Runes invented to fix Svelte
2024: jQuery still used on 75% of websites
When you find a defect, look to the system to understand why that defect was created, then change the system so that similar defects cannot occur again. Fixing the defect is the easy, and not the most important, part.
If the AI revolution doesn't bring about productivity changes that lead us to a 4-day or even 3-day work week, then I have to wonder WTF the point of all this tech is.
#capitalism
#ACMTuringAward recipient Vint Cerf warns about ethical issues of the technology behind #ChatGPT, which "can generate plausible sounding but incorrect information even when trained on a foundation of factual material." Learn more here via @CNET : https://t.co/qLO0S14iAy #TechNews
XP never had a story about scaling, which limited its reach. I get the feeling that there is a good story to be told about helping 1000s of folks coordinate their efforts & that story starts by reducing team dependencies.
https://t.co/lKYiIdoEgH
In every case where I was “forced” to cut quality for speed it was because I offered that choice to a non-technical boss. And in every case I delivered late.
The only way to go fast is to go well.