In the early days of software development, the simplicity of tools like VI and a compiler sufficed for building enterprise-scale applications. These tools were straightforward, and developers could focus primarily on coding. However, as technology evolved, the complexity of software development has escalated. Today, we are wading through an ever-expanding array of tools and technologies. While tools like version control, automated testing, and static and dynamic analysis have undeniably enhanced our capabilities, there’s a growing concern that we’ve deviated from the path of efficiency, lost our focus on building software, and spend too much time distracted by maintaining the environments that are supposed to help us code. Our tech stacks are fast becoming tech piles, creating environments whose configuration and maintenance seem to work at odds with providing the value for the software they are supposed to support.
The Cost of Complexity
Developers now spend significant time stabilizing the tech stacks in their environments, often at the expense of actual software development. The ecosystem is littered with open-source solutions that promise much but deliver little, lacking robust support and tangible value. Our deployment pipelines, far from being agile and portable, have turned into unwieldy beasts, difficult to manage and replicate.
The problem is exacerbated by the need to create entire staging or development environments with a mal-configured Kubernetes, many APIs, extensive logs, multiple programming languages, and intricate security controls. This complexity doesn’t just impact the code; it also weighs heavily on the developers. Complicate this along another dimension by endlessly customizing every tool, and you have an intractable environment for anyone to understand, maintain, or debug. (See my article on preferring reasonable defaults.)
The Impact on Productivity and Creativity
Tech stack complexity has tangible impacts. First, it hinders productivity. Developers spend more time troubleshooting development environment issues than solving real-world problems.
Second, it stifles creativity. The cognitive load of managing complex environments can dampen the innovative spirit, diverting attention from creative problem-solving to mundane setup tasks.
Finally, developers lose the ability to self-service their environments. Navigating the boundaries between operations, cloud environments, DevOps tools, and actual application code requires cross-disciplinary teams. This is further compounded by separation of duties concerns that engineer communication, service, and technology bottlenecks.
Today’s typical tech stack can be daunting. They encompass a wide range of tools and technologies, from a developer’s local machine to the cloud environment and DevOps ecosystem. Each layer adds complexity and capability, creating a multi-faceted environment of friction for modern software development.
The Tech Pile On the Developer’s Machine
A developer’s local tech stack is often a microcosm of the broader tech stack. It may include:
- Code Editors and IDEs
- Compilers/Interpreters
- Version Control
- Package Managers
- Local Databases
- API Testing Tools
- Virtualization Tools
- Service Mesh
- Database Management Tools
- API Development Tools
- Language-Specific Tools
- Static Code Analysis Tools
- Code Documentation Tools
- Project Management Tools Integration
- Internationalization and Localization Tools
- Command Line Tools and Utilities
- Version Control Tools/GUIs
- UML and Design Tools
- Text Manipulation Tools
- Terminal Emulators and Shells
- Package Managers
- Database Clients and ORMs
- Performance Profiling Tools
- API Mocking Tools
- Code Quality and Linting Tools
- Local Environment Setup Tools
- Collaboration Tools
- Time Management and Productivity Tools
- Security Scanning Tools
- Accessibility Testing Tools
The Tech Pile In the Cloud Environment
The cloud tech stack is typically a complex amalgamation of services and tools, particularly in ecosystems like AWS or Azure:
- Compute Services
- Storage Solutions
- Databases
- Networking
- Security Controls
- Monitoring and Logging
- Developer Tools
- Advanced Security Services
- Content Delivery and Optimization
- Data Analytics
- Machine Learning and AI Services
- Disaster Recovery
- Hybrid and Multi-Cloud Management
- Cloud Cost Management and Optimization
- Message Brokers and Event Streaming
- Serverless Computing Services
- Container Registry
- Big Data Processing
- Edge Computing Services
- IoT Services
- Machine Learning and AI Platforms
- Blockchain as a Service
- Content Management and Delivery
- Mobile App Development Services
- Identity and Access Management (IAM)
The Tech Pile In the DevOps Environment
The DevOps environment aims to streamline the development and deployment pipeline with a suite of tools:
- Continuous Integration/Continuous Deployment (CI/CD)
- Configuration Management
- Container Orchestration
- Infrastructure as Code (IaC)
- Logging and Monitoring
- Incident Management
- Monitoring and Logging
- Artifact Storage and Management
- Custom Formatted Outputs
- Infrastructure Monitoring
- Code Documentation and Collaboration Tools
- Languages and Popular Libraries/Tools
- Python
- JavaScript/Node.js
- Java
- C/C++
- Ruby
- .NET Environment
- Secrets Management
- API Gateways
- Feature Flagging Systems
- Chaos Engineering Tools
- Network Policies and Firewalls
- Service Registry and Discovery
- Serverless Frameworks and Tools
- Database Management and Automation
- Performance Testing Tools
- Collaboration and Communication Tools
- Documentation and Knowledge Sharing
- Compliance and Governance Tools
- User Feedback and Analytics
- Desktop Automation and Setup
The Tech Pile in the Operations Environment
Creating a robust development and deployment environment requires a comprehensive set of tools and services that address various aspects of operations and infrastructure, including identity management, encryption, network monitoring, cybersecurity, zero-trust architecture, firewalls, and more. Here’s a list of such tools and services:
- Identity Management and Authentication
- Encryption and Data Protection
- Network Monitoring
- Cybersecurity
- Zero Trust Architecture
- Firewalls and Network Security
- Security Information and Event Management (SIEM)
- Endpoint Protection
- VPN and Secure Access
- Data Loss Prevention
- Container Security
- Intrusion Detection and Prevention
Navigating this tangled nest of technologies requires a deep understanding of each component and its role in the overall ecosystem. The challenge lies not just in the mastery of individual technologies but in ensuring their integration. How large is the team that can support this, and how do we train them? How do we design teams focused on product delivery that also cross-cut all of these technologies? When data isn’t showing up on a port, how do we start to debug the root of the problem? Creating an immutable tech stack configuration is a huge challenge that most teams simply ignore, and with this complexity, it is easy to see why.
Raising the BAR: A Call for Thoughtful Integration
Production software probably can’t (and probably shouldn’t) get back to the days when a text editor and a compiler were all that we needed. On the other hand, I’ve also seen the pendulum swing in the other direction with tools that try to do everything in one place and, of course, do nothing well.
The solution isn’t to abandon tools, but to raise the bar for their entry into our ecosystems. Every technology we integrate should be scrutinized not just for its immediate utility but for its long-term value, support structure, and impact on the developer experience.
Focus on Value Creation
Many teams seem to overly focus on processes instead of outcomes. In this sea of technology, we need to anchor ourselves to the principle of value creation. Tools are the means, not the end. They should be conduits that facilitate innovation, not impediments that stifle creativity. It’s imperative to rigorously evaluate whether a new tool augments our capabilities or adds another layer of complexity. This evaluation shouldn’t be superficial; it requires delving into the long-term value proposition of the tool, considering factors such as scalability, adaptability, and potential for integration with the existing tech stack. Every item we add to our tech stack increases its complexity. Therefore, every technology we add needs to buy its way into the environment.
Emphasize Developer Experience
Developer experience should be at the forefront of technological adoption. Tools that require excessive configuration, have steep learning curves or don’t integrate well with existing systems can detract from overall productivity.
For example, an extensive and overly complex DevOps toolchain can inadvertently become a hindrance, particularly regarding build and test times. Lengthy build and test durations can create significant bottlenecks in the development process, leading to frustration among developers. The irony is palpable: the very pipelines and tools designed to streamline and improve the development workflow can be counterproductive. Long wait times for builds or tests discourage developers from fully utilizing these pipelines, defeating their purpose. They can stifle the rapid iteration and continuous integration that DevOps is meant to facilitate. This calls for carefully evaluating the toolchain, ensuring that each component adds value and efficiency, rather than complexity and delays. Simplifying and optimizing the DevOps toolchain can significantly enhance developer productivity and morale, keeping the focus on innovation and quality rather than on waiting for processes to complete.
The developer experience is the heartbeat of technological adoption. Tools that demand excessive configuration present steep learning curves, or fail to integrate smoothly with existing systems can significantly derail productivity. A tool’s impact on a developer’s daily work life is equally, if not more, important than its technical prowess. The ultimate goal should be to enable developers to focus on what they do best: coding and problem-solving, rather than wrestling with unwieldy tools.
Foster Portability and Reproducibility
The tech stack for deployment pipelines should be agile and reproducible. Tools and environments must be portable, ensuring that applications can seamlessly move from development to production. This demands a thoughtful approach to standardization and a bias toward solutions that advocate for reproducibility and ease of deployment.
Add to your Tech Stack Incrementally
We’ve often seen an impulsive desire to chase the newest tools and platforms, sometimes leading teams to adopt a “big bang” approach to constructing their tech stacks. This approach involves implementing a comprehensive suite of tools and services all at once, with the hope that they will seamlessly integrate into the workflow.
A more prudent approach is to take it one step at a time. Begin by thoroughly understanding and mastering your existing tech stack. Each tool, service, or platform in your current arsenal likely has a depth of features and capabilities that are often underutilized. Delving deep into these existing resources can uncover hidden efficiencies and solutions that might negate the need for additional tools.
Once you have a firm grasp on your existing stack, evaluate your processes and your product’s needs. Does the current stack fulfill all essential functions effectively? Are there bottlenecks or pain points that could be resolved with a new tool? If so, then consider adding that new tool, but do so judiciously. Introduce it into your ecosystem, learn its nuances, understand its impact on your processes, and gauge its actual contribution to your product’s development. Know your metrics for success before you add the tool, evaluate it accurately, and remove it if it doesn’t improve your metrics (or improve them enough to buy its way in). This gradual approach ensures that each tool is not just a shiny new gadget but a meaningful addition that brings tangible benefits.
Adopt a Minimalist Approach
In this context, a minimalist approach doesn’t imply a reduction in tools but a strategic curation of them. It’s about slicing through the cacophony of options and concentrating on technologies that present tangible solutions to genuine challenges. This approach keeps the easy things easy, prevents feature bloat, and ensures that every element of the tech stack serves a purpose and adds value.
Promote Interoperability
Interoperability is a cornerstone of an effective tech stack. The aspiration should be to architect a tech ecosystem where components coexist and synergize. This interconnectivity can dramatically alleviate the complexity and maintenance burden. It’s about creating a seamless workflow where data, processes, and ideas flow unimpeded across different tools and platforms.
Prioritize Comprehensive Support
While open-source tools are cornerstones of innovation and community-driven progress, their viability hinges on robust support systems. Prioritizing tools that are backed by active communities, comprehensive documentation, and reliable support mechanisms is crucial. This not only mitigates the risks associated with complex tech stacks but also ensures that when challenges arise, solutions are readily accessible.
Cultivate a Shared Vision of Success
It’s not just about having the right tools or even the right processes; it’s fundamentally about having the right mindset and a shared vision of what success looks like. A disjointed approach where each team operates in its silo, content with the performance of their respective domains, is a recipe for inefficiency and frustration. To drive meaningful outcomes, fostering a culture where collaboration, communication, and a shared understanding of goals are paramount is essential. This helps create the Win-Win-Win for your users, company, and team.
Consider a scenario where the DevOps team proudly declares, “GitLab is functioning perfectly,” while the operations team asserts, “All virtual machines are operational,” but the software team is left grappling with unexecuted GitLab jobs. This disconnect hampers productivity and breeds a sense of isolation and misalignment.
We drive our teams into silos when they have to manage these huge tech piles. When we streamline our environments, we can engineer teams with more bandwidth to collaborate and focus on delivering outcomes.
Getting Back to Tech Stacks
The transformation from overwhelming tech piles to streamlined tech stacks poses significant challenges. However, by focusing on value creation, enhancing developer experience, fostering portability, adopting a minimalist approach, promoting interoperability, and prioritizing support, we can navigate this complexity.
It’s time to simplify our tools and processes, not for the sake of simplicity itself, but to unleash the full potential of our development teams and build truly great software.