Last week, while writing a simple systemd unit file for a backend service of my side product, I automatically opened Gemini Flash in my browser instead of the usual man systemd.service command. The assistant provided the structure I needed in seconds, but this reflex made me pause: Are AI code assistants truly increasing my productivity, or are they unknowingly creating a dependency that dulls my fundamental knowledge? This question has been one of the topics I’ve pondered most recently.
On one hand, there are incredible benefits like rapid prototyping, auto-completing boilerplate code, and instantly learning how to use an unfamiliar API. On the other hand, there are concerns about the quality of AI-generated code, security risks, and most importantly, the possibility of our problem-solving muscles as developers weakening over time. In this post, I will share my personal experiences and observations on this dilemma.
How AI Code Assistants Work and What They Bring to Me
AI code assistants are essentially large language models (LLMs) trained on massive codebases. They use the context I provide (existing code, comments, file names, etc.) and my prompt to predict the next logical piece of code. When writing a PostgreSQL query, I don’t need to remember the table schema, or when defining a FastAPI endpoint, instead of getting lost in the documentation to find the correct decorator, the assistant brings the suggestion to me with a few keystrokes.
Their biggest contribution for me has been automating repetitive and mentally draining tasks. For example, when designing a new operator screen in a production ERP, instead of manually writing CRUD endpoints for the backend and basic form components for the frontend, I can ask the AI for a draft. This saves me time and allows me to focus on the core business logic. I can even instantly get commands on how to set a specific eviction policy in Redis, which is a great convenience for details I use frequently but don’t always keep in mind.
Code Quality and the “Copy-Paste” Trap: A Real Risk?
The quality of AI-generated code has always been a question mark for me. A solution that looks correct at first glance might actually lead to performance issues, security vulnerabilities, or maintenance difficulties. When I ask AI for help with a PostgreSQL query, it usually does a great job for simple SELECT statements. However, when complex JOINs, subqueries, or window functions are needed, it can sometimes generate inefficient queries that create N+1 query problems, use incomplete indexes, or lead to WAL bloat.
Recently, in a client project, I found a simple SQL injection vulnerability in a Python code generated by AI. It had concatenated values directly with an f-string instead of using a parameterized query. Such errors can easily be overlooked, especially when rapidly prototyping, and can pose serious security risks in a production environment. Even when creating fail2ban rules, I’ve noticed that the regexes suggested by AI can sometimes be too broad or too narrow, requiring me to manually revise them based on patterns from my own audit subsystem logs. This situation reminded me once again how crucial it is to review every output from AI with a critical eye.
Productivity Boost: Speed and Repetitive Tasks
The biggest promise of AI code assistants is undoubtedly increased productivity. This promise clearly manifests itself, especially in repetitive, tedious, and boilerplate code writing tasks. The time I spend creating a simple data table or form component in a Vue or React frontend has been cut in half thanks to AI. AI can often generate clean and readable code blocks that adhere to the framework’s latest best practices. This is especially valuable when starting a new project or adding a new module to an existing one.
For example, when creating a basic .gitlab-ci.yml or .github/workflows file for a CI/CD pipeline, I can ask the AI for a draft by specifying the language and framework structure of my current project. This way, instead of writing build, test, and deploy stages from scratch, I can integrate my own rolling deploy or blue-green strategies on top of the basic structure provided by AI. This significantly reduces not only writing time but also the time spent reading documentation and searching for the correct syntax. Since I use Docker Compose-based deployments on my own servers, such automations are life-savers for me.
Dependency Syndrome: Knowledge Loss and Critical Thinking
As tempting as productivity gains are, the risk of developing a dependency on AI assistants always lingers in the back of my mind. Once upon a time, when I needed to write a complex Linux command, I would pore over man pages, try different parameters, and ultimately learn every detail of that command when I found a working solution. Now, I ask AI, “Find the 10 largest files in the file system and sort them by size,” and I directly copy the output. While this solves my immediate problem, it causes me to miss the opportunity to learn the nuances of fundamental commands like find, du, sort.
This situation can lead to the weakening of our critical thinking and problem-solving muscles. When faced with a VLAN tagging issue, in the past I would analyze tcpdump outputs, check switch configurations, and step-by-step find the root cause. Now, when I ask AI, “How to fix a VLAN tagging issue?”, it provides general solutions. However, subtle details like MTU/MSS mismatch or BGP configuration errors causing routing flaps can only be understood through in-depth investigation. AI cannot yet provide this depth of analysis, so losing our fundamental knowledge could leave us helpless in the face of more complex problems.
Effective Working Methods with AI Assistants: Prompt Engineering and Verification
To get the most out of AI code assistants, you need to treat them like a “junior assistant.” That is, you should always keep them under supervision, verify their output, and most importantly, guide them by asking the right questions. This requires a skill called prompt engineering. The more specific and contextually rich a prompt you provide, the better results you will get.
In my own experience, instead of directly telling the AI “write this for me,” it has been more productive to use it in the form of “in this context, with these requirements, list possible solutions and explain the trade-offs of each.” For example, when I have a performance issue in PostgreSQL, instead of directly asking AI “tell me how to speed it up,” I ask, “the EXPLAIN ANALYZE output for this query is this, the table schema is this, the indexes are these. What are the potential optimization strategies, which of B-tree, GIN, or BRIN indexes might be more suitable and why?” This way, I learn not only a solution from AI but also the advantages and disadvantages of different approaches.
Future Perspective: Evolution of the Developer Role
AI code assistants will establish a permanent place in the software development world. This will inevitably lead to the evolution of the developer’s role. Instead of merely being a “coder,” we will increasingly become “system architects” or “problem solvers.” While AI generates boilerplate code, simple functions, or even basic microservice skeletons, we will focus more on high-level architectural decisions, complex business logic integrations, and the implementation of advanced patterns like event-sourcing or CQRS.
My experiences in production ERP have shown that software architecture is mostly about organizational flow, not just software. AI can code this flow, but designing the flow, understanding the needs of different departments, correctly using transaction outbox patterns, or analyzing the effects of eventual consistency on business processes will still require human intelligence. Deciding whether to use logical replication or physical replication in PostgreSQL, determining read replica routing strategies, or optimizing partition strategies based on workload are areas that AI cannot yet fully undertake.
In the future, as developers, we must learn to use AI as a “co-pilot.” This means not just copying and pasting the code AI generates, but also finding its errors, identifying its weaknesses, and guiding it to produce better solutions. This evolution will direct us towards more creative, strategic, and higher value-added work. Perhaps one day AI will flawlessly generate auditd rules or SELinux/AppArmor profiles for us, but understanding the real-world implications and edge cases of these profiles will still fall to us.
Conclusion: A Balanced Approach Between Productivity and Dependency
The productivity gains that AI code assistants bring to our software development processes are undeniable. They save us time in daily repetitive tasks, help us adapt to new technologies faster, and accelerate prototyping processes. While working on the AI application architecture for my own side products, I see how critical prompt engineering and RAG patterns are. I even aim to get more reliable answers from AI with multi-provider fallback strategies like Gemini Flash, Groq, and Cerebras.
However, we must not ignore the potential risk of dependency on these tools and their possibility of dulling our critical thinking abilities. My clear position is to use AI as a tool, not as an authority. Questioning every output, verifying it, and maintaining a solid foundational knowledge becomes the most important responsibility of a modern developer. AI can give us speed, but in-depth expertise and problem-solving skills are still our most valuable assets. As long as we maintain this balance, AI code assistants will truly serve as a productivity engine.