English
This history is a map of why the subjects in this guide exist. It follows recurring problems—representing information, expressing procedures, sharing machines, preserving records, communicating, and learning—so that an unfamiliar subject has somewhere to attach. The dates indicate periods of development or wider adoption, not the birth and death of neatly separated eras.
Three histories intersect here. The history of computing includes human calculation, mechanical devices, offices, laboratories, and communications. The history of computer science concerns the concepts, methods, and institutions that made computation a subject of systematic study. The history of AI adds attempts to explain or construct intelligent behavior. These strands influenced one another, but they did not advance in a single sequence from theory to hardware to software to intelligence.
Read each section by asking: what difficulty were people trying to overcome, what representation or abstraction made progress possible, and what did the solution leave unresolved? The final synthesis uses “expanding constraints” as one organizing lens. It is a way to compare subjects, not a claim that history had a predetermined destination.
1930s–1950s: The Formalization of Computation
What makes a procedure mechanical? This became a precise mathematical question in the 1930s, but attempts to mechanize calculation were much older. Babbage’s nineteenth-century Difference Engine designs addressed the production of mathematical tables. His later Analytical Engine designs aimed at a much wider range of operations directed by instructions. Lovelace’s 1843 notes recognized that operations on numbers could stand for operations on other things if their relationships could be represented appropriately. The engine was not completed in their lifetimes, and later computer builders did not simply implement a continuously transmitted Babbage blueprint.
This earlier history gives a beginner a first foothold: a machine acts on representations. Numbers may stand for quantities, musical relationships, or symbols. The possibility of manipulating an encoding is different from understanding everything it represents.
The logicians’ problem concerned the limits of effective procedures. Turing’s machine model and Church’s lambda calculus made such procedures mathematically explicit. The decision problem for first-order logic asked for a procedure that would always decide whether a formula was logically valid; it was not a promise to settle every vaguely expressed question. Church and Turing established its undecidability. Turing’s analysis also laid the basis for the modern halting problem: no algorithm can decide, for every program and input, whether that execution eventually terminates. This does not prevent us from proving termination for particular programs. Turing’s 1936 paper
The Church–Turing thesis connects the informal notion of an effective procedure with formal computability. Equivalence between formal models can be proved; the thesis is not simply one more theorem of that kind. A universal machine can simulate other machines in the model, but universality promises neither unlimited practical resources nor intelligence.
The lasting distinction is between a question, a precise problem specification, and a procedure for solving it. Learning to separate them is useful long before you learn the proofs of undecidability.
1940s–1960s: From Formal Procedure to Physical Machine
Working computers emerged from several practical traditions, including numerical calculation, punched-card data processing, communications, and wartime engineering. They were not simply a downstream application of completed computability theory. Relays, vacuum tubes, memory devices, and the needs of users all shaped what builders could make. The core problem was: how can a specified sequence of operations be carried out reliably, quickly, and at an acceptable cost?
One concrete connection between logic and engineering was Shannon’s analysis of switching circuits, published in 1938. If a closed switch represents true, two switches in series conduct only when both are closed, implementing AND; parallel paths conduct when either switch is closed, implementing OR. Boolean expressions can therefore describe switching arrangements, and algebraic identities can guide changes that preserve their logical behavior. This made logic a tool for circuit design. Building a reliable machine still required handling physical delays, storage, and component failures.
It helps to distinguish three ideas that are often bundled together. A machine can be automatic, carrying out a sequence without repeated human intervention; programmable, changing behavior when its instructions change; and stored-program, holding executable instructions in an internal memory. Programmability existed before electronic stored-program computers. Storing instructions as manipulable encodings made loading, translation, and many forms of software construction much more convenient.
The stored-program approach took shape through the work of multiple people and projects. The familiar name “von Neumann architecture” should not erase the contributions of the ENIAC and EDVAC teams, including Eckert and Mauchly, or turn a complicated development into one person’s isolated invention. Nor should it be confused with the mathematical idea of universality: one concerns the organization of a practical machine, the other a model’s capacity to simulate computations.
Haigh and Ceruzzi’s history supplies a second useful distinction: theoretical universality and practical versatility. A machine might be general in principle yet be usable only by a few specialists for a narrow set of tasks. Storage, input and output, software, cost, and access determined whether it could become an office tool, an interactive instrument, or a communication medium.
For learning architecture, follow one instruction through the machine, then ask which details a programmer needs to see. An instruction set describes a visible contract; different internal implementations can support it with different performance. This distinction between a stable description and changing machinery will reappear in languages, operating systems, and databases.
1950s–1970s: From Machine Control to Programming Abstraction
As programming work accumulated, programmers needed ways to retain and reuse what they had learned. Subroutine libraries and symbolic notations reduced repeated effort. Compilers made it possible to express some tasks in a notation closer to the problem than to a particular machine. The question was: which details should a programmer have to manage, and which can a tool manage reliably?
There was no single ladder on which each language replaced a less advanced predecessor. Fortran served numerical work; COBOL expressed business records and processing; Lisp made symbolic expressions and recursive operations convenient; ALGOL contributed block structure, scope, and a precise published description of syntax. These were answers to different communities’ problems. Knuth and Trabb Pardo’s history compares early languages by expressing the same algorithm in them—a useful way to see differences that a list of release dates would conceal.
Notation can change the difficulty of thought. In an arithmetic expression, named variables and nested structure save a reader from reconstructing a sequence of memory transfers. Procedures let us reason about a task through inputs, outputs, and assumptions. But a higher-level description still needs an implementation, and a compiler must preserve the language’s defined behavior rather than guess what the programmer hoped to mean.
ALGOL’s influence also shows why language design became a research subject. Agreeing on grammatical form did not by itself settle every question of meaning, implementation, or usability. Formal semantics, type systems, and language implementation grew around those gaps. Different programming paradigms emphasize different ways to organize computation; they do not necessarily have different computability power.
For a beginner, compare two implementations of a tiny task and ask which decisions are explicit in each. An abstraction is useful when it removes a burden while retaining the distinctions you still need.
1960s–1970s: The Software Crisis and the Need for Discipline
Large programs exposed the limits of relying on individual memory and informal coordination. The “software crisis” named concerns about cost, schedules, reliability, and the difficulty of changing software. The 1968 NATO conference helped make software engineering a public agenda, but neither the problems nor the responses began at one meeting. Participants did not agree on one cure.
One response was to make reasoning more local. Structured programming sought control structures whose effects could be followed and justified. Formal methods related program behavior to explicit specifications. Testing supplied evidence about selected executions. These approaches address different needs: tests can expose a counterexample, while a proof establishes a property only under its stated model and assumptions. Dijkstra’s work made the limits of relying on testing alone especially forceful. Notes on Structured Programming
A second response concerned change. Parnas argued that modules should hide design decisions likely to change, rather than merely mirror successive processing steps. For example, users of a queue should not need to know whether it stores items in an array or linked nodes. A module boundary is valuable when it prevents one implementation choice from spreading through the whole program. Parnas’s 1972 paper
Correctness, maintainability, and suitability are related but distinct. A program can satisfy its specification and still be hard to change; it can faithfully implement a specification that users do not need. The lesson for a learner is to ask separately: what is promised, why should the implementation keep that promise, and what happens when the promise or implementation changes? This turns software engineering from a collection of ceremonies into a study of dependencies and evidence.
1960s–1980s: Complexity, Feasibility, and the Limits of Efficient Computation
A computable problem need not be affordable to solve. Complexity theory asks how the resources required by a computation grow with its input, under a specified model. This complements measurement: an experiment tells us about particular machines and inputs, while an asymptotic analysis helps us reason about growth beyond those observations.
The theory of NP-completeness connected apparently unrelated decision problems through efficient reductions. If problem A can be transformed into problem B in polynomial time, an efficient general solver for B would also give one for A. The direction matters: reducing a known hard problem to your problem supports a hardness claim about yours. Reducing yours to something difficult does not establish that yours is difficult.
NP-completeness does not mean that every instance is hard, or that exponential time has been proved necessary. Whether P equals NP remains unresolved. Polynomial time is a powerful theoretical classification, not a guarantee that a program will meet a real deadline: constants, exponents, memory traffic, and input structure also matter.
For the beginner, compare finding a route that satisfies a few constraints with finding the best route among all possibilities. Adding “best” can change the problem dramatically. A useful next step may be an approximation, a heuristic, a restricted case, or a different specification, rather than simply a faster computer.
This gives you three distinct questions: can it be computed, how does the cost grow, and is this implementation useful for these inputs? Neither a proof nor a benchmark answers all three.
1960s–1980s: Operating Systems and the Governance of Resources
Operating systems grew through changing patterns of computer use. Batch systems tried to keep expensive machines busy by processing jobs with less manual intervention. Time-sharing made it possible for several people at terminals to interact with a machine. Real-time control imposed another requirement: a result could be useless if it arrived too late. These demands coexisted; operating systems were not invented solely for personal desktops or multi-user convenience.
A useful first distinction is between a program and a process. A program describes operations; a process is a running instance with state and resources. Two processes can execute the same program while holding different data. Scheduling lets them share processor time; memory management and protection help keep their execution contexts separate; file systems and system calls provide controlled access to persistent data and devices.
These abstractions create room for local reasoning. Your program can use a virtual address without tracking a memory chip, but someone must implement translation and protection. The abstraction has costs and limits. A private address space does not mean infinite memory, and a scheduler cannot make every workload fast at once.
Shared use also turns event order into a problem. If two processes both read a counter, add one, and write it back, one increment may disappear. Both additions can be arithmetically correct while the combined operation is wrong. Synchronization makes selected relationships between events explicit.
The lesson is that an operating system constructs an environment in which other programs can make useful assumptions. Learning it means studying both the assumptions offered to applications and the mechanisms that make them credible.
1970s–1990s: Databases and the Problem of Persistent Truth
Computers entered organizations with records, classifications, and workflows already in place. Punched-card systems and file-processing applications were part of that inheritance. The database problem was therefore more than finding room for bytes: how could several applications share changing records without depending on every detail of their storage?
Codd’s 1970 relational model made data independence a central objective. Users and programs should be less exposed to changes in the internal organization of data. Relations and declarative queries helped separate a logical question from a physical access plan. A query such as “which customers have unpaid orders?” need not specify which index to traverse. Codd’s original paper
Transactions address a different problem. Suppose a transfer debits one account and credits another. A crash between those steps must not leave half a completed transfer. Concurrent transfers must also respect the chosen isolation guarantees. Logging, recovery, and concurrency control supply mechanisms; merely calling two statements a “transaction” does not explain how those guarantees are implemented.
“Persistent truth” in this section’s title should be read carefully. A database preserves records and specified invariants, not truth about the world. It can faithfully retain a mistaken address, a duplicate identity, or a biased classification. A constraint such as “every order refers to an existing customer” is enforceable inside the model; whether that customer record represents the right person requires evidence from outside it.
For a beginner, separate what the data means, how it is organized, and what changes are allowed. This distinction connects schemas, queries, transactions, and data quality without pretending that one mechanism solves all four.
1970s–1990s: Networking and the Problem of Communication Between Machines
Computer networking developed around different needs, not one agreed destination. In the 1960s, Paul Baran investigated communications that could survive severe damage, Donald Davies pursued efficient communication for computer traffic, and ARPA pursued sharing expensive computing resources. Abbate’s history shows why these motivations should not be collapsed into the claim that the Internet was simply built to survive nuclear war.
Packet switching divides traffic into units that can share transmission capacity. This suits traffic that arrives in bursts: a conversation between computers need not reserve an idle circuit continuously. But sharing introduces queues, delay, loss, and congestion. Packet switching alone does not guarantee reliability or survivability; those depend on topology, capacity, protocols, and the failures assumed.
Internetworking adds another problem: how can independently designed networks cooperate without all becoming the same network? Common protocols and gateways allowed heterogeneity to remain behind a shared interface. The Internet and the Web are consequently different things: the Web is one information service built using Internet communication.
The endpoint perspective is easiest to grasp through a failure. A sender transmits a request; the receiver performs the action; the reply disappears. A timeout cannot tell the sender whether the action failed or merely the reply was lost. Reliable transport does not by itself ensure that an application action happens exactly once. The application needs its own way to recognize retries or reconcile state.
Users also changed what networks were for. Electronic mail became a major use of the ARPANET even though resource sharing had been a central justification. A system’s eventual value is shaped by the activities people build around it. Learning networks therefore means understanding both protocol mechanisms and the uses whose requirements those mechanisms must serve.
1980s–1990s: Human Interfaces and the Problem of Usability
Widespread graphical interfaces in the 1980s and 1990s drew on much earlier interactive work. Sketchpad, Engelbart’s work on augmenting human activity, and Xerox PARC’s systems helped explore how people could manipulate and inspect information directly. These efforts asked more than how to make a command line attractive: how could a computer become a medium for thinking and acting?
A user needs a workable model of actions and consequences. A visible selection, immediate feedback, and an undo operation can make an action easier to understand and safer to explore. Conversely, an interface can hide a consequential state change even when every internal computation is correct. The difficulty is the relationship between the user’s interpretation and the system’s behavior.
Interaction also changed system requirements. A batch job might prioritize throughput; an interactive drawing tool must respond quickly enough that an action and its result feel connected. Display hardware, input devices, memory, scheduling, and software design all contribute to that experience. Usability is not a finishing layer independent of the machine underneath it.
Human-computer interaction combines design with observation and experiment. Watching someone use an interface can reveal a misunderstanding that a proof about the implementation would never address. But a successful demonstration with one user does not establish universal usability: tasks, abilities, environments, and prior experience differ.
For a learner, ask someone else to use a small program without your spoken instructions. Where they hesitate is evidence about the model your interface communicates. This makes the human part of a computing system available for investigation, rather than treating it as an afterthought.
1980s–1990s: Security and the Problem of Adversarial Computation
Security did not begin when the Internet became popular. Cryptography had a much longer history, and shared computers already faced questions about who could read memory, alter files, or exercise privileged operations. Networking widened exposure and made those questions harder to contain within one institution.
The distinctive question is: what can someone do when they intentionally depart from expected use? Correctly processing a well-formed request is not enough. An attacker may choose unusual inputs, replay an earlier message, exploit a timing difference, or obtain more privilege than the designer intended.
Cryptography can establish particular properties under assumptions about algorithms, keys, and adversaries. A secure channel does not prove that the party at the other end should be trusted with the data. A sound encryption algorithm does not compensate for exposing its key. Protection, authentication, authorization, and confidentiality solve related but different problems.
A beginner can make this concrete with a file-sharing program. Identifying a user answers “who is requesting?” Checking permissions answers “may this user read this file?” Encryption can protect content in transit. None of these alone decides whether the file path supplied by the user should be accepted.
The lasting contribution of security is making trust assumptions explicit. State what must be protected, from whom, and under which conditions. Then examine the entire path by which those conditions are enforced. This turns a vague promise of safety into claims that can be challenged.
1980s–1990s: Object-Oriented Design, Reuse, and Large Software Organization
Object-oriented programming became widely influential in the 1980s and 1990s, but its roots reach back to Simula’s simulation work and later Smalltalk’s interactive environment. Objects offered a way to organize state together with operations on that state. Their appeal was connected to modeling and managing change, not merely to shortening repeated code.
Consider a simulated bank queue. Each customer can have its own arrival time and state, while a teller follows rules for serving customers. This representation makes some relationships easy to express. A different task—aggregating millions of records—may be better expressed as operations over collections. An object model is one choice of representation, not a requirement to reproduce every noun in the real world as a class.
Reuse depends on a reliable agreement. Two implementations may support the same operations while managing their internal state differently. Callers benefit when they can depend on that interface rather than the implementation. Inheritance can help express relationships, but it can also couple code to details of a parent class. Sharing code and preserving substitutability are not the same achievement.
The enduring question is which boundaries make change local? Sometimes the answer is objects; sometimes it is modules, functions, abstract data types, or a declarative data model. Study object-oriented design as one influential response to that question, alongside the alternatives, rather than as the inevitable culmination of programming languages.
Toward the Web: From Networked Machines to Global Information Space
By the late twentieth century, computers had become scientific instruments, business machines, interactive tools, and communication devices through partly overlapping developments. None of these roles made the Web inevitable. Hypertext research and existing Internet services offered ingredients; a particular information-management problem supplied a reason to combine them.
At CERN, documents, people, projects, and machines changed while useful knowledge was scattered among them. Berners-Lee’s 1989 proposal addressed this organizational difficulty through linked information. The problem was not simply to move more bits: it was to preserve connections between pieces of knowledge despite changes in location and responsibility. The original proposal
This is a useful turning point for a learner. A technical invention may come from changing what a system is for. Networking supplies communication; a linked information space requires additional agreements about names, documents, links, and access. Understanding the distinction makes it easier to see why networking, information retrieval, databases, and interface design remain separate subjects even when one browser brings them together.
1990s–2000s: The Web and the Problem of Global Information Access
The Web combined a small set of agreements: identifiers for resources, HTTP for exchanges between clients and servers, and HTML for documents containing links. A browser could follow those links without requiring each information provider to design a new client. These abstractions made independently maintained information easier to connect.
A consequential design choice was that a publisher could link to another document without obtaining permission from its owner or registering the link in one global catalogue. This reduced coordination costs, while allowing links to break when targets moved or disappeared. The architecture favored broad participation over guarantees that every relationship would remain intact.
Openness did not mean that access was equal or costless. People still needed equipment, connectivity, hosting, usable software, and often institutional support. Nor did the Web create networked services from nothing: remote access, mail, and file transfer already existed. Its contribution was a widely shared way to publish and navigate linked information, which subsequently became a platform for applications.
For a beginner, distinguish a resource’s name, the protocol used to request it, and the representation returned. A URL is not the document itself. A successful HTTP exchange does not establish that its content is correct. A browser displaying a page does not reveal every service behind it.
These boundaries explain both the Web’s reach and its later problems. Decentralized publication supports growth; discovery, authenticity, persistence, and abuse require additional mechanisms. Simple shared agreements can make a system extensible without solving every problem at the same layer.
Late 1990s–2010s: Search and the Problem of Relevance at Scale
As the Web grew, the central problem shifted from access to discovery. Publishing information was no longer enough. Users needed to find relevant information among billions of documents. The question became: how can a system decide what is useful, authoritative, fresh, and relevant for a particular query?
This was not a simple database lookup problem. A database query usually assumes structured data and clear semantics. Web search had to operate over messy, heterogeneous, constantly changing documents. A page could contain the right words and still be useless. Another page might not match the query exactly but might better satisfy the user’s intent. Queries were short, ambiguous, and context-dependent. The Web also contained manipulation, duplication, spam, and outdated material.
Search therefore became an integrated CS problem. It required crawling the Web, building indexes, ranking documents, understanding queries, fighting manipulation, serving results at low latency, and evaluating whether users were satisfied. The inverted index was central to retrieval, but ranking required more than term matching. Link structure, textual relevance, freshness, user behavior, authority signals, and later machine learning all became part of search.
Web search expanded the scale and commercial importance of data-driven evaluation, building on earlier information-retrieval experiments. A search engine could not be judged only by formal correctness, because there was often no single correct result. It had to be judged by relevance, usefulness, and user behavior. This made offline metrics, human evaluation, click logs, and online experiments important. The system improved not only through theoretical analysis but through continuous measurement.
Search changed CS because it made ranking a central computational operation. Earlier systems often returned exact answers from structured data. Search systems returned ordered approximations of relevance. This anticipated many later systems: recommendation engines, social media feeds, advertising platforms, content moderation systems, and AI assistants. In all of these, the system does not simply retrieve a known object. It estimates what should be shown, recommended, hidden, or generated.
The deeper lesson was that at large information scale, computation often becomes inference over imperfect signals. Exact correctness remains important in the infrastructure, but the user-facing result may be probabilistic, ranked, and context-sensitive. This pushed CS further toward statistics, machine learning, experimentation, and human-centered evaluation.
2000s–2010s: Internet-Scale Systems and the Problem of Continuous Operation
Once web services attracted millions and then billions of users, another problem became dominant: how can a system remain fast, reliable, secure, and maintainable under massive scale and constant change?
This was different from building a program that runs correctly once. An internet-scale service is always operating. It receives unpredictable traffic, stores changing data, depends on other services, runs across many machines, undergoes frequent deployment, and faces continuous security threats. It cannot assume that hardware is reliable or that the network is stable. At sufficient scale, failure is not exceptional. It is normal.
This period made distributed systems and operational engineering central to everyday software practice. Large services required replication, sharding, load balancing, distributed storage, caching, asynchronous processing, queueing, monitoring, logging, tracing, deployment automation, rollback strategies, and incident response. Systems had to be designed not only for normal execution but for degraded operation, partial failure, overload, and recovery.
The emergence of cloud computing also changed the economic and architectural basis of software. Organizations no longer needed to own every physical machine they used. Computing, storage, networking, databases, and later machine learning services could be rented through programmable interfaces. Infrastructure became elastic, abstracted, and API-driven. This made it easier to build large systems, but it also created new layers of dependency.
The methodological shift was toward operational systems thinking. A mature service is not defined only by its source code. It is defined by how it behaves in production. Does it recover from failure? Can it be observed? Can it be deployed safely? Can it handle load spikes? Can engineers understand incidents? Can security patches be applied quickly? Can the cost be controlled?
This changed the meaning of reliability. Reliability was no longer a final property added after implementation. It became a continuous discipline. The system had to be measured, operated, repaired, and evolved. Incident reports, service-level objectives, capacity planning, and observability became part of the knowledge structure of modern CS practice.
The lesson of this period is that at internet scale, software becomes a living system. It is never simply “finished.” It is deployed, monitored, updated, defended, and reorganized over time.
2000s–2010s: Platforms and the Problem of Ecosystem Governance
As internet systems matured, some systems became more than applications. They became platforms. A platform is not only a tool used by end users. It is an environment in which other users, developers, businesses, advertisers, creators, institutions, and services act. This changed the central problem again: how can a computational system organize and govern an ecosystem?
Platforms include operating system ecosystems, app stores, social networks, search platforms, cloud platforms, payment systems, development platforms, and content platforms. Their technical architecture determines what other actors can do. APIs define access. Permission systems define authority. Ranking systems define visibility. Moderation systems define acceptable behavior. Identity systems define trust. App review systems define distribution. Logging and analytics define what can be measured.
This period made it harder to separate technical design from institutional design. A platform’s architecture is also a governance structure. A rate limit is not only a performance control; it may shape market access. A permission model is not only a security mechanism; it determines what kinds of applications can exist. A recommendation algorithm is not only an optimization system; it shapes attention and public discourse. A cloud interface is not only an engineering convenience; it changes how organizations build and operate software.
The difficulty of platforms lies in balancing openness and control. If a platform is too closed, it may not attract developers or users. If it is too open, it may enable abuse, fraud, privacy violations, spam, malware, or ecosystem instability. This made trust boundaries, policy enforcement, developer relations, security review, and abuse detection central to platform design.
The methodological shift was toward architecture as governance. In earlier software, architecture mainly organized complexity. In platforms, architecture also organizes power. The design of interfaces, permissions, policies, and defaults determines what actors can do and what harms become likely.
This is one reason modern CS increasingly intersects with law, economics, sociology, political theory, and ethics. Platforms are computational systems, but their effects are social. They mediate communication, commerce, labor, creativity, knowledge, and institutional authority. The lesson is that large software systems do not merely process information. They structure environments in which people act.
2010s: Mobile and Ubiquitous Computing and the Problem of Context
The rise of smartphones moved computation from desks into pockets, homes, streets, vehicles, and bodies. The central problem became: how can computation adapt to the user’s context while respecting constraints of battery, privacy, attention, connectivity, and physical movement?
Mobile devices were not simply smaller personal computers. They had sensors, cameras, microphones, touchscreens, GPS, accelerometers, wireless radios, biometric mechanisms, and constant network connections. They moved with users and collected contextual data. Applications could respond to location, motion, contacts, time, notifications, and personal habits.
This made mobile computing both powerful and risky. A mobile device could help with navigation, communication, payment, photography, health tracking, language learning, and work. But it could also expose location, behavior, identity, contacts, and private content. The same context-awareness that made applications useful also increased privacy sensitivity.
Mobile systems required integration across many CS areas: operating systems, networking, HCI, security, databases, distributed services, cloud synchronization, sensor processing, and machine learning. The smartphone became a client in a larger distributed system. Many mobile applications were only partly local; they depended on cloud services, identity systems, maps, search, recommendation, push notification, and remote storage.
The methodological shift was toward context-aware design. Designers had to ask not only what the software does, but where it is used, when it interrupts, what data it senses, what it can do offline, what permissions it requests, what latency is tolerable, and what risks it creates. This made user experience, privacy, and systems design tightly connected.
Mobile computing also intensified the social presence of computation. It entered attention, movement, memory, social relationships, health, commerce, and everyday decision-making. The lesson is that when computation becomes ubiquitous, context becomes part of the system. A system is no longer defined only by its code and data. It is also defined by when, where, how, and by whom it is used.
2010s: Deep Learning and the Problem of Learned Representation
Deep learning’s successes in the 2010s were a major change in practical capability, not the beginning of learning or neural approaches in AI. The 1955 Dartmouth proposal already discussed learning and neural networks. Early pattern recognition investigated statistical and neural methods, while other researchers pursued search, symbolic reasoning, and planning. These approaches overlapped and competed rather than forming a clean relay race. The Dartmouth proposal
Nilsson’s history provides a useful contrast. A theorem-proving program searches among explicitly represented expressions and inference steps. A pattern recognizer must extract distinctions from variable sensory input. DENDRAL combined search with chemical knowledge to constrain candidate molecular structures. These examples show that how a problem is represented and what prior knowledge is supplied can matter as much as a general search procedure.
For a handwritten-digit recognizer, one approach is to design features such as loops or strokes. A neural model instead adjusts parameters so that intermediate transformations become useful for the training objective. Deep learning made learning multiple layers of representation practically effective for many tasks through developments in methods, data, computation, and software. It did not eliminate the designer’s choices of data, architecture, objective, or evaluation.
Separate training performance from generalization. A model may fit examples it has seen while failing on new handwriting, a different scanner, or an unfamiliar population. Training by an algorithm does not make an empirical claim about future inputs into a proof. Keep evaluation data separate and ask whether its conditions resemble the intended use.
Finally, successful task performance does not by itself show that a system explains human cognition. Boden’s history emphasizes the breadth of cognitive science, including perception, action, emotion, and multiple kinds of explanation. For learning AI, distinguish building a useful artifact, predicting behavior, and explaining a mind. They can inform one another without being the same achievement.
2010s–2020s: Data Infrastructure and the Problem of the Data Lifecycle
As machine learning and analytics became central, CS had to confront a less glamorous but fundamental problem: how can data be collected, cleaned, transformed, governed, versioned, and used reliably over time?
Models depend on data, but data is not a natural substance that simply exists. It is produced by instruments, users, institutions, platforms, sensors, logs, labels, and historical decisions. It may be incomplete, biased, duplicated, stale, noisy, private, or legally restricted. Its meaning depends on schemas, collection processes, definitions, and context.
This made data engineering a central part of modern computing. A reliable data system needs extraction, transformation, loading, validation, lineage tracking, access control, schema management, quality monitoring, privacy controls, and reproducibility. In machine learning, the data lifecycle also includes labeling, feature construction, training set construction, evaluation set design, drift detection, and model monitoring.
The main shift was from treating data as input to treating data as infrastructure. In a mature organization, data is not merely stored. It is governed. People need to know where it came from, who can use it, how it was transformed, whether it is fresh, whether definitions have changed, whether it contains sensitive information, and whether analyses can be reproduced.
This period also revealed that many AI failures are data failures. A model may perform poorly because the training data is unrepresentative. A metric may mislead because labels are flawed. A dashboard may be wrong because definitions changed. A deployed model may degrade because the world changed after training. The quality of computation increasingly depends on the integrity of the data lifecycle.
The lesson is that modern CS is not only algorithm-centered. It is also pipeline-centered. Trustworthy computation requires trustworthy data processes.
2020s: Foundation Models and the Problem of General-Purpose Learned Capability
In the 2020s, the focus shifted from task-specific models to large, general-purpose learned systems. The central problem became: how can broad models trained on massive data be adapted, controlled, evaluated, and integrated into real systems?
Foundation models changed the interface between users and computation. Earlier software usually exposed specific functions. A foundation model exposes flexible capabilities: writing, summarizing, translating, coding, classifying, explaining, generating images, answering questions, using tools, and transforming information across modalities. The same base model may support many tasks through prompting, fine-tuning, retrieval, tool use, or system integration.
This created new power and new instability. A model may produce fluent language without being truthful. It may solve one task well and fail unexpectedly on another. It may encode bias, leak memorized information, follow misleading instructions, or be manipulated by adversarial prompts. Its behavior is probabilistic and context-sensitive. It may be difficult to specify all intended and unintended uses in advance.
The major breakthrough came from the combination of transformer architectures, large-scale pretraining, large datasets, massive compute, instruction tuning, reinforcement from human feedback, retrieval augmentation, multimodal modeling, and deployment through APIs and products. But the deeper change was architectural. A model became a reusable capability layer inside larger systems.
This shifted design practice toward model-centered system design. Engineers now ask what context the model receives, what tools it can call, what data it may access, what outputs require verification, where deterministic code should be used, where human review is necessary, how failures are detected, and how risks vary by domain. A foundation-model application is not just a model. It is a system involving retrieval, prompts, policies, interfaces, logging, evaluation, permissions, and fallback behavior.
Foundation models also changed programming education and software work. AI-assisted programming can accelerate coding, but it can also conceal misunderstanding. The developer still needs to understand requirements, architecture, testing, security, performance, and maintainability. The model can produce code, but it cannot remove the need for judgment.
The lesson is that foundation models do not make CS foundations obsolete. They make them more important, because more behavior becomes indirect, learned, probabilistic, and difficult to inspect.
2020s: AI Evaluation, Safety, and the Problem of Trustworthy Learned Behavior
As AI systems became more capable and more widely deployed, the next problem became: how can learned systems be evaluated, constrained, monitored, and governed when their behavior cannot be fully specified in advance?
Traditional software often begins with a specification. One can write tests for expected behavior. AI systems complicate this because their outputs are probabilistic, open-ended, and context-sensitive. A model may pass benchmarks and still fail in deployment. It may perform well on average while failing badly in rare or high-stakes cases. It may be useful for one population and harmful for another. It may appear confident when wrong.
Evaluation has been central to AI throughout its history; broader deployment increases the variety and stakes of what must be checked. Evaluation includes benchmarks, human review, red teaming, adversarial testing, robustness analysis, calibration, interpretability work, monitoring, misuse analysis, and post-deployment auditing. The challenge is not simply to maximize performance. It is to understand the relationship between capability and risk.
This period shifted method from performance optimization to capability-risk assessment. A powerful system is not automatically a good system. Its value depends on where it is used, who is affected, what errors cost, whether users understand its limits, whether outputs can be verified, whether misuse is likely, and whether there is accountability.
AI safety also forces CS to confront incomplete specifications. In many domains, the desired behavior is not purely technical. It involves human values, institutional norms, legal constraints, and contextual judgment. This does not mean abandoning technical rigor. It means expanding the set of constraints that technical design must respect.
The lesson is that for powerful learned systems, success means more than high capability. It means controlled, evaluated, accountable behavior under realistic conditions.
2020s: Privacy, Security, and the Problem of Computation Over Sensitive Data
Privacy concerns predate contemporary AI and large online platforms. Expanding data collection and model deployment sharpened an existing problem in computing. The question became: how can useful computation happen without creating unacceptable exposure, surveillance, or inference power?
Earlier security often focused on protecting systems from unauthorized access and malicious modification. Privacy adds a different concern. Even authorized data use can be harmful if data is aggregated, retained, inferred from, or repurposed. Removing names is not enough. Location traces, search histories, social graphs, biometric signals, writing patterns, and behavioral logs can reveal sensitive information. Different datasets can be combined to produce new forms of identification and prediction.
This changed the technical meaning of privacy. Privacy is not only secrecy. It is also control over inference. A system may never reveal a raw record and still expose information through aggregate statistics, model outputs, metadata, or access patterns. Machine learning adds another layer because models can memorize, leak, or encode sensitive information from training data.
Several technical approaches became more important: differential privacy, federated learning, secure multi-party computation, homomorphic encryption, trusted execution environments, access controls, data minimization, and privacy-preserving analytics. None of these is a universal solution. Each offers a way to reduce certain kinds of exposure under certain assumptions.
The methodological shift was toward privacy by design. A mature system asks whether data is needed at all, whether less data can be collected, whether computation can happen locally, whether data can be aggregated safely, whether retention can be limited, whether users can understand the data flow, and whether sensitive inference is possible even when direct identifiers are removed.
The lesson is that privacy is a system property. It depends on architecture, data flows, incentives, interfaces, law, and institutional practice. In modern CS, protecting data means protecting people from harmful inference and unequal power.
2020s: Cyber-Physical and Edge Systems and the Problem of Computation in the World
Real-time control and computing in physical environments have a long history. Recent cyber-physical and edge systems extend that history through denser sensing, connectivity, and learned components. The central problem became: how can systems sense, decide, and act safely under physical constraints?
This includes robotics, autonomous vehicles, drones, smart homes, industrial control, medical devices, wearables, sensor networks, and edge AI. These systems differ from ordinary software because they act in the world. A failure may not merely produce a wrong output. It may cause physical damage, injury, privacy loss, or environmental disruption.
Cyber-physical systems must handle noisy sensors, uncertain environments, real-time constraints, limited energy, intermittent connectivity, hardware failure, and human unpredictability. They combine embedded systems, operating systems, networking, control theory, signal processing, computer vision, machine learning, safety engineering, and hardware-software co-design.
Edge computing became important because not all computation can or should happen in the cloud. Some tasks require low latency, local reliability, privacy protection, or reduced bandwidth. A device may need to make decisions even when disconnected. This creates a new balance between local computation and centralized infrastructure.
The methodological shift was toward real-time and safety-aware design. Designers must ask what happens if a sensor fails, if a network connection disappears, if a model is uncertain, if an actuator behaves unexpectedly, or if a human intervenes. The system must often have safe fallback states. Timing becomes part of correctness.
The lesson is that when computation acts in the physical world, abstraction cannot ignore embodiment. Latency, energy, uncertainty, and safety become first-class constraints.
2020s and Beyond: Socio-Technical Computing and the Problem of Governance
Governance is a longstanding concern in computing, from institutional record keeping and access control to standards and network administration. Large platforms and AI deployments give these questions additional forms and urgency. Computational systems now shape communication, education, labor, law, finance, medicine, culture, public administration, and political life. The central question becomes: how should computational systems be designed and governed when they organize social reality?
This is not separate from technical CS. Ranking systems, recommendation systems, search engines, identity systems, moderation tools, fraud detectors, hiring algorithms, educational platforms, risk models, and AI assistants are technical systems. But their effects are social. They affect what people see, what opportunities they receive, how institutions make decisions, and how power is distributed.
This creates problems that cannot be solved only through better algorithms. One must ask who benefits, who is harmed, who can appeal, who understands the system, who audits it, who controls the data, which errors are tolerable, and which values are embedded in the design. A technically accurate system may still be unjust, illegitimate, inaccessible, or harmful in context.
The methodology of CS therefore expands again. It must include fairness evaluation, interpretability, transparency, accountability, privacy, human-in-the-loop review, legal compliance, institutional design, and public-interest analysis. This does not mean technical rigor becomes less important. It means technical rigor must operate within a wider account of social consequence.
Socio-technical computing also changes the meaning of responsibility. A system’s effect is not determined only by its code. It is shaped by deployment context, incentives, users, institutions, feedback loops, and governance structures. A recommendation algorithm may change what people produce. A moderation system may change speech norms. An AI assistant may change how people learn or work. A risk model may change access to resources.
The lesson is that modern CS is no longer only about computation inside machines. It is also about computation inside society. This is why ethics, law, policy, and institutional analysis are not external decorations. They become part of understanding what computational systems actually do.
The Long Arc: CS as Expanding Constraint Management
The historical pattern is not a succession in which one field finishes its work and hands the result to the next. Calculation, record keeping, communication, control, and attempts to understand intelligence developed through different communities and institutions. The recurring achievement was to find a representation, an abstraction, or an arrangement of people and machines that made a previously difficult activity manageable.
“Expanding constraint management” is useful as a synthesis, but it should not define away the rest of computer science. Some research proves impossibility; some explains an existing system; some invents a new medium or discovers a new use. Reliability is one important objective among expressiveness, understanding, efficiency, accessibility, and other goals that can conflict.
The history supplies a set of questions for the rest of this guide. With algorithms, ask what representation makes the procedure possible and how its cost grows. With languages and architecture, ask what the interface promises and what the implementation may change. With operating systems, databases, and networks, ask which assumptions remain valid under sharing or failure. With AI, ask which knowledge is supplied, which is learned, and what evidence supports generalization. With every application, ask whose activity is being represented and whose needs the design serves.
These connections explain why earlier subjects remain useful. A learned model still executes through programs and hardware; an online service still depends on records, protocols, and human interpretation. New work often changes the relative importance of an old problem rather than making that problem disappear.
Use history to recognize a problem before memorizing its solution. You should leave a section able to say not only what a technique is called, but why someone needed it, what it makes easier, and what you must still check yourself.
中文
这段历史是一张帮助你理解本指南中的各个主题为什么会出现的地图。它沿着反复出现的问题展开:表示信息、表达过程、共享机器、保存记录、通信和学习,让陌生的学科名称有地方可以依附。标题中的年代表示某种发展或广泛应用的时期,并非界限分明的时代的起止点。
这里交汇着三种历史。计算发展史包括人的计算活动、机械装置、办公室、实验室与通信;计算机科学发展史关注那些使计算成为系统研究对象的概念、方法和学科建制;AI 发展史则加入了解释或建造智能行为的尝试。这些线索相互影响,却没有沿着理论、硬件、软件、智能的单一路线依次前进。
阅读每一节时都可以问:当时的人试图克服什么困难,哪一种表示或抽象使进展成为可能,这个解法又留下了什么? 最后的总结用“不断扩展的约束”作为一种组织视角。它用于比较学科主题,不意味着历史早就有了注定的终点。
1930s–1950s:计算的形式化
什么使一个过程成为“机械可执行”的过程? 这个问题在 1930 年代获得了精确的数学形式,但把计算机械化的尝试早得多。巴贝奇在十九世纪设计差分机,是为了制作数学用表;后来的分析机设计,则希望通过指令组织广泛得多的操作。洛夫莱斯在 1843 年的注释中认识到:如果其他事物的关系能够被适当表示,对数字的操作就可以代表对那些事物的操作。分析机在他们生前没有建成,后来的计算机制造者也并非只是沿着连续传承的巴贝奇蓝图进行实现。
这段更早的历史给新手提供了第一个抓手:机器操作的是表示。数字可以代表数量、音乐关系或符号。能够操作一种编码,与理解它所代表的一切,并不是一回事。
逻辑学家关心的是有效过程的边界。图灵机模型和丘奇的 lambda 演算,把这样的过程明确地表达为数学对象。一阶逻辑的判定问题要求一种总能判断公式是否逻辑有效的过程,而不是承诺解决所有含糊表达的问题。丘奇和图灵确立了它的不可判定性。图灵的分析也奠定了现代停机问题的基础:不存在一个算法,能对所有程序及其输入判断执行是否最终终止。这并不妨碍我们证明特定程序会终止。图灵 1936 年论文
丘奇—图灵论题把“有效过程”这一非形式化概念与形式化的可计算性联系起来。形式模型之间的等价性可以证明;这个论题却不只是另一条同类定理。通用机能够模拟模型中的其他机器,但通用性既不承诺现实资源无限,也不承诺智能。
值得一直保留的区分是:一个疑问、一个精确的问题规格,以及解决它的过程。早在学习不可判定性证明之前,学会区分它们就很有用。
1940s–1960s:从形式程序到物理机器
实际计算机来自多种实践传统,包括数值计算、穿孔卡数据处理、通信与战时工程。它们并不只是已经完成的可计算性理论的下游应用。继电器、真空管、存储装置,以及用户的需要,共同决定了制造者能做出什么。核心问题是:怎样可靠、快速,并以可接受的成本执行一串规定的操作?
逻辑与工程之间有一项具体联系:Shannon 在 1938 年发表的开关电路分析。若用开关闭合表示真,两个串联开关只有同时闭合才能导通,对应与运算;并联支路中只要有一个开关闭合就能导通,对应或运算。因此,可以用布尔表达式描述开关连接,再通过代数恒等式调整电路而保持逻辑行为。这使逻辑成为电路设计的工具。要造出可靠的机器,仍需处理物理延迟、存储和元件故障。
有必要分开三个经常被混在一起的概念。机器可以是自动的,不必由人反复干预就能执行一串操作;可以是可编程的,通过改变指令来改变行为;也可以采用存储程序方式,把可执行指令保存在内部存储器里。可编程性早于电子存储程序计算机。把指令保存为可以操作的编码,使装载、翻译和许多软件构造工作便利得多。
存储程序思想通过多个参与者和项目逐渐成形。“冯·诺依曼体系结构”这个熟悉的名称,不应抹去埃克特、莫奇利等 ENIAC、EDVAC 团队成员的贡献,也不应把复杂的发展写成一个人的孤立发明。它也不等同于数学上的通用性:前者涉及实际机器的组织,后者涉及一个模型模拟计算的能力。
Haigh 与 Ceruzzi 的历史研究提供了第二个有用区分:理论上的通用性与实际用途的广泛性。一台机器在原理上可能很通用,实际却只有少数专家能用它完成有限任务。存储、输入输出、软件、成本与使用机会,决定了它能否成为办公工具、交互式仪器或通信媒介。
学习体系结构时,可以跟踪一条指令在机器中的执行,再问程序员需要看见哪些细节。指令集描述对外可见的约定;不同的内部实现可以支持同样的约定,却具有不同性能。这种稳定描述与变化中的实现之间的区别,会在语言、操作系统和数据库中再次出现。
1950s–1970s:从机器控制到编程抽象
随着编程工作积累,程序员需要保存和复用已经获得的经验。子程序库与符号记法减少了重复劳动;编译器让一些任务可以用更接近问题、而非特定机器的记法表达。问题是:哪些细节必须由程序员管理,哪些可以可靠地交给工具?
并不存在一架单一的梯子,让每种新语言都取代一个更落后的前辈。Fortran 服务于数值工作;COBOL 表达商业记录及其处理;Lisp 让符号表达式和递归操作更加便利;ALGOL 推进了块结构、作用域与精确公开的语法描述。它们回答的是不同群体的问题。Knuth 与 Trabb Pardo 的历史研究,把同一个算法写成多种早期语言进行比较;这种方法能看见发行年份列表无法揭示的区别。
记法能改变思考的难度。在算术表达式中,具名变量和嵌套结构,使读者不必从一串内存传送中重建意图。过程让我们围绕输入、输出和假设理解一项任务。但较高层的描述仍然需要实现;编译器必须保持语言已经定义的行为,而不是猜测程序员希望表达什么。
ALGOL 的影响也说明了,为什么语言设计会成为研究对象。对语法形式达成一致,并不能自动解决所有语义、实现或可用性问题。形式语义、类型系统和语言实现,正是在这些间隙周围发展起来的。不同编程范式强调组织计算的不同方式,却不一定具有不同的可计算能力。
对初学者,可以比较同一个小任务的两种实现,观察各自要求你明确作出哪些决定。当抽象减轻一种负担,同时保留你仍然需要的区别时,它才有用。
1960s–1970s:软件危机与纪律化的必要
大型程序暴露了依靠个人记忆和非正式协调的局限。“软件危机”这个名称汇集了对成本、进度、可靠性以及修改困难的担忧。1968 年的 NATO 会议帮助软件工程成为公开议题,但问题与应对方式都不是在一次会议上突然诞生的,参与者也没有就唯一疗法达成一致。
一种回应,是让推理能够更局部地进行。结构化程序设计寻求易于跟踪和论证的控制结构;形式化方法把程序行为与明确的规格说明联系起来;测试则提供关于选定执行实例的证据。它们回答不同的需要:测试可以暴露反例,证明则只在规定的模型和假设下确立性质。Dijkstra 的工作尤其鲜明地指出了仅靠测试的局限。《结构化程序设计札记》
另一种回应涉及变化。Parnas 主张,模块应隐藏可能变化的设计决定,而不只是对应连续的处理步骤。例如,使用队列的人不应必须知道元素保存在数组还是链式节点中。如果一个模块边界能够阻止某项实现选择蔓延到整个程序,它才有价值。Parnas 1972 年论文
正确性、可维护性与是否适合用途相互关联,却是不同的性质。程序可以满足规格,却很难修改;也可以忠实实现一份用户根本不需要的规格。学习时值得分别问:承诺了什么,为什么相信实现能兑现承诺,以及承诺或实现变化时会发生什么? 这让软件工程从一套仪式,变成对依赖关系与证据的研究。
1960s–1980s:复杂性、可行性与高效计算的边界
可计算的问题,未必付得起求解成本。复杂性理论在规定的模型下,研究计算需要的资源如何随输入增长。它与测量互补:实验告诉我们特定机器与输入上的表现,渐近分析则帮助我们推理超出这些观测范围的增长趋势。
NP 完全性理论通过高效归约,把表面上无关的判定问题联系起来。如果问题 A 能在多项式时间内变换为问题 B,那么 B 的高效通用求解器也会给出 A 的高效解法。方向很重要:把已知困难的问题归约到你的问题,才能支持关于你的问题的困难性结论;把你的问题归约到一个困难问题,并不能证明你的问题也困难。
NP 完全不意味着每个实例都难,也不意味着已经证明必须花费指数时间。P 是否等于 NP 仍未解决。多项式时间是一种有力的理论分类,却不保证程序能在现实期限内完成:常数、指数、内存访问和输入结构也很重要。
对初学者,可以比较“找一条满足若干约束的路线”和“从所有可能中找出最好的路线”。加上“最好”可能显著改变问题。有用的下一步可能是近似、启发式、限制问题范围,或改变规格,而不只是换一台更快的计算机。
这里出现了三个不同的问题:能否计算,成本怎样增长,以及这个实现对这些输入是否有用? 单独一个证明或基准测试,都不能回答全部三个问题。
1960s–1980s:操作系统与资源治理
操作系统随着计算机使用方式的变化而发展。批处理系统希望减少人工干预,让昂贵的机器持续处理作业;分时系统让多个人能够通过终端与一台机器交互;实时控制则提出了另一项要求:结果来得太晚,也可能毫无用处。这些需求同时存在。操作系统并不是仅仅为了个人桌面或多人使用方便而发明的。
第一个有用的区别是程序与进程。程序描述操作;进程是带有状态和资源的运行实例。两个进程可以执行同一个程序,却持有不同数据。调度使它们共享处理器时间;内存管理与保护帮助隔离执行环境;文件系统与系统调用提供对持久数据和设备的受控访问。
这些抽象为局部推理创造了条件。程序可以使用虚拟地址,而不必追踪内存芯片,但总得有人实现地址转换与保护。抽象有成本,也有边界:私有地址空间不等于无限内存,调度器也无法让所有工作负载同时变快。
共享使用还会让事件顺序成为问题。如果两个进程都读取计数器、加一、再写回,一次增加可能消失。两次加法在算术上都正确,组合操作却可能错误。同步让事件之间需要维持的关系得到明确规定。
操作系统的意义在于:构造一个让其他程序能够作出有用假设的环境。学习它,既要研究向应用提供的假设,也要研究使这些假设可信的机制。
1970s–1990s:数据库与持久真相的问题
计算机进入组织时,那里早已有记录、分类方式和工作流程。穿孔卡系统和文件处理应用,都是这一历史的一部分。因此,数据库问题不只是给字节找地方:怎样让多个应用共享不断变化的记录,而不必依赖存储的每个细节?
Codd 在 1970 年提出的关系模型,把数据独立性置于核心位置。用户和程序应当较少受到数据内部组织变化的影响。关系与声明式查询,帮助人们把逻辑问题和物理访问计划分开。“哪些客户有未付款订单?”这样的查询,不必规定应遍历哪个索引。Codd 原始论文
事务处理的是另一个问题。假设转账先从一个账户扣款,再向另一个账户入账,两步之间发生崩溃,不应留下半笔已完成的转账。并发转账还必须遵守所选择的隔离保证。日志、恢复和并发控制提供实现机制;仅仅把两条语句称为“事务”,并没有解释这些保证怎样成立。
本节标题中的“持久真相”需要谨慎理解。数据库保存的是记录和规定的不变量,而不是关于现实的真理。它可以忠实保存错误地址、重复身份或带偏差的分类。“每个订单都指向一个存在的客户”这类约束,可以在模型内部实施;客户记录是否代表正确的人,则需要模型外部的证据。
对初学者,要区分数据意味着什么、怎样组织,以及允许发生哪些变化。这个区分能把模式、查询、事务和数据质量联系起来,而不假装一种机制可以解决全部问题。
1970s–1990s:网络与机器之间通信的问题
计算机网络围绕不同需求发展,并非一开始就朝着共同终点前进。1960 年代,Paul Baran 研究能在严重破坏后继续工作的通信;Donald Davies 寻求适合计算机流量的高效通信;ARPA 则推动昂贵计算资源的共享。Abbate 的历史研究说明,为什么不能把这些动机合并成“互联网就是为了在核战争中生存而建造的”。
分组交换把流量分成可以共享传输容量的单元。这适合突发式流量:计算机之间的一次通信不必持续预留一条闲置电路。但共享也引入排队、延迟、丢失和拥塞。分组交换本身不保证可靠性或抗毁性;这些性质取决于拓扑、容量、协议,以及所假设的故障。
网际互联又增加了一个问题:独立设计的网络,怎样协作而不必全部变成同一种网络?共同协议与网关,使异质性能够保留在共享接口之后。因此,互联网与 Web 是不同事物:Web 是利用互联网通信建立的一种信息服务。
通过一次故障,最容易理解端点的视角:发送者发出请求,接收者完成操作,但回复丢失了。一次超时无法告诉发送者,是操作失败了,还是仅仅回复丢失。可靠传输本身,并不能确保应用操作恰好发生一次。应用还需要识别重试或协调状态的机制。
用户也会改变网络的用途。虽然资源共享是 ARPANET 的重要立项理由,电子邮件却成为它的一项主要用途。系统最终的价值,也由人们围绕它建立的活动塑造。 因此,学习网络既要理解协议机制,也要理解这些机制必须服务的使用需求。
1980s–1990s:人机界面与可用性问题
1980 至 1990 年代广泛出现的图形界面,继承了更早的交互式研究。Sketchpad、Engelbart 增强人的活动的工作,以及 Xerox PARC 的系统,都探索了人怎样直接操作和检查信息。这些努力问的不只是如何让命令行更好看,而是:计算机怎样成为思考和行动的媒介?
用户需要一个能理解动作及其后果的模型。清晰可见的选中状态、即时反馈和撤销操作,可以让动作更容易理解,也让探索更安全。反过来,即使所有内部计算都正确,界面仍可能隐藏一个影响重大的状态变化。难点在于用户的理解与系统行为之间的关系。
交互还改变了系统需求。批处理作业可能优先考虑吞吐量;交互式绘图工具则必须足够快地响应,使动作与结果在感觉上连在一起。显示硬件、输入设备、内存、调度和软件设计,共同决定这种体验。可用性不是独立于底层机器的最后一道装饰。
人机交互把设计与观察、实验结合起来。观察一个人使用界面,可以揭示实现正确性的证明根本不会回答的误解。但对一个用户演示成功,也不等于普遍易用:任务、能力、环境和既有经验都有差异。
学习时,可以让别人不听你的口头指导,使用你写的小程序。他们犹豫的地方,就是界面正在传达什么模型的证据。 这样,计算系统中的人也成为可以调查研究的一部分,而不是事后才考虑的因素。
1980s–1990s:安全与对抗性计算的问题
安全并不是互联网普及之后才出现的。密码学有长得多的历史,共享计算机也早已面对谁能读取内存、修改文件或执行特权操作的问题。联网扩大了暴露范围,使这些问题更难被限制在单个机构之内。
安全的独特问题是:如果有人故意偏离预期用法,他能做什么? 正确处理格式正常的请求还不够。攻击者可能选择异常输入、重放早先的消息、利用时间差,或获得超出设计意图的权限。
密码学可以在关于算法、密钥和攻击者的假设下,建立特定性质。安全信道并不能证明另一端值得托付数据;可靠的加密算法也无法补偿密钥被直接泄露。保护、认证、授权和保密,解决的是相关却不同的问题。
初学者可以用文件共享程序把它具体化。识别用户回答“谁在请求”;检查权限回答“这个用户能否读取这个文件”;加密可以保护传输中的内容。但它们任何一项,都不能单独决定用户提交的文件路径是否应该被接受。
安全留下的持久贡献是:把信任假设明确写出来。说明保护什么、防范谁、在哪些条件下成立,再检查这些条件被实施的完整路径。这样,含糊的安全承诺就变成了可以被质疑的主张。
1980s–1990s:面向对象设计、复用与大型软件组织
面向对象编程在 1980 至 1990 年代产生了广泛影响,但其根源可以追溯到 Simula 的模拟工作,以及后来的 Smalltalk 交互环境。对象提供了一种把状态与操作该状态的行为组织起来的方法。它的吸引力与建模和管理变化有关,而不只是减少重复代码。
考虑一个模拟银行排队的程序。每位顾客可以有自己的到达时间与状态,柜员则遵循服务顾客的规则。这种表示让一些关系容易表达。另一项任务——汇总数百万条记录——也许更适合表达为对集合的操作。对象模型是一种表示选择,不要求把现实中的每个名词都复制成一个类。
复用依赖可靠的约定。两种实现可以提供相同操作,却采用不同的内部状态管理方式。如果调用者能依赖接口,而非实现细节,就能从中获益。继承可以帮助表达关系,也可能让代码耦合到父类的细节。共享代码与保持可替代性,并不是同一个成就。
持久的问题是:什么边界能让变化保持局部? 有时答案是对象,有时是模块、函数、抽象数据类型,或声明式的数据模型。应该把面向对象设计作为这个问题的一种重要回应,与其他选择一起学习,而不是把它当作编程语言注定到达的终点。
走向 Web:从联网机器到全球信息空间
到了二十世纪后期,计算机通过部分重叠的发展,成为科学仪器、商业机器、交互工具和通信设备。这些角色没有任何一种使 Web 的出现成为必然。超文本研究与已有互联网服务提供了材料,一个具体的信息管理问题则提供了把它们结合起来的理由。
在 CERN,文档、人员、项目与机器不断变化,有用的知识分散在它们之间。Berners-Lee 在 1989 年的提案中,试图用相互链接的信息处理这种组织困难。问题不只是传送更多比特,而是在位置与责任不断变化时,保留知识片段之间的联系。原始提案
对学习者,这是一个有用的转折点:技术发明也可能来自系统用途的改变。 网络提供通信;相互链接的信息空间,还需要关于名称、文档、链接和访问的额外约定。理解这个区别,就更容易看见为什么网络、信息检索、数据库和界面设计仍是不同主题,即使一个浏览器把它们放到了你面前。
1990s–2000s:Web 与全球信息访问问题
Web 结合了一组相对简洁的约定:资源标识符、客户端与服务器交换信息的 HTTP,以及包含链接的 HTML 文档。浏览器可以沿着链接访问,而不必让每个信息提供者都设计一个新客户端。这些抽象让独立维护的信息更容易连接。
一个影响深远的设计选择是:发布者可以链接到另一份文档,不必先取得对方所有者的许可,也不必把链接登记到一个全球总目录。这降低了协调成本,同时允许目标移动或消失时链接失效。架构优先支持广泛参与,而没有保证每个关系都永远完整。
开放并不意味着访问机会平等或没有成本。人们仍然需要设备、连接、托管、可用的软件,以及往往不可缺少的机构支持。Web 也没有从无到有创造网络服务:远程访问、邮件和文件传输早已存在。它的贡献是提供了一种广泛共享的方式,用于发布和浏览相互链接的信息,随后又成为应用平台。
对初学者,要区分资源的名称、请求它所用的协议,以及返回的表示。URL 不是文档本身;一次成功的 HTTP 交换不能证明内容正确;浏览器显示一页内容,也不会揭示背后的全部服务。
这些边界同时解释了 Web 的广泛影响与后续问题。分散发布支持增长,而发现、真实性、持久性与滥用需要额外机制。简洁的共享约定能使系统易于扩展,却不必在同一层解决所有问题。
1990s 后期–2010s:搜索与大规模相关性问题
随着 Web 增长,中心问题从访问转向发现。发布信息已经不够。用户需要在数十亿文档中找到相关信息。问题变成:一个系统如何判断什么对某个查询有用、权威、新鲜且相关?
这不是简单的数据库查找问题。数据库查询通常假设结构化数据和清晰语义。Web 搜索必须处理混乱、异构、不断变化的文档。一个页面可能包含正确词语,却仍然无用。另一个页面可能并不精确匹配查询,却更能满足用户意图。查询通常很短、含糊,并且依赖上下文。Web 中还存在操纵、重复、垃圾信息和过时材料。
因此,搜索变成一个整合性的 CS 问题。它需要爬取 Web、建立索引、排序文档、理解查询、对抗操纵、以低延迟提供结果,并评估用户是否满意。倒排索引是检索的核心,但排序需要的不只是词项匹配。链接结构、文本相关性、新鲜度、用户行为、权威信号,以及后来的机器学习,都成为搜索的一部分。
Web 搜索承接了更早的信息检索实验,扩大了数据驱动评估的规模与商业重要性。搜索引擎不能只用形式正确性来判断,因为往往没有唯一正确结果。它必须根据相关性、有用性和用户行为来判断。这使离线指标、人工评估、点击日志和在线实验变得重要。系统的改进不仅来自理论分析,也来自持续测量。
搜索改变了 CS,因为它使排序成为一种核心计算操作。早期系统通常从结构化数据中返回精确答案。搜索系统返回的是相关性的有序近似。这预示了许多后来的系统:推荐引擎、社交媒体信息流、广告平台、内容审核系统和 AI 助手。在所有这些系统中,系统并不只是取回一个已知对象。它估计应该展示、推荐、隐藏或生成什么。
更深的教训是:在大规模信息环境中,计算常常变成对不完美信号的推断。精确正确性在基础设施中仍然重要,但面向用户的结果可能是概率性的、排序的、上下文敏感的。这进一步把 CS 推向统计、机器学习、实验和以人为中心的评估。
2000s–2010s:互联网规模系统与持续运行问题
一旦 Web 服务吸引了数百万乃至数十亿用户,另一个问题成为主导:系统如何在巨大规模和持续变化下保持快速、可靠、安全和可维护?
这不同于构建一个能正确运行一次的程序。互联网规模服务总是在运行。它接收不可预测的流量,存储不断变化的数据,依赖其他服务,运行在许多机器之上,经历频繁部署,并面临持续安全威胁。它不能假设硬件可靠,也不能假设网络稳定。在足够大的规模上,失败不是例外。它是常态。
这个时期使分布式系统和运维工程成为日常软件实践的核心。大型服务需要复制、分片、负载均衡、分布式存储、缓存、异步处理、队列、监控、日志、追踪、部署自动化、回滚策略和事故响应。系统设计不仅要面向正常执行,也要面向降级运行、局部失败、过载和恢复。
云计算的出现也改变了软件的经济基础和架构基础。组织不再需要拥有自己使用的每一台物理机器。计算、存储、网络、数据库,以及后来的机器学习服务,都可以通过可编程接口租用。基础设施变得弹性化、抽象化,并由 API 驱动。这让构建大型系统更容易,但也创造了新的依赖层。
方法论转向运维系统思维。一个成熟服务不只由源代码定义。它由自己在生产环境中的行为定义。它能否从失败中恢复?它能否被观测?它能否安全部署?它能否处理负载峰值?工程师能否理解事故?安全补丁能否快速应用?成本能否被控制?
这改变了可靠性的含义。可靠性不再是实现完成后附加的最终属性。它变成一门持续纪律。系统必须被测量、运行、修复和演化。事故报告、服务级目标、容量规划和可观测性,成为现代 CS 实践知识结构的一部分。
这个时期的教训是:在互联网规模上,软件变成一个活系统。它从来不只是“完成”了。它会被部署、监控、更新、防御,并随时间重组。
2000s–2010s:平台与生态治理问题
随着互联网系统成熟,有些系统不再只是应用。它们变成了平台。平台不只是终端用户使用的工具。它是一个环境,其他用户、开发者、企业、广告商、创作者、机构和服务都在其中行动。这再次改变了中心问题:一个计算系统如何组织和治理一个生态?
平台包括操作系统生态、应用商店、社交网络、搜索平台、云平台、支付系统、开发平台和内容平台。它们的技术架构决定其他行动者能做什么。API 定义访问。权限系统定义权威。排序系统定义可见性。审核系统定义可接受行为。身份系统定义信任。应用审查系统定义分发。日志和分析定义什么可以被测量。
这个时期让技术设计和制度设计更难分开。平台的架构同时也是治理结构。速率限制不只是性能控制;它可能塑造市场进入。权限模型不只是安全机制;它决定哪些应用能够存在。推荐算法不只是优化系统;它塑造注意力和公共讨论。云接口不只是工程便利;它改变组织构建和运行软件的方式。
平台的困难在于平衡开放和控制。如果一个平台过于封闭,它可能无法吸引开发者或用户。如果它过于开放,它可能助长滥用、欺诈、隐私侵犯、垃圾信息、恶意软件或生态不稳定。这使信任边界、策略执行、开发者关系、安全审查和滥用检测成为平台设计的核心。
方法论转向作为治理的架构。在早期软件中,架构主要用于组织复杂性。在平台中,架构还组织权力。接口、权限、策略和默认设置的设计,决定行动者能做什么,以及哪些伤害更可能发生。
这也是现代 CS 越来越与法律、经济学、社会学、政治理论和伦理学交叉的原因之一。平台是计算系统,但它们的影响是社会性的。它们调解通信、商业、劳动、创造、知识和机构权威。教训是,大型软件系统不只是处理信息。它们结构化了人们行动的环境。
2010s:移动与泛在计算,以及语境问题
智能手机的兴起把计算从桌面带入口袋、家庭、街道、车辆和身体。核心问题变成:计算如何适应用户语境,同时尊重电池、隐私、注意力、连接性和身体移动这些约束?
移动设备并不只是更小的个人计算机。它们拥有传感器、摄像头、麦克风、触摸屏、GPS、加速度计、无线电、生物识别机制和持续网络连接。它们随用户移动,并收集语境数据。应用可以响应位置、运动、联系人、时间、通知和个人习惯。
这使移动计算既强大又危险。移动设备可以帮助导航、通信、支付、摄影、健康追踪、语言学习和工作。但它也可能暴露位置、行为、身份、联系人和私人内容。让应用有用的同一种语境感知能力,也提高了隐私敏感性。
移动系统需要整合许多 CS 领域:操作系统、网络、HCI、安全、数据库、分布式服务、云同步、传感器处理和机器学习。智能手机成为一个更大分布式系统中的客户端。许多移动应用只是一部分在本地运行;它们依赖云服务、身份系统、地图、搜索、推荐、推送通知和远程存储。
方法论转向语境感知设计。设计者不仅要问软件做什么,还要问它在哪里被使用,什么时候打断用户,感知什么数据,离线时能做什么,请求什么权限,什么延迟可以接受,以及它制造什么风险。这使用户体验、隐私和系统设计紧密连接。
移动计算也强化了计算的社会存在。它进入注意力、移动、记忆、社会关系、健康、商业和日常决策。教训是:当计算变得无处不在,语境就成为系统的一部分。一个系统不再只由代码和数据定义。它也由何时、何地、如何,以及被谁使用来定义。
2010s:深度学习与学习表征问题
深度学习在 2010 年代的成功,标志着实际能力的重要变化,却不是 AI 中学习方法或神经方法的起点。1955 年的达特茅斯提案就讨论了学习与神经网络。早期模式识别探索统计和神经方法,另一些研究者则研究搜索、符号推理与规划。这些路径相互交叠、竞争,并非一场界限清楚的接力赛。达特茅斯提案
Nilsson 的历史研究提供了一组有用的对照。定理证明程序在明确表示的表达式和推理步骤之间搜索;模式识别器需要从变化的感官输入中提取区别;DENDRAL 则把搜索与化学知识结合,用来约束候选分子结构。这些例子说明:问题怎样被表示、预先提供什么知识,可能与一般的搜索过程同样重要。
以手写数字识别器为例,一种做法是人工设计圆环、笔画等特征。神经模型则调整参数,使中间变换对训练目标有用。通过方法、数据、计算能力和软件的发展,深度学习让多层表示的学习在许多任务上变得实际有效。但设计者对数据、架构、目标与评估的选择,并没有消失。
要区分训练表现与泛化。模型可能拟合见过的样本,却在新笔迹、不同扫描仪或不熟悉的人群上失效。由算法进行训练,并不会把关于未来输入的经验主张变成证明。应把评估数据与训练分开,并追问评估条件是否接近预期用途。
最后,任务表现成功,并不能单独证明系统解释了人的认知。Boden 的历史研究强调认知科学的广度,包括感知、行动、情感与多种解释方式。学习 AI 时,要区分建造有用的人工物、预测行为,以及解释心智。它们可以相互启发,却不是同一个成就。
2010s–2020s:数据基础设施与数据生命周期问题
随着机器学习和分析变成核心,CS 不得不面对一个不那么光鲜但极其基础的问题:数据如何被收集、清洗、转换、治理、版本化,并在时间中可靠使用?
模型依赖数据,但数据不是一种天然存在的物质。它由仪器、用户、机构、平台、传感器、日志、标签和历史决策生产出来。它可能不完整、有偏、重复、过时、嘈杂、私密,或受到法律限制。它的意义依赖 schema、收集过程、定义和上下文。
这使数据工程成为现代计算的核心部分。一个可靠的数据系统需要抽取、转换、加载、验证、血缘追踪、访问控制、schema 管理、质量监控、隐私控制和可复现性。在机器学习中,数据生命周期还包括标注、特征构造、训练集构造、评估集设计、漂移检测和模型监控。
主要转变是从把数据视为输入,转向把数据视为基础设施。在成熟组织中,数据不只是被存储。它被治理。人们需要知道它来自哪里,谁能使用,如何被转换,是否新鲜,定义是否变化,是否包含敏感信息,以及分析是否可以复现。
这个时期还揭示,许多 AI 失败本质上是数据失败。模型表现差,可能是因为训练数据不具代表性。指标误导,可能是因为标签有缺陷。仪表盘错误,可能是因为定义变化。部署后的模型退化,可能是因为训练之后世界发生了变化。计算质量越来越取决于数据生命周期的完整性。
教训是,现代 CS 不只是以算法为中心。它也以流水线为中心。可信计算需要可信的数据过程。
2020s:基础模型与通用学习能力问题
进入 2020 年代,关注点从任务特定模型转向大型通用学习系统。核心问题变成:在海量数据上训练出的广泛模型,如何被适配、控制、评估,并整合进真实系统?
基础模型改变了用户与计算之间的接口。早期软件通常暴露具体功能。基础模型暴露的是灵活能力:写作、总结、翻译、编码、分类、解释、生成图像、回答问题、使用工具,以及跨模态转换信息。同一个基础模型可以通过提示、微调、检索、工具使用或系统集成来支持许多任务。
这创造了新的力量,也创造了新的不稳定性。模型可能生成流畅语言,却并不真实。它可能很好地解决一个任务,却在另一个任务上意外失败。它可能编码偏见、泄漏记忆信息、遵循误导性指令,或被对抗性提示操纵。它的行为是概率性的、上下文敏感的。提前指定所有预期和非预期用途可能非常困难。
主要突破来自 Transformer 架构、大规模预训练、大数据集、巨大计算量、指令微调、基于人类反馈的强化学习、检索增强、多模态建模,以及通过 API 和产品部署的结合。但更深的变化是架构性的。模型成为大型系统中的可复用能力层。
这使设计实践转向以模型为中心的系统设计。工程师现在要问:模型接收什么上下文,可以调用什么工具,可以访问什么数据,哪些输出需要验证,哪里应该使用确定性代码,哪里需要人类审查,失败如何被检测,以及风险如何随领域变化。基础模型应用不只是一个模型。它是一个由检索、提示、策略、界面、日志、评估、权限和 fallback 行为组成的系统。
基础模型也改变了编程教育和软件工作。AI 辅助编程可以加速编码,但也可能掩盖误解。开发者仍然需要理解需求、架构、测试、安全、性能和可维护性。模型可以生成代码,但它无法取消判断的必要。
教训是,基础模型并不会让 CS 基础过时。它们让这些基础更重要,因为更多行为变得间接、学习得来、概率化,并且难以检查。
2020s:AI 评估、安全与可信学习行为问题
随着 AI 系统变得更强、更广泛部署,下一个问题变成:当学习系统的行为无法被提前完全规定时,如何对其评估、约束、监控和治理?
传统软件通常从规约开始。人们可以为预期行为编写测试。AI 系统使这件事复杂化,因为它们的输出是概率性的、开放式的、上下文敏感的。一个模型可能通过基准,却仍然在部署中失败。它可能平均表现很好,却在罕见或高风险案例中严重失败。它可能对一个群体有用,却对另一个群体有害。它可能在错误时显得很自信。
评估一直是 AI 研究的核心活动;更广泛的部署,增加了需要检查的情形及其后果的重要性。评估包括基准、人类审查、红队测试、对抗性测试、鲁棒性分析、校准、可解释性工作、监控、误用分析和部署后审计。挑战不只是最大化性能,而是理解能力与风险之间的关系。
这个时期的方法从性能优化转向能力—风险评估。一个强大的系统并不自动是一个好系统。它的价值取决于它在哪里使用、谁受影响、错误代价是什么、用户是否理解其边界、输出是否可验证、误用是否可能,以及是否存在问责机制。
AI 安全也迫使 CS 面对不完整规格。在许多领域,期望行为并不是纯技术问题。它涉及人类价值、制度规范、法律约束和语境判断。这并不意味着放弃技术严谨性。它意味着扩大技术设计必须尊重的约束集合。
教训是:对于强大的学习系统,成功不只是高能力。成功意味着在现实条件下具备受控、被评估、可问责的行为。
2020s:隐私、安全与敏感数据上的计算问题
隐私问题早于当代 AI 和大型在线平台。数据收集与模型部署的扩张,使计算领域一个既有的问题变得更加尖锐。问题变成:如何在不制造不可接受的暴露、监视或推断能力的情况下进行有用计算?
早期安全通常关注保护系统免受未授权访问和恶意修改。隐私增加了另一种关注。即使是被授权的数据使用,也可能因为数据被聚合、保留、推断或重新利用而造成伤害。去掉姓名是不够的。位置轨迹、搜索历史、社交图谱、生物识别信号、写作模式和行为日志,都可能揭示敏感信息。不同数据集可以被结合起来,产生新的识别和预测形式。
这改变了隐私的技术含义。隐私不只是保密。它也是对推断的控制。一个系统可能从不泄露原始记录,但仍然通过聚合统计、模型输出、元数据或访问模式暴露信息。机器学习增加了另一层问题,因为模型可能记忆、泄漏或编码训练数据中的敏感信息。
几种技术路径变得更重要:差分隐私、联邦学习、安全多方计算、同态加密、可信执行环境、访问控制、数据最小化和隐私保护分析。没有一种是通用解决方案。每一种都在特定假设下减少某些类型的暴露。
方法论转向隐私设计优先。成熟系统会问:是否真的需要数据,能否收集更少数据,计算能否在本地发生,数据能否被安全聚合,保留时间能否限制,用户能否理解数据流,以及即使直接标识符被移除,是否仍可能发生敏感推断。
教训是,隐私是系统属性。它取决于架构、数据流、激励、界面、法律和机构实践。在现代 CS 中,保护数据意味着保护人免受有害推断和不平等权力的伤害。
2020s:信息物理系统、边缘系统与现实世界中的计算问题
实时控制与物理环境中的计算有很长的历史。近年的信息物理系统与边缘系统,通过更密集的感知、连接和学习组件延伸了这段历史。核心问题变成:系统如何在物理约束下感知、决策并安全行动?
这包括机器人、自动驾驶汽车、无人机、智能家居、工业控制、医疗设备、可穿戴设备、传感器网络和边缘 AI。这些系统不同于普通软件,因为它们会在世界中行动。一次失败可能不只是产生错误输出。它可能造成物理损害、伤害、隐私损失或环境扰动。
信息物理系统必须处理嘈杂传感器、不确定环境、实时约束、有限能量、间歇连接、硬件故障和人类不可预测性。它们结合了嵌入式系统、操作系统、网络、控制理论、信号处理、计算机视觉、机器学习、安全工程,以及软硬件协同设计。
边缘计算变得重要,是因为并不是所有计算都能或应该发生在云端。有些任务需要低延迟、本地可靠性、隐私保护或减少带宽。设备可能需要在断网时仍能决策。这在本地计算和集中式基础设施之间创造了新的平衡。
方法论转向实时与安全感知设计。设计者必须追问:如果传感器失败,如果网络连接消失,如果模型不确定,如果执行器行为异常,或者如果人类介入,会发生什么。系统通常必须具备安全 fallback 状态。时间性成为正确性的一部分。
教训是:当计算在物理世界中行动时,抽象不能忽视具身性。延迟、能量、不确定性和安全都变成一等约束。
2020s 及以后:社会技术计算与治理问题
治理一直是计算领域的问题,从机构记录处理、访问控制,到标准与网络管理。大型平台和 AI 的部署,让这些问题出现了更多形式,也变得更加紧迫。计算系统现在塑造通信、教育、劳动、法律、金融、医疗、文化、公共行政和政治生活。核心问题变成:当计算系统组织社会现实时,它们应如何被设计和治理?
这并不与技术 CS 分离。排序系统、推荐系统、搜索引擎、身份系统、审核工具、欺诈检测器、招聘算法、教育平台、风险模型和 AI 助手,都是技术系统。但它们的效果是社会性的。它们影响人们看见什么、获得什么机会、机构如何做出决策,以及权力如何分配。
这创造了无法只靠更好算法解决的问题。人们必须追问谁受益、谁受害、谁可以申诉、谁理解系统、谁审计系统、谁控制数据、哪些错误可以容忍,以及哪些价值被嵌入设计之中。一个技术上准确的系统,在具体语境中仍然可能是不公正的、不合法的、不可访问的或有害的。
因此,CS 的方法论再次扩展。它必须包括公平性评估、可解释性、透明度、问责、隐私、人类参与审查、法律合规、制度设计和公共利益分析。这并不意味着技术严谨性变得不重要。它意味着技术严谨性必须在更宽的社会后果说明中运作。
社会技术计算也改变了责任的含义。一个系统的影响并不只由代码决定。它由部署语境、激励、用户、机构、反馈回路和治理结构共同塑造。推荐算法可能改变人们生产什么。审核系统可能改变言论规范。AI 助手可能改变人们如何学习或工作。风险模型可能改变对资源的访问。
教训是,现代 CS 不再只关心机器内部的计算。它也关心社会内部的计算。这就是为什么伦理、法律、政策和制度分析并不是外部装饰。它们成为理解计算系统实际做什么的一部分。
长弧线:CS 作为不断扩展的约束管理
历史并不是一个领域完成工作,再把成果交给下一个领域的顺序过程。计算、记录处理、通信、控制,以及理解智能的尝试,通过不同群体和机构发展。反复出现的成就是:找到一种表示、抽象,或人与机器的组织方式,使原本困难的活动变得可以处理。
“不断扩展的约束管理”是一种有用的综合视角,但不应把计算机科学的其余部分排除在定义之外。有些研究证明不可能性,有些解释既有系统,有些发明新媒介或发现新用途。可靠性是重要目标之一,与表达力、理解、效率、可及性等目标并存,它们还可能发生冲突。
这段历史为后面的学习提供了一组问题。学习算法时,问什么表示使过程成为可能,成本怎样增长;学习语言和体系结构时,问接口承诺什么,实现可以改变什么;学习操作系统、数据库和网络时,问哪些假设在共享或故障下仍然成立;学习 AI 时,问哪些知识被预先提供、哪些通过学习获得,以及什么证据支持泛化;面对任何应用,都要问被表示的是谁的活动,设计服务的是谁的需要。
这些联系说明了为什么早先的主题仍然有用。学习模型仍通过程序与硬件执行;在线服务仍依赖记录、协议和人的解释。新工作经常改变老问题的相对重要性,而不是让问题消失。
借助历史认出问题,再去记住解法。 读完一节后,你应当不只能说出一项技术的名称,还能说明为什么有人需要它、它让什么变容易,以及哪些事情仍然需要自己检查。