Tech experiments, travel adventures, and code explorations by Robert Taylor
by Robert Taylor
During my recent projects, I’ve been experimenting extensively with AI tools like Claude and ChatGPT for code generation. Here’s what I’ve learned about the strengths, limitations, and best practices for AI-assisted development.
NOTE: This post was generated with Claude, based on the totality of the project described earlier, Building a Personal VPN Service with AWS, Terraform, and iOS
My typical workflow now involves a collaborative process with AI:
This approach has dramatically accelerated my development process, especially for projects with standard patterns and boilerplate code.
After building several complete projects with AI assistance, I’ve found these tools excel at:
AI tools are exceptional at generating repetitive, structural code:
// Generated by Claude - A standard SwiftUI view with common patterns
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
@State private var isLoading = false
var body: some View {
NavigationStack {
List {
ForEach(viewModel.items) { item in
ItemRow(item: item)
}
}
.navigationTitle("Items")
.toolbar {
Button("Add") {
viewModel.addItem()
}
}
.overlay {
if isLoading {
ProgressView()
}
}
}
.onAppear {
loadData()
}
}
private func loadData() {
isLoading = true
Task {
await viewModel.fetchData()
isLoading = false
}
}
}
AI models know patterns across multiple languages and frameworks, making them valuable for full-stack development:
AI tools excel at creating clear documentation, including:
Despite their capabilities, I’ve encountered several limitations:
AI tools often struggle with higher-level architectural decisions that require deep domain knowledge. For my VPN project, I needed to:
These decisions required human judgment based on experience.
When generating code for multiple components, I found AI tools sometimes created inconsistent interfaces. I needed to:
Generated code often handles the happy path well but misses edge cases:
# Original AI-generated code - missing error handling
def get_vpn_status(instance_id):
response = ec2_client.describe_instances(InstanceIds=[instance_id])
state = response["Reservations"][0]["Instances"][0]["State"]["Name"]
return state
# After human refinement
def get_vpn_status(instance_id):
try:
response = ec2_client.describe_instances(InstanceIds=[instance_id])
if not response["Reservations"]:
return "unknown"
state = response["Reservations"][0]["Instances"][0]["State"]["Name"]
return state
except Exception as e:
logger.error(f"Error getting VPN status: {str(e)}")
return "error"
Through my experiments, I’ve developed these best practices:
The quality of generated code directly depends on prompt quality:
The prompts used and responses given which produced project are published in the project repo: TerrorTunnels: GenAI Chat Transcripts
Treat AI-generated code as a first draft:
Always review generated code for:
For my VPN control project, I used AI for:
However, I needed to manually:
As AI tools continue to evolve, I see several trends emerging:
AI-assisted development has transformed my workflow and productivity. While these tools can’t replace human judgment and experience, they dramatically accelerate the implementation process and handle routine aspects of development.
For developers looking to incorporate AI into their workflow, I recommend starting with smaller components, developing good prompt engineering skills, and maintaining a balance between AI assistance and human oversight.
Have you experimented with AI-assisted development? I’d love to hear about your experiences in the comments!
tags: ai - development - claude - chatgpt - coding