# Web Acequia Components (WAC): The 50-Year Quest for Network-First Objects ## The Dream That Keeps Returning Every decade since the 1970s, software architects have attempted to solve the same problem: make the object, the fundamental unit of software, aware of the network from birth. Not as an afterthought. Not as a serialization layer bolted on. The object itself should be a citizen of the network, capable of being discovered, composed, moved, and wired to other objects across machine boundaries as naturally as calling a local method. This is the thread that connects Smalltalk to OpenDoc to ActiveX to Director's multiuser casts to Enterprise JavaBeans to today's Web Components. Each attempt got something right. Each failed for reasons that illuminate what Acequia components must get right. (For the full set of architectural tenets that inform this discussion, see the [Redfish Creed](https://guerin.acequia.io/redfish/redfish-creed.md).) ## Alan Kay's Cells (1972) Alan Kay did not invent "object-oriented programming" the way most people use the term. He invented something more radical. In the Smalltalk vision, objects are not data structures with methods. They are autonomous computers that communicate exclusively through messages. > "I thought of objects being like biological cells, and/or individual computers on a network, only able to communicate with messages." > -- Alan Kay, 1998 This is a networking metaphor at the origin. Each object is a node. Each method call is a message dispatch. The Smalltalk image, where objects persist and remain live across sessions, was a prototype of exactly what the Redfish Creed means by "GitHub is where code goes to die." In Smalltalk, code never dies. You manipulate living objects directly, in context, continuously running. What Smalltalk lacked was the actual network. Objects lived inside a single image on a single machine. The message-passing architecture was ready for distribution, but the infrastructure was not. Every subsequent attempt in this lineage is an effort to take Kay's cellular, message-passing objects and extend them across the wire. ## Apple OpenDoc (1993-1997) OpenDoc was Apple's answer to the monolithic application. Instead of launching Microsoft Word to edit text and Adobe Photoshop to edit images, you would have a single compound document containing "parts," each implemented by a different vendor's component. A spreadsheet part. A drawing part. A text part. Each part was a live, editable object inside a shared document container. OpenDoc got several things right: - **The document is the application.** There is no "app" in the traditional sense. The user works with a document that contains parts, each contributing its own editing capabilities. This anticipated the Redfish Creed's tenet that "apps are soft-assembled model views and controllers." - **Uniform object model.** Every part obeyed the same protocols for embedding, activation, storage, and scripting (via OSA, the Open Scripting Architecture). This is Kay's uniformity principle: all objects have basic uniform behavior. - **In-place editing.** You click on a part and its editor activates in-place, no mode switch, no separate window. This is directness and modelessness from the Self design philosophy. What OpenDoc got wrong: - **No network.** Parts were local objects in a local document on a local machine. There was no concept of a part existing at a URL, subscribing to remote data, or synchronizing state with parts in another user's document. - **Complexity killed adoption.** The SOM (System Object Model) and CORBA underpinnings were heavyweight. Developers had to invest enormous effort to create even simple parts. - **Apple killed it.** When Steve Jobs returned in 1997, he canceled OpenDoc along with most of Copland. The compound document dream died at Apple, though it lived on in different forms elsewhere. OpenDoc proved that component composition in documents works as a user experience. It failed to prove that the industry would bear the complexity cost, and it never confronted the network question at all. ## Microsoft ActiveX and DCOM (1993-2002) Microsoft's approach was more ambitious in scope, if more chaotic in execution. The Component Object Model (COM) gave Windows a binary standard for components. OLE (Object Linking and Embedding) let you put an Excel spreadsheet inside a Word document. OLE2 made the embedding richer. And then ActiveX took COM objects and put them on the web. The evolution went further. DCOM (Distributed COM) extended COM across the network. A component on machine A could instantiate and call methods on a component on machine B, with the RPC plumbing handled transparently. This was, on paper, exactly what Kay's vision demanded: objects that communicate across machine boundaries via messages. What Microsoft got right: - **Binary interop.** COM components could be written in any language, composed in any container. A Visual Basic control, a C++ COM server, and a Delphi component could all coexist. The interface was the contract, not the implementation language. - **Network transparency.** DCOM genuinely made remote objects feel local. You called `QueryInterface`, got back a pointer, and called methods. Whether the object was in-process, out-of-process, or on another continent was (in theory) just a configuration detail. - **Compound documents.** OLE containers achieved what OpenDoc attempted: live, editable parts from different applications coexisting in a single document. What Microsoft got wrong: - **Security.** ActiveX controls on the web had full access to the local machine. The only gate was a code-signing certificate and a dialog box asking the user "Do you trust this publisher?" This was a catastrophe. The entire ActiveX-on-the-web experiment became synonymous with malware, drive-by installs, and browser exploits. - **Windows-only.** DCOM was theoretically cross-platform but practically Windows-only. The dream of network-first objects collapsed into vendor lock-in. - **RPC, not pub/sub.** DCOM's model was remote procedure calls: synchronous, request-response, tightly coupled. This is exactly what the Redfish Creed warns against ("Architect for Synchronized State not Message Passing"). DCOM objects called each other. They did not subscribe to shared state. - **Heavy infrastructure.** DCOM required COM+ services, registry entries, type libraries, proxy/stub DLLs. The overhead of making an object "network-aware" was enormous compared to the simplicity of the object itself. ActiveX/DCOM is the cautionary tale of trying to bolt networking onto an existing component model through RPC. The network was there, but the architecture was wrong: synchronous calls instead of state synchronization, security through trust dialogs instead of capability models, platform-specific infrastructure instead of protocol-level interop. ## Macromedia Director Multiuser and Peer-to-Peer Casts (1997-2004) Director occupies a unique place in this lineage because it was the first popular environment where components (cast members) routinely operated in a networked, multiuser context, and where the component itself was the unit of network communication. In Director, a "cast" is a library of reusable components: bitmaps, scripts, sounds, vector shapes, text, Flash members, 3D models. A "cast member" is an individual component. The stage assembles cast members into a running presentation. Behaviors (scripts attached to sprites) give cast members interactivity. This is component-based development with a visual metaphor that predates modern component frameworks. The Multiuser Xtra (and later the Shockwave Multiuser Server) added networking. Multiple Director movies, running on different machines, could connect to a shared server and exchange messages, synchronize properties, and share cast members in real time. Groups and peer-to-peer messaging allowed cast scripts to address specific users or broadcast to all connected peers. What Director got right: - **Components as the unit of sharing.** When a Director movie shared state across the network, the unit of sharing was the cast member and its properties, not raw bytes or database rows. The component model and the network model were aligned. - **Live authoring in context.** Director's authoring model let you edit cast members while the movie was running. Lingo scripts could be modified and re-executed without restarting. This is exactly the "code never dies" principle. - **Groups and multicast.** The multiuser architecture supported groups, which is a precursor to channel-based pub/sub. A script could join a group and receive messages only from that group. - **Peer-to-peer messaging.** While the Multiuser Server was centralized, the message-passing model supported point-to-point communication between connected peers. Scripts could address messages to specific users by ID. What Director got wrong: - **Proprietary runtime.** Everything depended on the Shockwave plugin. When browsers stopped supporting plugins, the entire ecosystem vanished. A component model tied to a proprietary runtime cannot survive the platform transitions that the web inevitably imposes. - **Server-centric.** Despite supporting peer messaging, the architecture required a central Multiuser Server to broker connections and relay messages. True P2P (as WebRTC later enabled) was not possible. - **No URL-addressable components.** Cast members existed inside a Director file. They did not have URLs. You could not link to a specific cast member, mount it from a remote source, or subscribe to it from outside the Director movie. The components were live and networked but not web-native. Director was the closest anyone came to "networked components" in the multimedia era. It demonstrated that developers will naturally think in terms of components when given a visual authoring environment, and that networking those components is a tractable problem. Its failure was not architectural but environmental: the proprietary plugin model could not survive the open web. ## Java Beans and Enterprise JavaBeans (1996-2006) Sun Microsystems made the most deliberate, large-scale attempt to create network-first objects. The story unfolds in two acts. **Act 1: JavaBeans (1996).** JavaBeans were reusable software components that could be visually composed in builder tools (like Visual Basic's form designer, but for Java). A Bean exposed properties, events, and methods through introspection. Beans could be wired together visually: the "temperature changed" event from a Thermometer bean could be connected to the "update display" method on a Gauge bean. This was pub/sub at the component level, inside a single JVM. **Act 2: Enterprise JavaBeans (1998).** EJB took the Bean concept and made it explicitly distributed. An Enterprise Bean ran inside a container (an application server) that provided: - **Distribution transparency.** A client could call methods on an EJB through a remote interface. The container handled serialization, network transport, and dispatching. The object was genuinely on the network. - **Lifecycle management.** The container could create, pool, passivate, and activate Bean instances. Beans were not tied to a single process lifetime. - **Declarative services.** Transaction management, security, persistence, and concurrency were declared in deployment descriptors, not coded into the Bean. The component author focused on business logic; the container handled cross-cutting concerns. - **Naming and discovery.** Beans were published in JNDI (Java Naming and Directory Interface), a registry that allowed clients to look up remote objects by name. This was a nascent form of URL-based discovery. What the Java approach got right: - **Separation of mechanism and policy.** The EJB container model cleanly separated what the component does (business logic) from how it runs (transactions, security, pooling). This is a powerful architectural insight that survives in modern service mesh and container orchestration. - **Introspection as protocol.** JavaBeans' reliance on introspection (discovering properties and events at runtime) meant that components were self-describing. A builder tool could wire together Beans it had never seen before. This is the uniformity principle: all components expose a common meta-interface. - **The network was first-class.** EJB was one of the few component models where the network was not an afterthought. The distinction between "local" and "remote" interfaces was explicit in the API. You designed your Bean knowing it would live on the network. What the Java approach got wrong: - **Staggering complexity.** An EJB required a home interface, a remote interface, a bean class, a deployment descriptor, and a container. Making a simple "Hello World" Bean network-accessible required dozens of files and a full application server. The overhead-to-value ratio was crushing. - **RPC, again.** Like DCOM, EJB's network model was synchronous remote method invocation. The client called a method on a remote stub. This is message passing, not synchronized state. The Redfish Creed's preference for state synchronization over RPC finds its negative example here. - **Not browser-native.** EJBs lived on server-side application servers. They were not components you could embed in a web page, compose in a document, or interact with directly in a browser. The browser was a thin presentation layer calling server-side EJBs through servlets. The "Browser is the OS" vision is the opposite of the J2EE architecture. - **Java-only.** Despite Java's "write once, run anywhere" promise, EJBs only composed with other EJBs. Cross-language, cross-platform component interop was not part of the model. The EJB era proved that enterprise developers want network-first objects. It also proved that the complexity cost of achieving network transparency through RPC proxies, container services, and deployment descriptors is too high. The industry's reaction, lightweight frameworks like Spring, then microservices, then serverless, was a retreat from the component model entirely. The baby (network-first objects) was thrown out with the bathwater (J2EE complexity). ## Modern Web Components (2011-present) The current chapter begins with Alex Russell's 2011 proposal for Web Components, which became a set of W3C standards: - **Custom Elements.** Define new HTML tags with encapsulated behavior. `` is a first-class element in the DOM, with its own lifecycle callbacks, attributes, and methods. - **Shadow DOM.** Encapsulate a component's internal DOM tree so it cannot be accidentally styled or scripted from outside. This is the encapsulation that Kay's objects demanded: internal state is private, interaction happens through a public interface. - **HTML Templates.** Declare inert markup that gets stamped out when needed. Efficient, declarative component instantiation. - **ES Modules.** Standard module system for loading component definitions from URLs. Web Components get several things profoundly right: - **The browser is the runtime.** No plugin (Director), no JVM (Java), no Windows registry (COM). The component runs wherever there is a browser, which is everywhere. This aligns perfectly with "The Browser is the OS." - **URL-loadable.** A component definition can be loaded from any URL via ES Modules. `import 'https://example.com/components/weather-widget.js'` is a native capability. Components are web-native resources with addresses. - **Framework-agnostic.** A Web Component works in React, Angular, Vue, Svelte, or no framework at all. It is a platform primitive, not a library construct. This is the interoperability that COM promised and OpenDoc attempted. - **Encapsulation without isolation.** Shadow DOM provides style and DOM encapsulation while still allowing the component to participate in the page's event system, accessibility tree, and form submission. The component is both independent and composable. What Web Components still lack: - **No network awareness.** A `` might fetch data from an API, but that is application code inside the component, not a platform capability. There is no standard way for a Web Component to declare "I subscribe to this URL channel" or "my state persists at this endpoint." The component is locally alive but network-dead. - **No state synchronization.** Two instances of the same Web Component on different machines have no built-in mechanism to share state. Each is an island. If you want synchronization, you build it yourself with WebSockets, Firebase, or some other service. - **No discovery.** There is no standard registry where Web Components advertise their existence, capabilities, or interfaces. You cannot browse a catalog of available components the way JNDI allowed for EJBs or a Director cast window displayed cast members. - **No composition protocol.** Wiring two Web Components together (component A's output feeds component B's input) requires application code. There is no declarative, visual, or URL-based wiring mechanism. JavaBeans had event wiring. Director had message passing. Web Components have nothing beyond DOM events and JavaScript glue. ## The Recurring Pattern Looking across five decades, the same cycle repeats: | Attempt | Components | Network | Composition | Survived | |---------|-----------|---------|-------------|----------| | Smalltalk | Objects as cells | Metaphor only | Message passing | The image model lives on | | OpenDoc | Document parts | None | In-place editing | Canceled by Apple | | ActiveX/DCOM | COM objects | RPC (synchronous) | OLE containers | Security killed it | | Director Multiuser | Cast members | Server-brokered P2P | Stage/score | Plugin death | | JavaBeans/EJB | Beans | RPC (synchronous) | Deployment descriptors | Complexity killed it | | Web Components | Custom Elements | None (DIY) | None (DIY) | Alive but incomplete | Every attempt achieves components OR networking but never both in a way that is simple enough to adopt, secure enough to trust, and open enough to survive platform transitions. The failures cluster around three mistakes: 1. **RPC instead of state sync.** DCOM and EJB both chose synchronous remote procedure calls. This creates tight coupling, brittleness under network failure, and an architecture that cannot work offline. The Redfish Creed identified this clearly: "Architect for Synchronized State not Message Passing." 2. **Proprietary runtime.** OpenDoc needed SOM. ActiveX needed Windows. Director needed Shockwave. EJB needed a J2EE server. Each tied the component model to infrastructure that could be withdrawn or superseded. Only Web Components, built on browser standards, have avoided this trap. 3. **Ignoring the URL.** None of these systems made the URL a first-class concept in the component model. Components had class names, CLSIDs, JNDI names, cast member numbers, but not URLs. In a web-native architecture, the URL is the universal address, the API channel, the identity. ## Acequia Components: A Possible Framing One way to read the history above is that we now have all the ingredients that prior attempts lacked. Whether this is the right framing for our component story is worth discussing, but here is the case as I see it. **Web Components as the local component model.** Custom Elements, Shadow DOM, and ES Modules give us encapsulated, framework-agnostic, browser-native components. This may be the best component foundation any of these attempts has had, precisely because it requires no proprietary runtime, no plugin, no application server. It is the platform itself. That alone avoids the failure mode that killed OpenDoc, Director, and EJB. **URLs as network identity.** In the Acequia framing, a URL is not just an address for fetching a resource. It is a channel: a Firebase Reference, a WebDAV endpoint, a WebRTC data channel. If we take the [Redfish Creed's](https://guerin.acequia.io/redfish/redfish-creed.md) third tenet seriously ("URLs as API channels"), then every Acequia component could declare the URLs it publishes to and subscribes from. The URL becomes the wiring mechanism that JavaBeans' event model and Director's message groups attempted, but expressed as a web-native, language-agnostic, OS-agnostic address. **State synchronization over RPC.** Instead of calling methods on remote objects (DCOM, EJB), Acequia components would bind to shared state at URL channels. When state changes, all subscribers see the change. This is the Firebase model generalized: rather than calling a remote procedure, you mutate shared data and let the infrastructure propagate the change. In principle this works offline (local mutations queue), works peer-to-peer (WebRTC sync), and degrades gracefully (eventual consistency). There are open questions about conflict resolution and ordering, but the direction feels right. **The document as the application, again.** OpenDoc's core insight, that the document is a container of live parts, could return in a web-native form. An Acequia page would be a document containing Web Components, each bound to URL channels, each rendering and editing a facet of the shared state. The "app" becomes the specific assemblage of components and channel bindings. A different assemblage of the same components, wired to different channels, yields a different app. This maps well to the [Redfish Creed's](https://guerin.acequia.io/redfish/redfish-creed.md) tenet 20: "Apps are soft-assembled model views and controllers." **Domain-based identity instead of code signing.** Where ActiveX asked "Do you trust this publisher's certificate?" and failed catastrophically, Acequia could ask "Does this component come from a domain whose mayordomo, user, device or app you trust?" Identity would be domain-based, keys published at `.well-known/acequia.json`, and trust would flow through the community governance model of the acequia. A parciante publishes components at their domain endpoint. Other parciantes subscribe based on community trust relationships, not certificate authorities. This is one possible trust model; there may be others worth considering. ### What an Acequia Component Might Look Like If we follow this framing, an Acequia component would be a standard Web Component with three additional conventions: 1. **Channel declarations.** The component declares the URL channels it reads from and writes to, either as HTML attributes or in a manifest. These declarations are the component's network interface, analogous to a JavaBean's event interface or a DCOM object's type library, but expressed as URLs. 2. **State binding.** The component binds its internal state to channel data. When channel data changes (whether from a local edit, a peer's WebRTC message, or a Firebase sync event), the component re-renders. When the user manipulates the component, it writes to the channel. The component does not need to know whether the channel is local, remote, or replicated. 3. **Self-description.** The component publishes metadata (name, version, channel interface, authoring domain) so that composition tools can discover and wire it. This is the introspection that JavaBeans provided through reflection and Director provided through the cast window. ```html ``` The `channel` attribute is a URL. The component subscribes to that URL. When the data changes (whether from a local sensor publishing via WebRTC, a Firebase sync, or a WebDAV resource update), the gauge re-renders. If the user drags the gauge to set a threshold, the component writes back to the channel. No RPC. No method stubs. No deployment descriptors. Just a URL and a Web Component. ### Composition Through Channel Wiring In this model, two Acequia components compose by sharing a channel: ```html ``` The slider writes wind speed to a channel. The fire simulation subscribes to wind speed and publishes spread rate. The map layer subscribes to spread rate. No JavaScript glue. No framework. No import graph. The components are independently developed, independently deployed, and composed through the shared medium of the acequia channel, like three irrigators drawing from the same ditch. If this framing holds up, it would be something close to what Alan Kay imagined in 1972: autonomous objects, communicating through messages, composable without knowing each other's internals, living on the network. It took fifty years, the failure of OpenDoc, the security disaster of ActiveX, the plugin death of Director, the complexity meltdown of EJB, and the incomplete promise of Web Components, to arrive at a moment where the browser platform may finally be ready. The channel is the ditch. The component is the parciante's field. The URL is the water right. And the browser, perhaps, is the acequia.