One of the biggest changes I’ve seen in the industry over the last twenty years is the evolution of the developer from a “bricklayer” to a “foreman.” It’s no longer enough to just write code or finish a specific feature; we now have to understand the entire system, business workflows, and even organizational dynamics. This shift places more responsibility on us but also offers a greater sphere of influence.
Today, in the modern software development environment, when designing a feature, I need to consider not only its technical implementation but also which business process it will accelerate, which department it will simplify life for, and how it will affect the system’s overall performance or security. While I used to just write code and be done with it, now I act almost like an architect or a consultant. For someone like me, who has spent many years in the field, this is both a challenging and exciting transformation.
What We Used to Do? (Laying Bricks and Our Focus)
Twenty years ago, my primary job as a developer was to write code according to the specs given to me. My focus was generally on ensuring a specific module or function worked correctly. When working on a manufacturing ERP, for instance, I was busy optimizing the performance of a report in the warehouse inbound-outbound module. There, reducing a 2000-line SQL query from 30 seconds to 3 seconds was the most important event of my day.
Back then, I didn’t think much about the overall architecture of the system or its interactions with other modules. When I encountered an N+1 problem, I would just optimize the current query; I didn’t really consider that this error might occur elsewhere in the system or stem from a more fundamental architectural issue. For me, “laying bricks”—that is, writing and testing code—was a big part of my job. At that time, issues like a PostgreSQL server experiencing WAL bloat or what Redis’s OOM eviction policy meant were typically the responsibility of system administrators. However, these boundaries have blurred over time.
Automation and AI: Not Our Screwdrivers, But Construction Machines
Today, automation and especially artificial intelligence (AI) tools have fundamentally changed how we work. We can now leave tedious and repetitive tasks to machines. Thanks to CI/CD pipelines, automated tests, and infrastructure as code (IaC), I’ve reduced the deployment process of an application from hours to minutes. At one point, while setting up the CI/CD pipeline for my own side product, I was tired of manually SSHing into the server and running the deploy script every time. Then I automated it with GitLab CI/CD, and the reliability of deployments increased by 90%.
With the advent of AI, our code writing time has also decreased. In my own projects, I get code snippets, and sometimes even entire functions, from AI using prompt engineering techniques. This saves me more time, and I can dedicate this time to higher-level issues such as system architecture, integration of different components, and improvement of workflows. When designing an AI-powered operations pipeline, bringing together different providers like Groq and Gemini Flash and managing latency and cost trade-offs has become more important to me than writing code.
# A simple FastAPI endpoint example, can be generated with AI but its architecture is our job
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.post("/items/")
async def create_item(item: Item):
if item.price < 0:
raise HTTPException(status_code=400, detail="Price cannot be negative")
# Database saving or other business logic goes here
return {"message": "Item created successfully", "item": item}
The Foreman Mindset: Holistic View and System Architecture
The foreman mindset requires thinking about how the entire building will stand, rather than just placing a single brick correctly. As a developer, when developing a feature, I now have to consider how it will interact with other modules in the system, which database tables it will affect, and even what kind of load it will create at the network layer. When I worked on a manufacturing ERP, I didn’t just think about UI/UX when designing an operator screen. I also planned which sensor data that screen would pull, how it would integrate with the production planning engine, and how it would reflect in the supply chain with iSCSI integration.
This also includes making big decisions like Monolith vs. Microservice architecture choices. In one project, we decided to start with a monolith for a quick MVP, then convert critical modules to microservices. This decision was entirely based on trade-offs between cost, development speed, and scalability. When implementing event-sourcing and CQRS patterns, I designed how we would use the transaction outbox pattern to ensure idempotency. Such decisions are no longer just for architects but also for experienced developers.
Understanding Workflow: Organization Before Code
I’ve experienced that software architecture is often a reflection of organizational flow. Not just writing code, but understanding business processes and organizational structure is key to producing the right solutions. In a manufacturing company’s ERP, delayed shipment reports were consistently erroneous. At first, I looked for an error in database queries or code, but the root cause was somewhere else entirely. Warehouse employees were manually entering shipment information into the system with a certain delay. The problem wasn’t in the software, but in the workflow.
In this situation, my role wasn’t just to fix the code, but also to talk to the warehouse operations team and design a new integration to automate the process. This included IFRS integrations or supply chain optimizations. A developer now needs to think like a “business analyst,” and sometimes even act like an “organizational consultant.” Going beyond code to understand and solve real-world problems is an integral part of our job today.
graph TD
A[Delayed Shipment Report Erroneous] --> B{Code/DB Error?}
B -- No --> C[Warehouse Operations Examined]
C --> D[Manual Data Entry Delay Detected]
D --> E[Automation Need Identified]
E --> F[New Integration Design (API/MQ)]
F --> G[Process Improvement with Warehouse Team]
G --> H[Report Accuracy Increased]
B -- Yes --> I[Code/DB Optimized]
Security and Operations: The Strength and Maintenance of Walls
In the past, security and operational tasks were typically the responsibility of separate teams. I would just write the code, and system administrators or security specialists would handle the rest. However, in today’s world, this distinction has disappeared. Now I also have to consider the security of the code I write and the operational health of the application. Issues like a kernel module blacklist (e.g., security vulnerabilities like CVE-2026-31431 for algif_aead), fail2ban patterns, or SELinux profiles are no longer just for system administrators, but also things I need to follow.
Last month, I saw a container OOM-killed with a sleep 360 command because the cgroup memory.high limit was not set correctly. This was a simple error but caused application downtime. I then switched to a polling-wait mechanism to solve this problem. I closely follow issues like WAL bloat in PostgreSQL or OOM eviction policies in Redis because these situations directly affect the performance and stability of my application. Therefore, I need to manage not only the functionality of the code I write but also its systemd units, journald logs, and cgroup limits.
# Command to check memory limits on a system
# This is critical for understanding memory usage of containers or services.
cat /sys/fs/cgroup/memory/memory.max
# Configuring journald rate limits is important to prevent log spam.
# Configured in /etc/systemd/journald.conf.
# RateLimitIntervalSec=30s
# RateLimitBurst=1000
The Developer of the Future: From Engineering to Orchestration
The developer of the future is no longer just an engineer but also an orchestra conductor. While our ability to write code is still fundamental, our true value now lies in our ability to bring together different systems, technologies, and people. Problem-solving, design, integration, and communication skills have become as important as our technical abilities. I remember how I brought together different AI providers (Gemini Flash, Groq, Cerebras) via OpenRouter in the backend of one of my side products and developed a fallback strategy against potential outages. This was less about just writing code and more about orchestrating different parts of a system.
This transformation necessitates continuous learning and self-improvement. We are not just learning new programming languages or frameworks, but also gaining knowledge in areas such as network security (ZTNA egress control, segmentation), database optimizations (PostgreSQL index strategies, replication), and CI/CD processes. When developing my own Android spam blocker application, integrating native packages with Flutter or managing Play Store publishing processes was more than just a technical task for me; it was a holistic product development experience.
The developer’s role is no longer just a “bricklayer” who follows instructions, but a “foreman” who views the project holistically, brings together different areas of expertise, and takes an active role in every stage of the work. This means more responsibility, yes, but it also offers a great opportunity to increase the impact of our work and build more satisfying careers. Those who adapt to this change will remain permanent and valuable in the industry.