Ask a developer to explain how programming works and they will probably show you examples of print statements and maths. Next, maybe conditional statements and loops. After the immediate basics people tend to venture into object oriented programming (OOP). No one can deny that OOP has been a successful idea in software development, and hundreds of thousands of successful software projects are around to prove it. However, even though many find it hard to think about software development without OOP, there are alternatives.
The basic idea of OOP is that logic and data should be bundled together in a unit called an object. This has the useful property that the exact structure of the data can be hidden behind an interface and that changes to this structure will only require changes to the logic in the same unit; allowing for safe refactorings and optimisations. The sometimes less fortunate side effect is that mutable data, state, can be passed around freely between parts of the system, and potentially used by multiple execution paths (threads and processes) concurrently.
The assumption that state can be accessed efficiently and reliably across a software system is a fallacy born out of the decades of single processor computing. At least for PCs, there was one processor and one type of random-access memory (RAM). Even though operating systems were able to give a convincing experience of multitasking, there was no true concurrency. This assumption no longer holds. Computers are more connected than ever, it is rare to have a game or application that does not perform any type of network access and many depend on a connection to the internet to function at all. It is also rare to find a processor architecture with a single processing unit, even mobile phones are now multi core!
To deal with distributed systems, i.e. systems where the individual parts do not have direct access to shared data storage, it is inevitable to use a message passing, directly, or indirectly. Various attempts have been made to hide the fact that messages are being exchanged and allow the programmer to think in terms of objects, CORBA, DCOM, .NET Remoting, and Java RMI being a few examples. Though these framework provide a somewhat more familiar software development experience, and to some degree allow flexibility in how components in a software system are deployed physically, they have inherent problems.
By hiding the fact that an operation is (or may be) performed remotely and through massage passing under the hood, the programmer may write code that, though efficient if running as a local application, can run orders of magnitude slower when parts of the system are executing remotely. A harmless looking operation such as accessing a counter that normally would complete in microseconds if performed as a local method call may take milliseconds if running on another computer on a local network or even seconds if accessed over the Internet over a congested connection.
Another problem, closely related, is the fact that a remote operation may not complete at all! A system running on a single computer and accessing only local resources will usually fail or work as a whole. If the RAM memory or a execution unit fails, you don’t normally expect a software system to continue gracefully. If your network connection is temporarily disconnected or a remote machine stops functioning however, you would expect something more than the entire system crashing or freezing. Hiding the fact that some method calls may fail completely again makes it likely that the programmer will not handle such catastrophic errors.
To address these issues, some software systems opt to embrace the message passing paradigm rather than hiding it under a thin object oriented layer. Erlang is an example where message passing as well as partial catastrophic failure are first class concepts. Originally design and used for building telecom switches, it has proven itself as a platform that allows for massive scalability and reliability, even claiming somewhat ridiculous records of “nine nines” (99.9999999% availability). Other systems have been inspired by the same ideas, such as the MailboxProcessor shipped with F# and the Akka message passing framework running on the JVM.
In the next post, finally, we will see how, when a multi threaded application is running on a modern multi core processor, you are already using message passing under the hood and how it has the same type of implications for software architecture as it has for distributed systems.
Update May 16 You can now continue reading in part 2.