# AI Code Assistants: Creating Efficiency or Dependency?

> Source: <https://dev.to/merbayerp/ai-code-assistants-creating-efficiency-or-dependency-4lba>
> Published: 2026-06-29 19:35:29+00:00

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.

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.

💡 Quick StartThere's a pattern I frequently use when creating a

`Docker Compose`

file. When I tell the AI, "Create a Docker Compose file with PostgreSQL 16, Redis, and an Nginx reverse proxy. Nginx should listen for the FastAPI application on port 8000," it usually provides a solid starting point. Here's a simple example:

```
# docker-compose.yml
version: '3.8'

services:
  db:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - db_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    restart: always

  app:
    build: .
    restart: always
    ports:
      - "8000:8000"
    depends_on:
      - db
      - redis
    environment:
      DATABASE_URL: "postgresql://user:password@db/mydb"
      REDIS_URL: "redis://redis:6379/0"

  nginx:
    image: nginx:stable-alpine
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - app

volumes:
  db_data:
```

This kind of skeleton eliminates the mental burden of starting from scratch and moves me directly to the customization phase. Instead of manually writing an

`Nginx reverse proxy`

configuration, I can ask the AI for a basic`proxy_pass`

setting and then add my own`rate limiting`

and`JWT`

validation patterns on top. I've observed a 15-20% speed increase in my daily workflow with this approach.

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 `JOIN`

s, subqueries, or `window function`

s 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.

⚠️ Security Risk: SQL Injection in AI-Generated CodeWe should always manually review code examples from AI. Here's an example of a

`Python`

function that AI might sometimes generate, which is vulnerable to`SQL Injection`

:

``` python
# Potentially WEAK AI-generated code
import psycopg2

def get_user_data(username):
    conn = psycopg2.connect(database="mydb", user="user", password="password", host="db")
    cur = conn.cursor()
    # Bad example: Concatenating parameters directly as a string
    query = f"SELECT * FROM users WHERE username = '{username}'"
    cur.execute(query)
    result = cur.fetchone()
    cur.close()
    conn.close()
    return result

# Value an attacker could enter: "' OR '1'='1"
# This becomes WHERE username = '' OR '1'='1' and could return all users.
```

This type of code can easily be missed by an inexperienced developer. In my production ERP, when integrating

`iSCSI`

, I always made sure to use`prepared statements`

or the ORM's own secure parameter binding mechanisms to prevent such vulnerabilities in functions handling critical data. AI can be an accelerator in this regard, but the final check should always be human.

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.

ℹ️ AI's Role in CI/CD ProcessesCreating a basic structure for a

`GitLab CI`

pipeline is significantly accelerated with AI. Here's an example of a scenario and output you might request from AI:

Prompt:"Create a`GitLab CI/CD`

pipeline for a Python-based FastAPI application. Tests should run with`pytest`

, a Docker image should be built and pushed to`Docker Hub`

when pushed to the`main`

branch. Use caching."

AI's Potential Output:

```
# .gitlab-ci.yml
image: docker:latest
services:
  - docker:dind

variables:
  DOCKER_HOST: tcp://docker:2375/tcp
  DOCKER_TLS_CERTDIR: ""
  DOCKER_REGISTRY_USER: $CI_REGISTRY_USER
  DOCKER_REGISTRY_PASSWORD: $CI_REGISTRY_PASSWORD
  DOCKER_REGISTRY_IMAGE: $CI_REGISTRY_IMAGE

cache:
  paths:
    - .venv/

stages:
  - build
  - test
  - deploy

build_image:
  stage: build
  script:
    - docker build -t $DOCKER_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker login -u "$DOCKER_REGISTRY_USER" -p "$DOCKER_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker push $DOCKER_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

test:
  stage: test
  image: python:3.10-slim-buster
  before_script:
    - python -m venv .venv
    - source .venv/bin/activate
    - pip install poetry # or pip install -r requirements.txt
    - poetry install --no-root # or pip install -r requirements.txt
  script:
    - pytest

deploy_prod:
  stage: deploy
  script:
    - docker login -u "$DOCKER_REGISTRY_USER" -p "$DOCKER_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker push $DOCKER_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    - # Here could be commands to SSH into the production server, pull the new image, and restart the service.
    - # For example: ssh user@prod "docker pull $DOCKER_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA && docker-compose up -d"
  only:
    - main
```

This saves me 5-10 minutes of setup time, and I can dedicate that time to defining my

`SLO`

s (Service Level Objectives) or thinking about more complex`feature flag`

strategies. I frequently use AI to generate simple code snippets for collecting`observability`

metrics, such as`Prometheus`

exporters or`Grafana`

dashboards.

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 page`

s, 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 flap`

s 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.

🔥 Dependency Trap: Lost Fundamental KnowledgeOver-reliance on AI can dull fundamental system administration skills. For example, if you need to free up space on a file system, AI can quickly give you a

`du -sh * | sort -rh | head -n 10`

command. However, using this command without understanding how it affects`hard link`

s, how it handles`sparse file`

s, or how its performance changes on different file systems (e.g.,`NFS`

or`Ceph`

) can lead to different problems later on.Once, when I was setting the

`cgroup memory.high`

limit, I proceeded based on an example given by AI. However, because AI didn't fully explain how soft limits work and the scenarios in which the`OOM killer`

would be triggered, the application didn't behave as expected and continued to overuse memory. I had to manually optimize the`systemd unit`

settings by examining my own`journald`

logs. This reminded me that AI is just a tool, and in-depth system knowledge is indispensable.

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.

ℹ️ Example of Effective Prompt EngineeringDetail your prompts to get more efficient and secure code from AI. For example, if you want to create a

`rate limiting`

mechanism in a`FastAPI`

application:

Weak Prompt:"Add rate limiting to FastAPI."

Effective Prompt:"I want to implement user-based`rate limiting`

for my FastAPI application. How can I implement a limit of 10 requests per minute based on IP address or`user_id`

from a`JWT token`

using`Redis`

? What are the`scalability`

and`security`

trade-offs of this solution? Please explain with`Python`

code and`Redis`

commands."This detailed prompt enables AI to provide you with a much more specific, secure, and explanatory solution. I can even include

`JWT`

validation with`OAuth2`

patterns in this prompt. In the backend of my Android spam blocker application, I significantly sped up the design of`rate limiting`

and`DoS mitigation`

layers with such detailed prompts. I combine the solutions offered by AI with my own`CVE`

tracking and`kernel module blacklist`

experiences to put them through security checks.

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 case`

s of these profiles will still fall to us.

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.
