I started experimenting with Claude Code a while ago. I am not the first person to make this observation, but thinking of Claude Code as an early career developer whom one is mentoring and needs to guide to a solution is a good mental model for it. It is pretty impressive in what it can do.
Asking it to produce something the size of what one would want to see in a code review from an early career developer produces good results, far faster than I could write myself, at a cost of a few cents.
For example:
Add a command line utility written in Go in cmd/adduser. It takes command line arguments for email, phone, imsi, realm, remsim, gpp_hostname, ns, slack_app_token, slack_channel_id, and smtp_list. It encrypts the slack_app_token, slack_channel_id, and smtp_list using the code in internal/db/encryption.go. It opens a connection to the database using the code in internal/db/server.go, and adds a new row to the accounts table using the command line arguments it was given.
This resulted in a quite functional command line program which did what I asked.
func main() {
var (
email = flag.String("email", "", "Email address (required)")
phone = flag.String("phone", "", "Phone number (required)")
imsi = flag.String("imsi", "", "IMSI (required)")
realm = flag.String("realm", "", "Realm (required)")
remsim = flag.String("remsim", "", "Remsim (required)")
gppHostname = flag.String("gpp_hostname", "", "GPP hostname (required)")
ns = flag.String("ns", "", "NS (required)")
slackAppToken = flag.String("slack_app_token", "", "Slack app token")
slackChannelID = flag.String("slack_channel_id", "", "Slack channel ID")
smtpList = flag.String("smtp_list", "", "SMTP list")
)
//...omit the rest but it was straightforward code...
Unit Testing
Claude Code doesn't seem to produce unit tests as a regular part of its development... like some engineers I've worked with I suppose. However it can be prompted to do so and produces a reasonable result.
In cmd/forwarding create a unit test which starts a server on localhost and uses an http client to connect and POST JSON with input arguments.
In cmd/user-management create a unit test which starts a server on localhost and uses an http client to fetch /api/account/<uuid>/db
Claude Code produced a quite reasonable table-driven Go test, including creating an in-memory sqlite3 to mock the Postgres database.
+ testCases := []struct {
+ name string
+ uuid string
+ requestBody ForwardRequest
+ expectedStatus int
+ setupDB func(*sql.DB, string)
+ }{
+ {
+ name: "successful forward",
+ uuid: testUUID,
+ requestBody: ForwardRequest{
+ Sender: "test@example.com",
+ Received: "2023-12-01T10:00:00Z",
+ Content: "test message",
+ },
+ expectedStatus: http.StatusOK,
+ setupDB: func(database *sql.DB, uuid string) {
+ slackToken, _ := db.Encrypt("test-slack-token")
+ slackChannel, _ := db.Encrypt("test-channel")
+ smtpList, _ := db.Encrypt("test@smtp.com")
+
+ query := `INSERT INTO accounts (id, account_number, email, phone_number,
+ imsi, realm, remsim, gpp_hostname, ns, slack_app_token,
+ slack_channel_id, smtp_list)
+ VALUES (?, 1001, 'test@example.com', '+1234567890',
+ '123456789012345', 'test.realm', 'test-remsim',
+ 'test-gpp', 'test-ns', ?, ?, ?)`
+ database.Exec(query, uuid, slackToken, slackChannel, smtpList)
+ },
+ },
Unwise Approaches
Attempting to get Claude Code to generate larger systems with less guidance didn't go as well. What it produced was functional and quite impressive, but unwise.
I wanted to try out an admin panel with a login link sent to an email address. Not suitable for all environments, but sufficient for many services which rely on the user's email.
In the admin sub-directory, generate a web user interface for an admin console using typescript and react, with a backend server written in Go.
The login screen has a text box to enter an email address. When the Submit button is pressed, the backend server should generate a 128 bit random string and use os.exec to run an email.sh process. The backend server should redirect the user to an interstitial page which says "Please click the login link sent to <email address>."
Once logged in, the main page has ...
Claude Code generated a quite functional admin console. One could submit an email address and it would fork the script to send email. It maintained a map of pending login tokens in the Go backend. When one clicked the link in the email the backend would respond with ok it it found that token in its active table, otherwise failure. Quite exhilerating to see all of that work within a couple minutes of starting on it.
However this means the client code, itself, was deciding the success or failure of the login link. If it got an ok from the backend, it would proceed to the URL for the admin panel. The backend code would serve up whatever it was asked for, there was no enforcement in the backend.
Anyone capable of understanding the client JavaScript could figure out the URL of the admin panel for any user. The login link only provided the illusion of protection. It was trivial to bypass.
One can observe that Claude Code generated exactly what I told it to, which is a fair observation. One might also observe that Claude Code just regurgitates its training set, meaning that human developers have done similar things in large numbers. This is also a fair observation.
Nonetheless it reinforces that vibe coding is best used as a multiplier, not a substitute, for actual expertise.