Has Software Development Peaked? A Critical Look at Modern vs. Past Practices

Software Development

An expert's critique contrasting modern JavaScript and cloud-native development with Java and on-premise practices from 15 years ago, arguing current workflows are slower, more complex, and less efficient.

The author presents a compelling comparison between software development practices of 2010 and 2025, arguing that despite technological advancements, the process has become significantly slower, more complex, and less efficient. This piece offers a critical perspective on modern development workflows, tools, and paradigms.

Programming in 2025

The author describes current programming in 2025 as a JavaScript-centric landscape. Modern JavaScript, now with types and a dependency manager, runs universally. However, this ecosystem is often plagued by security vulnerabilities, with packages frequently used for malicious injections. Development heavily relies on AI-assisted code generation, which, while offering plausible solutions, has a notable risk of installing malicious packages.

The popular VS Code editor, despite its features, is noted for its substantial RAM requirements and its inclusion of a web browser, a common characteristic of modern applications. While capable of basic refactoring like renaming variables within a single file, it's often perceived as less powerful than older IDEs. The build process, even with powerful multi-core machines, takes several seconds for TypeScript compilation.

The modern deployment pipeline is depicted as an ordeal. The "pull request" model, intended to emulate open-source development within a single company, is criticized for its bureaucracy. This typically involves downloading and building code on a separate machine, followed by colleagues requesting minor textual changes, leading to repeated builds and potential delays of days before merging. Once merged, JavaScript is packaged into a "container" – a term sometimes used to describe an overly comprehensive bundle. This packaging process is lengthy (20 minutes) due to the complete re-download of system repositories and JavaScript dependencies each time.

Pushing containers to a "registry" often encounters issues, such as security scanners flagging insecure Perl versions. Even if Perl isn't required, its presence and the difficulty of removal often lead to simply disabling the scanner. Next, extensive YAML configurations are written to instruct Kubernetes (k8s) on how to run the container. Unlike JavaScript, this YAML is untyped and often relies on string templating, creating complex and unpredictable configurations. These k8s clusters operate in the "Cloud" – a collection of Linux services hosted on rented VMs. This approach, while abstracting infrastructure, often incurs monthly costs comparable to outright computer purchases. Sending YAML to the cluster can yield unpredictable results, making an entirely separate cluster necessary for deployment verification due to the lack of reliable testing methods.

Fifteen Years Ago

The author recounts their first full-time job in 2010, detailing a Java-based development environment. Java, described as a general-purpose, verbose, and mostly type-safe language, compiled quickly on single-core 2 GHz machines. The Eclipse IDE was praised for its robust refactoring capabilities (extracting/inlining functions, classes, interfaces) and real-time compilation, allowing for application compilation and test runs with nearly every keystroke.

Development emphasized writing tests, often first, and running them constantly. This involved direct communication about functionality, translating requirements into verifiable code. Running 10,000 unit tests typically took around a minute, with options for more selective runs when time was critical. Interestingly, overall application performance was comparable to current speeds.

Code was pushed directly to the trunk, often through pair programming. After a coffee break, work would begin on the next task, and testers would be informed to review the changes. Lacking containers, applications were packaged into "JARs" – large zip files containing the application and its Maven Central dependencies. Maven Central, in contrast to modern package managers, vetted submitters, leading to a more controlled dependency environment. These JARs ran inside Java servers like Apache Tomcat on Linux VMs within on-premise data centers. Deployment was managed by tools like Puppet. The on-premise nature meant direct access to hardware: "If the computer broke, we could go and turn it off and on again." The author emphasizes the reliability of this setup, attributing it to quality construction, optimal resource utilization, and diligent monitoring.

Reflections on Progress

The author expresses a longing for those earlier days, reminiscing about Java development and collaboration with colleagues. Tools like Eclipse and Maven are remembered for their dependability, advanced features, and thoughtful dependency management that solved problems like namespacing and trust. A significant point of frustration is the regression in deployment speed: "builds and deployment have become slower in the last 15 years, not faster." The process, which once took less than a minute from code to shipping, now extends to hours or even days, especially when involving staging environments and Kubernetes.

The absence of dedicated testers is also lamented, as their role in identifying issues provided a crucial safety net. While acknowledging some modern improvements, such as Git over Subversion, well-built containers, and the utility of the Cloud for specific use cases (especially for startups), the author ultimately finds the current development landscape dissatisfying.

The perceived "catalyst" for this shift is attributed to NPM, which elevated Node.js and JavaScript to a serious programming language, bringing both benefits and significant drawbacks. The rise of React is labeled a "tragedy" for front-end programming, and Electron's prevalence means that a web browser now forms the basis of many applications. While appreciating JavaScript's versatility and server-side capabilities, the author advocates for a return to using "sensible tools for the job at hand."