Separating concerns to speed up AI coding
When coding with AI, the primary speed constraint is your own rate of review. AI can produce code at a huge rate, but the result can differ from what you wanted. That means that, at the very least, you have to inspect what the output is (even if you don’t care about the code).
This review involves you opening the app, going to the relevant pages, clicking around to see if it looks like what you want, and then making iterative corrections.
While you are doing this, the AI is mostly idle, waiting for you to finish. Even if you do things in parallel, it all piles up waiting for you to review.
Here is a better strategy:
Explicitly design your code to run in parallel for AI coding.
A standard architecture like MVC is actually all mixed up - you have an auth model beside another unrelated model like a todo model. The separation is conceptual - a model is one thing, the thing that drives the model (the controller) is another thing, and when you are in each, you can mentally map what they do. It’s designed for humans.
The AI does not really need this. What is of more importance to the AI is modularisation - it should have auth as a separate, standalone unit compared to todo. All the files for auth should be encapsulated, almost like auth were its own library. What happens then is that auth can be built, tested and iterated upon independently of the todo module. So both can run in full parallel mode.
And now a powerful tool can be introduced - the CLI version of the app. If you have a CLI version, a feature can be built and tested deeply in the CLI version, and this can happen almost autonomously, as the AI will be getting live feedback and can autonomously add traces to figure out what is happening.
The UI then is layered on top of this functionality, and since it required human-in-the-loop, it is the slowest of all, but importantly, it does not slow down the development or testing of the core features.
In C++, here is how a simple interface can look like:
- modules
- auth
- iauth.h
- auth_callback.h
- auth.h
- auth.cpp
- todo
- itodo.h
- todo_callback.h
- todo.h
- todo.cpp
- auth
- cli
- cli.cpp
- cli_test.sh
- ui
And the classes would look this way:
// IAuthCallback.h class IAuthCallback { public: virtual ~IAuthCallback() = default; virtual void onAuthResult(bool success, const std::string& message) = 0; };
// IAuth.h class IAuth { public: virtual ~IAuth() = default; virtual void Login(const std::string& username, const std::string& password, IAuthCallback* callback) = 0; virtual void Logout(IAuthCallback* callback) = 0; };
Each module is completely decoupled from the rest of the app, and has a single standard and documented interface.
With this, your cli is used by the ai for rapid self-review of work, and takes little of your own review time, while you can be more involved in the ui review.