My Account List Orders

The Code Makers: Software History and the Evolution of Programming Culture

Table of Contents

  • Introduction
  • Chapter 1 From Logic to Code: The Prehistory of Programming
  • Chapter 2 The First Compilers: From Assembly to Automatic Programming
  • Chapter 3 FORTRAN, COBOL, and the Business of Software
  • Chapter 4 Lisp, AI Dreams, and the Ideal of Expressiveness
  • Chapter 5 C, Unix, and the Portable Systems Revolution
  • Chapter 6 Microcomputers and the Democratization of Coding
  • Chapter 7 Personal Computing, BASIC, and the Hobbyist Culture
  • Chapter 8 Networking the World: Protocols, Sockets, and the Internet Ethos
  • Chapter 9 Object-Oriented Paradigms: Simula, Smalltalk, and Java
  • Chapter 10 Scripting Languages and the Rise of Developer Productivity
  • Chapter 11 The Web as Platform: JavaScript and the Browser Wars
  • Chapter 12 Version Control from RCS to Git: How History Shapes Collaboration
  • Chapter 13 The Cathedral and the Bazaar: Open Source Becomes a Movement
  • Chapter 14 Licensing, Governance, and the Politics of Code
  • Chapter 15 Agile Manifesto and Its Afterlives: Scrum, XP, and Lean Thinking
  • Chapter 16 Continuous Integration to Continuous Delivery: Toolchains and Rituals
  • Chapter 17 Package Managers and Dependency Ecosystems
  • Chapter 18 Mobile Platforms and Walled Gardens: iOS, Android, and App Stores
  • Chapter 19 Data Science, Scientific Computing, and Reproducibility
  • Chapter 20 Machine Learning and Differentiable Programming Cultures
  • Chapter 21 Safety, Concurrency, and Systems Languages: Go, Rust, and Beyond
  • Chapter 22 Cloud-Native Software: Containers, Orchestrators, and Serverless
  • Chapter 23 Security by Design: Memory Safety, Supply Chains, and Zero Trust
  • Chapter 24 Careers, Communities, and Codes of Conduct
  • Chapter 25 The Future of Programming Culture: Economics, Ethics, and Evolution

Introduction

Software is more than instructions executed by machines; it is a web of ideas, practices, and communities that encode human values into functioning systems. The Code Makers explores how the history of programming languages and development practices reveals the social norms, commercial incentives, and cultural narratives that shape the craft. By tracing the interplay between technical design and human organization, this book argues that to understand contemporary software, we must understand the people and institutions that made it possible.

We begin with the emergence of programming from mathematics, logic, and early computing, then follow the decisive leap from hand-crafted assembly to the first compilers. That transformation did not merely improve productivity; it redefined who could program, how software was organized, and which kinds of problems could be economically addressed. As languages like FORTRAN and COBOL formalized scientific and business domains, they also codified assumptions about expertise, labor, and accountability. The history of language design is thus a history of trade-offs among expressiveness, performance, portability, safety, and the incentives of the organizations funding the work.

From there, the story widens to the ecosystems that grew around Unix, C, and the internet, where portability and networking fostered shared tooling and reusable abstractions. Version control systems evolved from solitary backups to social infrastructure, turning change history into collaboration currency. These developments culminated in the rise of open source, where licensing and governance became as central as algorithms. The choice between permissive and copyleft licenses, the creation of foundations, and the emergence of the maintainer role illustrate how legal frameworks and community norms steer technical direction.

At the same time, methodologies for organizing work underwent their own revolutions. Agile practices reframed planning and delivery around human feedback loops, shortening the distance between idea and deployment. Continuous integration and delivery, automated testing, and observability tools made these cultural shifts executable. Yet the successes of agile and DevOps coexist with new challenges: dependency sprawl, operational complexity, and the risk that rituals harden into dogma. Understanding their historical roots helps practitioners adapt the spirit of these ideas rather than merely adopting the ceremonies.

Modern software development sits atop vast package ecosystems, cloud platforms, and mobile distribution channels. With this abundance come new responsibilities: securing supply chains, designing for privacy, building accessible interfaces, and stewarding communities at scale. Languages such as Go and Rust reflect contemporary priorities—safety, concurrency, and maintainability—while data science and machine learning communities introduce different research-driven rhythms, cultural norms, and ethical questions. The convergence of these currents reveals a landscape where tools and culture continually reshape one another.

This book connects these threads to practical questions of governance and career growth. How do contributor ladders, codes of conduct, and foundation charters influence what gets built and who gets to build it? How do hiring practices, education pathways, and apprenticeship models reflect long-standing biases or open new doors? For individual developers, historians’ tools—periodization, context, and comparative analysis—offer a way to navigate shifting stacks without losing sight of enduring principles.

Each chapter pairs technical exposition with cultural analysis. We examine not just how languages and frameworks work, but why they emerged when they did, which problems and communities they privileged, and how economic forces shaped their adoption. By the end, readers will be equipped to see beyond trends: to identify the structural patterns that drive software change, to make more informed architectural and organizational choices, and to participate in communities with greater fluency and care. The code we write tomorrow is inseparable from the histories we inherit today; understanding those histories is itself a form of engineering.


CHAPTER ONE: From Logic to Code: The Prehistory of Programming

Programming did not begin with computers. It began with the human desire to make thought repeatable. Long before anyone wired a vacuum tube, people were building procedures that could be executed by other people, and then by machines. The story of code is, at its root, the story of formalizing instructions, compressing intention into symbols, and building bridges between abstract reasoning and physical action. The tools were different, but the habits of mind—breaking tasks into steps, checking conditions, looping back, and managing state—are recognizably the same.

In the nineteenth century, the dream of mechanizing reasoning took concrete form. Charles Babbage sketched the Analytical Engine as a general-purpose machine that executed operations described on punched cards. Ada Lovelace, writing what we now call notes on that design, saw that such a machine could manipulate more than numbers, if only the symbols could be arranged correctly. Her observation that a computing engine could work on any formal symbol system framed computation as generality itself, not just arithmetic. It was a leap from calculation to algorithm, and from procedure to program.

Punched cards themselves were inherited from the Jacquard loom, where patterns of holes controlled the raising of warp threads and allowed the weaving of intricate textiles without reprogramming the loom for each row. The notion of storing instructions as data and feeding them to a machine became literal. When Herman Hollerith adapted card technology for the 1890 U.S. Census, he revealed how much bureaucratic work could be reimagined as information processing. The census tabulator was not a computer in the modern sense, but it established a pattern: the machine reads the program; the program describes the task.

Logic also furnished a language for computation. George Boole’s algebra of true and false, manipulated by AND, OR, and NOT, turned binary states into rules. It became the substrate for circuit design and for reasoning about conditions in software. Around the same time, Gottlob Frege attempted to ground mathematics in a precise symbolic notation. His Begriffsschrift was difficult to read, but it demonstrated that complex thoughts could be expressed in an austere syntax. The dream of a formal language that could reliably capture reasoning—and be mechanically checked—was now unmistakable.

A quieter revolution occurred in the workplace. Frank and Lillian Gilbreth filmed bricklayers to understand motion economy and standardized procedures, turning labor into sequences that could be analyzed, optimized, and taught. Frederick Taylor’s time-and-motion studies extended this approach to factory floors, insisting that work should be broken into measurable steps, each specified and timed. This so-called scientific management is controversial today for its dehumanizing tendencies, but it made explicit the idea that tasks can be decomposed into deterministic steps that machines—or humans acting like machines—can execute.

The First World War accelerated the appetite for mechanized calculation. Ballistics tables required computing trajectories under many conditions, a task tedious and error-prone when done by hand. In the United States, Vannevar Bush led the construction of the Differential Analyzer, a massive analog machine of gears and shafts that solved differential equations by physical integration. It was not a general-purpose computer, but it showed how a problem domain could be encoded in the machine’s very structure. The program was the machine, and the machine was the program.

At the same time, Gödel’s incompleteness theorems put limits on formal systems, showing that within any sufficiently powerful axiomatic framework there are true statements that cannot be proved. Turing’s response was to define computability with a remarkably simple model: the Turing machine. By describing a head that reads and writes symbols on an infinite tape according to a finite set of rules, he gave the world a precise, universal notion of what could be computed. This abstraction mattered for the history of programming because it showed that all computable tasks share a common mechanism: a step-by-step process that manipulates symbols.

Turing’s 1936 paper also introduced the idea of a universal machine, one that can simulate any other Turing machine given the right program. That single concept is the intellectual foundation of the modern computer: a hardware engine that does almost nothing until supplied with instructions. It turns programming into the art of specifying behavior, not building behavior into the hardware. The machine becomes a medium for ideas, and the program becomes the artifact that carries them.

By the 1930s, the electromechanical relay had replaced some gears. Konrad Zuse built the Z series of machines in Germany using binary logic and mechanical memory. The Z1 was a prototype; the Z3, completed in 1941, is often considered the first programmable digital computer, even though it used relays and not vacuum tubes. It supported floating-point arithmetic and could be controlled via punched tape. It was not general-purpose in the modern von Neumann sense, but it demonstrated that a single machine could be directed to execute different algorithms by changing its input.

Across the Atlantic, IBM’s business machines were becoming more sophisticated. The Harvard Mark I, built by Howard Aiken with IBM’s collaboration, was an electromechanical behemoth controlled by paper tape. It was closer to a calculator than a stored-program computer, but its programs were sequences of operations that could be varied to attack different tasks. The cultural significance was as important as the technical: large institutions were now in the business of turning procedural knowledge into physical processes, and they were hiring people to write these sequences and keep them running.

Alan Turing himself contributed directly to programming practice during the war at Bletchley Park, where the Bombe machines were designed to break German Enigma ciphers. The process of configuring the Bombe—setting up the rotors, wiring the menus, and interpreting results—was effectively programming a machine to search for contradictions in encrypted text. The humans who performed this work, many of them women, developed methods for describing tasks to machines, testing assumptions, and debugging failures. The word “debugging” would later be attached to a moth found in a relay, but the habit was already ancient.

The ENIAC, unveiled in 1945, is often celebrated as the first electronic general-purpose computer, though its programming model was initially physical: operators set switches and plugged cables into plugboards to reconfigure the machine for each new problem. Rewiring ENIAC was not trivial; it took days or weeks to prepare a new computation. Yet ENIAC was also the machine that ran the first high-speed computations for the hydrogen bomb project, proving that electronic computing could solve problems of unprecedented scale. The hardware was ready; the programming interface was still a bottleneck.

John von Neumann and his collaborators articulated the stored-program concept in the “First Draft of a Report on the EDVAC” in 1945. Their idea was to store both data and instructions in the same memory, enabling a machine to treat code as data and to modify its own instructions. This architecture solved the rewiring problem elegantly: programs could be loaded into memory like any other information. The von Neumann machine became the canonical design for decades, and the practice of programming shifted from configuring hardware to writing and loading sequences of instructions.

In Manchester, the Small-Scale Experimental Machine—nicknamed the “Baby”—demonstrated the stored-program concept in 1948. Programmers entered instructions via switches and watched the contents of memory on a cathode-ray tube. It was modest, but it proved the principle: code could be entered, stored, executed, and altered by the machine itself. When the Manchester Mark I and the EDSAC followed, they included software libraries and assemblers, signaling that programming was becoming a discipline with reusable parts and common tools.

The first programs were written in machine code, numeric instructions that the hardware interpreted directly. It worked, but it was unforgiving. A single digit off could cause a crash or an incorrect result. Programmers invented mnemonics to help remember operation codes, and soon assembled them into symbolic notations that a program could translate into machine code. This assembler was the earliest kind of compiler: a program that turned human-friendly notation into machine instructions. It was a small step in technology but a giant leap in culture; programming was becoming a conversation with tools.

Maurice Wilkes, working on EDSAC in Cambridge, realized that programming would involve assembling commonly used routines into a library that others could call upon. The concept of a subroutine was born, and with it the need for a convention: how to jump to a subroutine, how to pass parameters, how to return to the caller. These conventions evolved into calling conventions and ABIs, the invisible protocols that allow code modules to interoperate. A program was no longer a single monolithic tape; it was a composite of pieces that could be built, tested, and reused separately.

During the war and its aftermath, women played central roles in programming. Kay McNulty, Betty Jennings, Betty Snyder, Marlyn Wescoff, and others programmed ENIAC by studying circuit diagrams, tracing signal paths, and setting switches to create logical flows. They were among the first to think algorithmically about electronic machines, inventing techniques that later became standard. Grace Hopper’s insight in the late 1940s and early 1950s was that the machine should shoulder more of the burden by compiling English-like statements into machine code. Her A-0 system was a prototype for what we now call a compiler, and her evangelism for “automatic programming” shifted expectations about who could program and how quickly.

Even as programming matured, it was tied to the rhythms of physical media. Punched paper tape and cards were fragile, noisy, and labor-intensive. Errors required re-punching tapes or reordering cards. Yet this physicality enforced discipline. Because execution was slow, programmers learned to think carefully before running a job. They also developed habits of testing, logging, and modularity, not because the software engineering literature told them to, but because the cost of a mistake was a walk to the tape punch and a stack of new cards. The medium shaped the method.

By the late 1940s, the pieces were in place: a universal model of computation, stored programs, symbolic assemblers, subroutines, and a growing sense that programming was a craft with tools and standards. The hardware was electronic, but the mind of the programmer was still the primary instrument. The next leap, the compiler, would transform programming from a manual transcription of logic into a design activity. But that leap needed a bridge from the abstractions of logic to the concrete realities of machines. The prehistory of programming is the story of building that bridge, one symbol, one routine, and one punched hole at a time.

Logic continued to provide a vocabulary. Alonzo Church developed the lambda calculus in the mid-1930s, offering a way to express computation as functions and bindings, independent of machines. Emil Post formulated another model of computation. These formal systems clarified what it meant to compute and helped philosophers and mathematicians see that computation was a general phenomenon. They did not immediately produce practical programming languages, but they furnished conceptual scaffolding. When, decades later, Lisp and other languages drew from lambda calculus, it was the culmination of a long conversation between pure logic and applied engineering.

The cultural habits of programming also began to crystallize around collaboration. As institutions like the University of Pennsylvania, Cambridge, and Manchester built machines, they also built communities of practice. Programmers shared subroutines, debugged each other’s tapes, and wrote manuals and notes. The exchange of useful routines and tricks, often handwritten or mimeographed, foreshadowed the later practices of open source. The problem, of course, was that every machine was different. Porting a routine from one computer to another meant rewriting it for a different instruction set and a different hardware culture.

The organizational context mattered. Military funding drove early work on ballistics and cryptography; scientific laboratories pursued large-scale simulation; corporations eyed data processing for payroll and inventory. Each community developed its own idioms and expectations. Scientists cared about numerical accuracy and speed; bureaucrats cared about volume and standardization; cryptographers cared about secrecy and reliability. These concerns would later be reflected in language design choices—precision controls, I/O formats, error handling—and in the norms of who was allowed to write software and for what purposes.

One might ask: why did programming emerge as a distinct profession at all? Because abstraction proved to be a force multiplier. A well-written procedure could be reused, taught, and improved. A specification could be checked against a machine’s behavior. The cost of building machines was enormous, and the cost of mistakes was high. By making programs into durable, understandable artifacts, society could invest in computing infrastructure with confidence. The prehistory of programming is therefore not just a story of technology; it is a story of trust in symbolic systems.

By the end of the 1940s, the scene was set. The stored-program computer had moved from proposal to practice. Symbolic assembly and subroutines had transformed how people wrote and organized code. Key figures were advocating for higher-level notations. Communities were forming around shared problems and shared tools. The idea that computing could be universal, that the same machine could execute any describable process, had taken root. The next chapters would see that idea explode into languages like FORTRAN and COBOL, and into new social structures for producing software. But it all began here: with logic, looms, and the conviction that the world’s procedures could be captured, stored, and made to run.


This is a sample preview. The complete book contains 27 sections.