1 Overview of Design Principles
Systems, or complete products, are made from a number of Applications. Applications provide the basic packaging mechanism for delivering systems. Applications are designed to be "weakly coupled" and it is often possible to make systems by combining existing applications with your own special purpose applications. New applications should be designed to be self sufficient, so they can be added to the existing base of applications and offered to future users of the system.
Examples of existing applications are
mnesia
, which has everything needed for programming database services, and thegs
graphics system for building graphical user interfaces.Applications are specified in terms of resources. Resources include modules, registered names, processes, and things like dependencies on other applications.
Applications must obey certain laws and must follow certain protocols so that they present a uniform interface to the Erlang system. For example, they must be written so that the code can be changed without stopping the system.
The easiest way to program a new application is to make use of the behaviours which are included in the system. A behaviour is a "pattern of design" which can be used to build an application. Applications which are programmed with the standard behaviours automatically follow the required protocols. Behaviours are explained in the next section of this chapter.
The most common way of programming an Erlang application is to start with a supervision tree. A supervision tree is a hierarchical tree of processes used to program fault-tolerant systems. The higher nodes in the supervision tree are called supervisors. They monitor the lower nodes, which are called workers, and detect when failures occur in the lower nodes.
Worker nodes actually perform computations. They do the work, the supervisors only check the status of the work and restart them if things go wrong. This supervision principle makes it possible to design and program fault-tolerant software. Worker nodes should also be programmed using behaviours, but this depends on what the worker nodes have to do.
If an application is written without the help of the behaviour modules, then the programmer must ensure that the application follows the required protocols. The following two modules are provided to help program applications which do not make use of the standard behaviors:
sys
. This module provides a set of library functions that follow the standard system protocols. Functions insys
should be used to interface your process to the rest of the system.supervisor_bridge
. This module makes it possible to use an existing set of processes within a supervision tree.Both
sys
andsupervisor_bridge
are intended for somewhat specialized usage and require detailed knowledge of the Erlang system.When writing code that is called by the standard behaviours, the programmer can call functions in the standard libraries. The libraries provide a rich and growing set of modules which contain commonly used library functions, such as
lists
,strings
,ordsets
,dict
, andfile
.1.1 Behaviours
Behaviours are formalizations of "design patterns" which can be used to program certain common problems.
Concurrent systems can be programmed by combining ideas and code from a small number of design patterns. Each design pattern, which we call a behaviour, solves a particular problem.
The standard behaviours which are included with the system are:
application
. This behaviour defines how applications are implemented and terminated.sup_bridge
. This behaviour is used to connect a process, or subsystem, to a supervisor tree although it has not been designed with the supervision principle in mind.supervisor
. This behaviour is a worker/supervisor model for structuring fault tolerant computations, and for programming supervision trees.gen_server
. This behaviour is used for programming client-server processes.gen_event
. This behaviour is used for programming event handling mechanisms, such as event handlers and loggers, error loggers, and plug-and-play handlers.gen_fsm
. This behaviour is used for programming finite state machines.Behaviours are implemented as callback modules. A callback module must export a specific set of functions, which are then called by the system as the behaviour process executes.
All modules which make use of behaviours should start as follows:
-module(xx). -behaviour(yy). ...This means that the module
xx
has the behaviouryy
. In the following declaration, the moduledisk_alloc
has behaviourgen_server
-module(disk_alloc). -behaviour(gen_server). ...In a following section, titled Servers, the following type of statements are used (see also the Reference Manual,
stdlib
, the modulegen_server)
:Module:init(Args) -> {ok, State} | {ok, State, Timeout}| ignore | {stop, StopReason} ... Module:handle_call(Request, From, State) -> CallReply ...Here
Module
is the name of the callback module. In the previous example, this is the moduledisk_alloc
, anddisk_alloc
must exportinit/1
andhandle_call/3
for example.Read the section Servers in this chapter, which explains the philosophy of the client-server behaviour. This section should be read in conjunction with the Reference Manual,
stdlib
, modulegen_server
, which describes the callback API in greater detail.It is sometimes possible to write a program which does not make use of the application and behaviour mechanisms. Such programs may be more efficient, but the increased efficiency will be at the expense of generality. The ability to manage all applications in the system in a consistent manner is very important.
Programmers will find it easy to read and understand the code produced by others who are familiar with the application architecture and standard behaviours. Ad hoc programming structures, while possibly more efficient, are always more difficult to understand.