One morning, I saw a “memory exhausted” error from a section of the production ERP’s billing module that I hadn’t touched. My first thought was, “Did someone touch my code and break it?” However, upon detailed investigation, I realized the problem wasn’t in my own code, but rather a Python dependency on the server triggering a cgroup memory limit. This situation once again highlighted how insufficient it can sometimes be for a software developer to just write code and focus solely on their area of expertise.
I’ve encountered these kinds of scenarios repeatedly: a perfectly written, optimized piece of code failing to perform as expected due to the underlying system or network infrastructure. Deep specialization in software is, of course, very valuable; however, without understanding the surrounding ecosystem, it becomes impossible to fully predict the real-world behavior and performance of the written code or to quickly resolve issues. In this post, I’ll explain from my own experiences why software expertise alone isn’t enough and why a developer needs to have a broader perspective.
Why Just Writing Code Isn’t Enough
Just writing code is like playing one instrument in an orchestra; you can deliver a great solo performance, but for the entire symphony, you need to understand the other instruments and the conductor’s vision. An application’s performance, security, or stability often depends on factors beyond the code itself.
In my experience, many times the root cause of a performance issue or an unexpected error was not directly within the application code, but hidden in operating system configurations, database settings, or network latencies. For example, when working on an API service with significantly increased response times in a production environment, I initially examined my FastAPI code and SQL queries. But I found the source of the problem was another process on the server consuming excessive CPU resources and hitting my application’s cgroup limits. Even if the code is perfect, if resource management is done incorrectly, the application will be perceived as “slow.” That’s why it’s critically important for a developer to know the environment their code runs in, what resources it consumes, and how those resources are managed.
The Importance of System and Network Knowledge
Every line of code we write runs on an operating system and usually communicates with other services over a network. Therefore, without understanding this infrastructure, it’s impossible to fully grasp the application’s behavior or effectively troubleshoot problems.
Once, in a client project, users connecting via VPN reported constant interruptions when accessing certain parts of the application. No errors appeared in the application logs, and my backend was responding healthily. I determined that the problem was actually at the network layer, specifically due to MTU (Maximum Transmission Unit) settings on the VPN gateway being incompatible with the MSS (Maximum Segment Size) settings of the users’ internet service providers. It would have been impossible to find such a problem by just looking at the application code; it required examining network packets and understanding the TCP handshake. Similarly, when managing Linux services with systemd units, knowing the differences between Type=notify and Type=simple, correctly setting up service dependencies, or configuring cgroup limits is vital for the application’s stability and reliability. Understanding how network segmentation, VLAN tagging, and firewall policies affect an application’s accessibility and security is also essential for a developer.
Is Database Optimization and Architecture an Overlooked Area?
The heart of most enterprise applications is a database. No matter how optimized your code is, if the database is slow or misconfigured, the entire application’s performance will suffer. Unfortunately, many developers prefer to hide behind ORMs (Object-Relational Mappers) and avoid database details, which can lead to serious problems in the future.
While working on a production ERP, we were experiencing performance issues, especially with reporting and large data queries. The source of the problem wasn’t N+1 queries or simple missing JOINs; it was more about inadequate PostgreSQL index strategies and incorrect connection pool settings. Knowing which scenarios B-tree, GIN, and BRIN indexes perform more efficiently in, correctly interpreting EXPLAIN ANALYZE outputs, and optimizing vacuum processes significantly improved the application’s overall response time. Furthermore, situations like PostgreSQL WAL bloat can lead to rapid disk space depletion and database slowdowns; this is directly part of the developer’s question, “where does my code run?” Understanding database replication mechanisms (logical vs. physical) and read replica routing is critical for application scalability. Architectural decisions like whether to use optimistic or pessimistic locking, or when to implement the transaction outbox pattern, directly require database knowledge.
Is Security Just an Add-on?
Security is not a “later added” feature in a software project, but a fundamental layer that must be integrated from the very beginning of the design. Focusing only on application-layer vulnerabilities often means missing the bigger picture.
In my experience, no matter how good application-level security is (e.g., using JWT/OAuth2, rate limiting on APIs, and SQL injection mitigation), weaknesses in the underlying system or network layer can jeopardize the entire system. For example, weak kernel module blacklist rules on a server or misconfigured tools like fail2ban can leave doors open to SSH brute-force attacks. Once, I detected an intrusion attempt on the test environment of an application under development, not through a vulnerability in the application itself, but via an exploit targeting a CVE in an old dependency on the server. Such situations demonstrate the importance of system security practices like using the auditd subsystem, creating SELinux or AppArmor profiles, and file integrity monitoring. Furthermore, understanding how switch hardening techniques on the network side, such as DHCP snooping, Dynamic ARP Inspection (DAI), and IP source guard, make the application’s operating environment more secure deepens a developer’s security perspective. Concepts like ZTNA (Zero Trust Network Access) architectures and egress control are topics that not only network administrators but also developers need to understand.
Understanding Business Workflows and Corporate Processes
Software development is often done to solve a specific business problem or automate a corporate process. Therefore, focusing only on technical details and not understanding business workflows can lead to the developed product not meeting real needs or incorrect prioritization.
While working on a production ERP, I had to deeply understand core business workflows like “purchase,” “produce,” “ship,” and “invoice.” When designing operator screens, designing a technically “correct” interface would be insufficient without knowing what a field operator truly needs, which information is critically important instantly, and which steps should be ordered most efficiently. For example, the reason delayed shipment reports sometimes provided incorrect information was often not database performance, but an inconsistency in data entry processes on the production line or a lack of integration between systems used by different departments. Software architecture decisions (monolith vs. microservice, event-sourcing vs. CQRS) are often a reflection of organizational flows and the independence levels of business units rather than technical requirements. As a developer, working closely with business units, listening to their problems, and understanding how software can better support these processes requires much more than just writing code.
Problem-Solving Approach: Broad Perspective and Debugging
When I encounter a problem, my first instinct is usually to check my code. However, 20 years of experience have shown me that this narrow perspective often prolongs the problem-solving process and causes us to miss the true root cause. A broad perspective is indispensable, especially when debugging distributed systems.
Once, I experienced an unexpected CPU spike followed by an OOM-killed error in the backend of one of my side products. Application logs simply stated “process killed” and provided no further details. Initially, I tried to fix the code, thinking a sleep(360) command I wrote was causing active waiting instead of polling-wait. However, upon examining journald logs and cgroup reports, I saw that a different process, at an unexpected time, was consuming intense resources and triggering my container. This situation once again proved how critical it is to understand not just the code, but the entire system and its environment. Implementing observability (metrics, logs, traces) only gains meaning when this data can be interpreted in a broad context. As a developer, being able to monitor and interpret not only the output of my own code but also operating system metrics, network traffic, database performance, and the status of other dependencies allows me to diagnose problems much faster. Operational concepts like SLO (Service Level Objective) and error budget management also gain meaning with this broad perspective.
Conclusion: A T-Shaped Specialization Journey
Specializing in software is, of course, very valuable; however, it’s not enough on its own. As a developer, I’ve learned from my own experiences that developing a T-shaped specialization is much more beneficial than just knowing a programming language or a framework in depth. This means having deep knowledge in one area (e.g., backend development) while also having a broad understanding of other areas such as system administration, networking, databases, security, and business processes.
This broad perspective not only allows you to solve problems faster but also enables you to design more resilient, scalable, and secure systems. This holistic approach has always helped me solve an integration error I encountered in a production ERP, a disk fire issue I experienced on a VPS, or a metadata rejection during the Play Store publishing process for one of my Android spam applications. Practical experiences like tinkering with Linux commands, examining EXPLAIN ANALYZE outputs of a database, or setting up a simple network topology incredibly broaden a developer’s horizon. Remember, the code you write doesn’t operate in a vacuum; it’s just one part of a large ecosystem. The better you understand this ecosystem, the greater the impact of the code you write.