Year 1 / Module 2 Programming interactive systems / Unit 6 / The network is a second machine: failure is a state to design

The network is a second machine: failure is a state to design

HCI1102 · Unit 6 of 10

A program that depends on a remote service must treat unreachability, refusal and slowness as distinct first-class states, because an interface can only act on a failure it has modelled.

The network is a second machine: failure is a state to design

A program that calls a remote service owns none of it: not the data, and not the machine that holds it. It has gained a second machine whose behaviour it does not control. This unit argues that such a program must treat unreachability, refusal and slowness as distinct first-class states, because an interface can act only on a failure it has modelled. A design that models only success shows one blank rectangle, whether the request never left the device, was refused, or is merely slow. The strongest counter-argument, taken up below, is that modelling failure is the second-best answer. If the client holds a copy of the data, the network becomes optional and unreachability never has to reach the interface. Unit 7 asks how a programmer finds the cause when a program like this misbehaves.

A failed request and a refused request are different states

The Fetch Standard draws the line the program inherits. A network error is a response whose type is error and whose status is 0, with an empty status message, header list and body. It is not a response that arrives carrying an error status (WHATWG, 2026). The first is a request that never became a conversation: the device is offline, the name does not resolve, or the connection is refused. The second is a server that answered and said no. From inside the caller the two look identical, and the remedies differ: a refusal may carry a reason, and a network error never does.

HTTP keeps the refusal informative. In RFC 9110 the first digit of a status code fixes its class, and the 5xx class means the server failed to fulfil an apparently valid request. A 503 may carry a Retry-After naming how long to wait, while a 504 says an intermediary gave up waiting for an upstream server (Fielding, Nottingham and Reschke, 2022). A client that renders both as one error has discarded the instruction the protocol provided.

Why a request is stateless, and why the caller carries the risk

Fielding's derivation of REST explains why a client cannot rely on the server to remember the last call. The stateless constraint requires each request to carry all the information needed to understand it and to take no advantage of stored context on the server, so session state is kept on the client. The layered-system constraint lets proxies and gateways sit between the two ends (Fielding, 2000). Both constraints buy scalability and both move work to the caller: because a request stands alone, its failure stands alone.

The network is not reliable, and the average is not the case

Bailis and Kingsbury test the assumption against real incidents and find it false in ordinary conditions. Partitions, misconfigurations and timeouts recur across production systems, and the consequences run from latency to inconsistency and data loss (Bailis and Kingsbury, 2014). A ninety-second partition made a pair of high-availability file servers conclude that each other was dead, and fail over at once.

Slowness is the harder half, because it is not a failure and does not announce itself. Dean and Barroso show why the average request time is the wrong thing to design against. A single request has a 99th-percentile latency of 10 milliseconds, but the 99th percentile for a fan-out is 140 milliseconds, so the slowest 5 per cent accounts for half the total (Dean and Barroso, 2013). Their remedy, a hedged request to a second replica, cut a benchmark's latency from 1,800 milliseconds to 74. Grigorik adds why the tail cannot be removed: latency is the sum of propagation, transmission, processing and queuing delays, and propagation is bounded by the speed of light in the medium (Grigorik, 2013).

Failure is normal and often human

Oppenheimer, Ganapathi and Patterson analysed the causes of failure across three large Internet services. Operator error was the largest single cause in two of the three, and configuration errors were the largest category of operator error (Oppenheimer, Ganapathi and Patterson, 2003). If the most common cause is a person changing a configuration, then failure is normal, and a program that treats it as exceptional has mis-modelled the world.

The operational literature treats it that way. Beyer and colleagues describe site reliability engineering through service level indicators such as request latency and error rate. Error budgets make the acceptable failure a planned quantity rather than a surprise (Beyer, Jones, Petoff and Murphy, 2016). Nygard sets out three patterns. A timeout caps every remote call, a circuit breaker stops calling a failing dependency and tests it later, and bulkheads partition resources so one failure cannot drain everything (Nygard, 2018).

Handling failure is learned, and the API teaches or misleads

Shah, Gorg and Harrold studied novices and experts in industry. Novices tend to ignore exceptions because handling them is complex, they found, while experts treat handling as a crucial part of development (Shah, Gorg and Harrold, 2010). Error handling is not a syntax a beginner already has. It is a disposition built by practice, and by what the surrounding code makes visible. Myers and Stylos argue that an API is the interface between developers and code, so its usability includes how well it prevents errors and matches a developer's mental model (Myers and Stylos, 2016).

What each state needs in the design

The sources yield a small model to carry into code. The interface needs four states rather than two: loading, success, empty, and a divided error state. Unreachability needs a retry the person controls, because the program cannot know when the network returns (WHATWG, 2026). Refusal needs a reading of its status: a 503 with a Retry-After can be waited out, while a 403 will not change by waiting (Fielding, Nottingham and Reschke, 2022). Slowness needs a bound, because without a timeout the client cannot tell a slow answer from none (Nygard, 2018; Dean and Barroso, 2013).

Take one screen that loads a list of records. If the device is offline, the request never leaves, so the honest state says so and offers a retry the person can press when the network returns. If the service answers 503 with a Retry-After of 120 seconds, the correct response is to wait, not to retry at once. If it answers 403, waiting will not help and the message should say why. If it answers but slowly, a timeout turns an indefinite wait into a state the interface can name. Four states, and the code has something to do in each. For a user on an intermittent or metered connection, slow and offline are the ordinary states rather than the exception.

Contested question: model the failure, or remove the dependence?

The literature agrees that a program depending on a remote service fails, and disagrees about where to spend the effort. The failure-engineering camp says to model the failure states and operate them. Give every call a timeout, a breaker and a fallback, and treat acceptable failure as a budget (Nygard, 2018; Beyer, Jones, Petoff and Murphy, 2016). Its warrant is the record that failure is normal and often human (Oppenheimer, Ganapathi and Patterson, 2003; Bailis and Kingsbury, 2014). Its best single result is Yuan and colleagues, who studied 198 user-reported failures across five distributed systems. Of the catastrophic failures, 92 per cent came from incorrect handling of non-fatal errors, and 58 per cent could have been caught by simple tests of error-handling code. 77 per cent were reproducible by a unit test (Yuan et al., 2014). That is strong evidence about where the faults sit, and it concerns server software rather than an interface.

The rival camp, put by Kleppmann, Wiggins, van Hardenberg and McGranaghan, says the better response is to stop depending on the service for the state the person is working with. In local-first software the primary copy of the data lives on the device and synchronisation happens in the background, so the network becomes optional. The seven ideals include working offline, collaborating across devices, and keeping the data usable after the vendor disappears (Kleppmann, Wiggins, van Hardenberg and McGranaghan, 2019). Unreachability, on this account, should never reach the interface at all. The position is a design argument with a reference implementation, not a measured outcome.

The two positions do not cover the same ground. Local-first is available only where the program can hold a copy of the data. Much interactive work calls a service for facts the client does not own, such as another party's records, and there the failure-engineering position is the only one on offer (Fielding, 2000). Nor does local-first abolish the failure: a synchronising client must still merge concurrent edits (Kleppmann, Wiggins, van Hardenberg and McGranaghan, 2019).

What would settle it is a comparison the field has not run. Build one feature three ways, with the failure states modelled, with them unhandled, and local-first with background synchronisation. Hold the task constant, inject a network error, a refusal with and without a Retry-After, and a tail delay, then measure what a person completes, how fast they recover, and the states the code handles. Dean and Barroso supply the incidence of latency and Oppenheimer and colleagues the incidence of human failure, but no study here supplies the outcome comparison. Until one does, a designer should model the four states and cap every call with a timeout. Holding a local copy of anything the person is editing is the part of local-first that survives its availability limit.

Where the argument is heading

Three lines of named work point the same way. Local-first software is the strongest attempt to move the copy of the state to the device and make the network optional (Kleppmann, Wiggins, van Hardenberg and McGranaghan, 2019). Operations has turned failure into a measured quantity through objectives and error budgets, so it designs the failure rather than reacting to it (Beyer, Jones, Petoff and Murphy, 2016). The standards keep fixing the vocabulary (WHATWG, 2026; Fielding, Nottingham and Reschke, 2022).

The sources this unit rests on

  • WHATWG. (2026). Fetch Standard. Living Standard. https://fetch.spec.whatwg.org/ Defines a network error as a response whose type is error and whose status is 0, apart from one carrying an error status. Unreachability and refusal are different events at the level of the standard.
  • Fielding, R. T. (2000). Architectural Styles and the Design of Network-based Software Architectures. Doctoral dissertation, University of California, Irvine. https://ics.uci.edu/~fielding/pubs/dissertation/top.htm Derives REST from constraints including statelessness and layered systems. The stateless constraint places every call's failure on the caller.
  • Fielding, R., Nottingham, M. and Reschke, J. (2022). HTTP Semantics. RFC 9110. Internet Engineering Task Force. doi:10.17487/RFC9110 Consolidates HTTP semantics, defining the status code classes and individual codes. The 5xx class marks a failure the server knows about, 503 may carry a Retry-After, and 504 marks an intermediary that gave up.
  • Oppenheimer, D., Ganapathi, A. and Patterson, D. A. (2003). Why do Internet services fail, and what can be done about it? In Proceedings of the 4th USENIX Symposium on Internet Technologies and Systems (USITS 03). https://www.usenix.org/conference/usits-03/why-do-internet-services-fail-and-what-can-be-done-about-it Analysed the causes of failure in three large Internet services from incident data and interviews. Operator error was the largest single cause in two of the three, so failure is normal and frequently human.
  • Dean, J. and Barroso, L. A. (2013). The tail at scale. Communications of the ACM 56(2), 74-80. doi:10.1145/2408776.2408794 Analyses latency variability in large services: one request costs 10 milliseconds at the 99th percentile, but a whole fan-out takes 140, so the tail carries the delay a person meets.
  • Yuan, D., Luo, Y., Zhuang, X., Rodrigues, G. R., Zhao, X., Zhang, Y., Jain, P. U. and Stumm, M. (2014). Simple testing can prevent most critical failures: an analysis of production failures in distributed data-intensive systems. OSDI 14, 249-265. https://www.usenix.org/conference/osdi14/technical-sessions/presentation/yuan Studied 198 user-reported failures across five distributed systems: 92 per cent of catastrophic failures came from incorrect handling of non-fatal errors, 58 per cent could have been found by simple tests of error-handling code, and 77 per cent were reproducible by a unit test. The strongest evidence that testing failure states pays.
  • Bailis, P. and Kingsbury, K. (2014). The network is reliable. Communications of the ACM 57(9), 48-55. doi:10.1145/2643130 Surveys real-world communications failures and documents them with incidents, including a ninety-second partition that made two high-availability file servers fail over at once. Grounds failure-first design in the record.
  • Shah, H. B., Gorg, C. and Harrold, M. J. (2010). Understanding exception handling: viewpoints of novices and experts. IEEE Transactions on Software Engineering 36(2), 150-161. doi:10.1109/TSE.2010.7 Studied novice and expert developers in industry and compared how each regards exception handling. Novices tend to ignore exceptions when handling is complex, while experts treat handling as crucial, so it is learned.
  • Myers, B. A. and Stylos, J. (2016). Improving API usability. Communications of the ACM 59(6), 62-69. doi:10.1145/2896587 Argues that an API is the interface between developers and the code, so human-computer interaction principles apply to it: usability includes error prevention and matching a developer's mental model.
  • Kleppmann, M., Wiggins, A., van Hardenberg, P. and McGranaghan, M. (2019). Local-first software: you own your data, in spite of the cloud. In Proceedings of the 2019 ACM SIGPLAN International Symposium on New Ideas, New Paradigms, and Reflections on Programming and Software (Onward! 19). doi:10.1145/3359591.3359737 Proposes local-first software, in which the primary copy of the data lives on the device with background synchronisation, and sets out seven ideals including offline working and longevity. The strongest alternative to modelling failure: the network becomes optional.
  • Beyer, B., Jones, C., Petoff, J. and Murphy, N. R. (2016). Site Reliability Engineering: How Google Runs Production Systems. Sebastopol: O'Reilly Media. https://sre.google/sre-book/table-of-contents/ Describes site reliability engineering at Google, including service level indicators such as request latency and error rate, and error budgets. The discipline that turns failure handling into design.
  • Nygard, M. T. (2018). Release It! Design and Deploy Production-Ready Software. 2nd edition. Raleigh: Pragmatic Bookshelf. https://pragprog.com/titles/mnee2/release-it-second-edition/ Catalogues stability patterns for production software: timeouts on remote calls, a circuit breaker that stops calling a failing dependency and tests it later, and bulkheads that isolate a failure to one pool. The vocabulary for the states this unit asks students to model.
  • Grigorik, I. (2013). High-Performance Browser Networking. Sebastopol: O'Reilly Media. https://hpbn.co/ Explains how browsers use the network, treating latency as the sum of propagation, transmission, processing and queuing delays. Propagation is bounded by the speed of light, so slowness is partly a physical limit.

Check your understanding & apply it · 4 questions, 1 essay

1An app's request fails because the phone is in a tunnel; on another occasion the same call fails because the server answered 503. Using the Fetch Standard distinction in this unit, how should the code treat the two cases?
2A list screen receives a 503 carrying a Retry-After of 120 seconds, and separately a 403. Following the unit's four-state model, what should the interface do in each case?
3Dean and Barroso (2013) report a single request at the 99th percentile of 10 milliseconds but a whole fan-out at 140 milliseconds. What should a designer take from that for slowness?
4The contested section sets the failure-engineering camp (Nygard, 2018; Beyer et al., 2016) against local-first software (Kleppmann et al., 2019). What limit does the unit put on local-first?
5Essay A team builds a single-page app that lists nearby restaurants by calling a third-party HTTP API. The code has one success path that renders the list and one else branch that renders the text 'Something went wrong'. Users report that sometimes the list is empty with no explanation, sometimes the text appears when the phone is in a tunnel, and sometimes the app hangs with no message at all. Using the model in this unit, name the states the code is collapsing, explain what each state needs in the design, and state the contested position that says the app should not depend on the API in this way, and why it may not apply here. Refer to the unit's sources where they bear on your answer.