aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/design_principles/des_princ.xml
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /system/doc/design_principles/des_princ.xml
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'system/doc/design_principles/des_princ.xml')
-rw-r--r--system/doc/design_principles/des_princ.xml285
1 files changed, 285 insertions, 0 deletions
diff --git a/system/doc/design_principles/des_princ.xml b/system/doc/design_principles/des_princ.xml
new file mode 100644
index 0000000000..977eda49b5
--- /dev/null
+++ b/system/doc/design_principles/des_princ.xml
@@ -0,0 +1,285 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Overview</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>des_princ.xml</file>
+ </header>
+ <p>The <em>OTP Design Principles</em> is a set of principles for how
+ to structure Erlang code in terms of processes, modules and
+ directories.</p>
+
+ <section>
+ <title>Supervision Trees</title>
+ <p>A basic concept in Erlang/OTP is the <em>supervision tree</em>.
+ This is a process structuring model based on the idea of
+ <em>workers</em> and <em>supervisors</em>.</p>
+ <list type="bulleted">
+ <item>Workers are processes which perform computations, that is,
+ they do the actual work.</item>
+ <item>Supervisors are processes which monitor the behaviour of
+ workers. A supervisor can restart a worker if something goes
+ wrong.</item>
+ <item>The supervision tree is a hierarchical arrangement of
+ code into supervisors and workers, making it possible to
+ design and program fault-tolerant software.</item>
+ </list>
+ <marker id="sup6"></marker>
+ <image file="../design_principles/sup6.gif">
+ <icaption>Supervision Tree</icaption>
+ </image>
+ <p>In the figure above, square boxes represents supervisors and
+ circles represent workers.</p>
+ </section>
+
+ <section>
+ <title>Behaviours</title>
+ <p>In a supervision tree, many of the processes have similar
+ structures, they follow similar patterns. For example,
+ the supervisors are very similar in structure. The only difference
+ between them is which child processes they supervise. Also, many
+ of the workers are servers in a server-client relation, finite
+ state machines, or event handlers such as error loggers.</p>
+ <p><em>Behaviours</em> are formalizations of these common patterns.
+ The idea is to divide the code for a process in a generic part
+ (a behaviour module) and a specific part (a <em>callback module</em>).</p>
+ <p>The behaviour module is part of Erlang/OTP. To implement a
+ process such as a supervisor, the user only has to implement
+ the callback module which should export a pre-defined set of
+ functions, the <em>callback functions</em>.</p>
+ <p>An example to illustrate how code can be divided into a generic
+ and a specific part: Consider the following code (written in
+ plain Erlang) for a simple server, which keeps track of a number
+ of "channels". Other processes can allocate and free the channels
+ by calling the functions <c>alloc/0</c> and <c>free/1</c>,
+ respectively.</p>
+ <marker id="ch1"></marker>
+ <code type="none">
+-module(ch1).
+-export([start/0]).
+-export([alloc/0, free/1]).
+-export([init/0]).
+
+start() ->
+ spawn(ch1, init, []).
+
+alloc() ->
+ ch1 ! {self(), alloc},
+ receive
+ {ch1, Res} ->
+ Res
+ end.
+
+free(Ch) ->
+ ch1 ! {free, Ch},
+ ok.
+
+init() ->
+ register(ch1, self()),
+ Chs = channels(),
+ loop(Chs).
+
+loop(Chs) ->
+ receive
+ {From, alloc} ->
+ {Ch, Chs2} = alloc(Chs),
+ From ! {ch1, Ch},
+ loop(Chs2);
+ {free, Ch} ->
+ Chs2 = free(Ch, Chs),
+ loop(Chs2)
+ end.</code>
+ <p>The code for the server can be rewritten into a generic part
+ <c>server.erl</c>:</p>
+ <code type="none">
+-module(server).
+-export([start/1]).
+-export([call/2, cast/2]).
+-export([init/1]).
+
+start(Mod) ->
+ spawn(server, init, [Mod]).
+
+call(Name, Req) ->
+ Name ! {call, self(), Req},
+ receive
+ {Name, Res} ->
+ Res
+ end.
+
+cast(Name, Req) ->
+ Name ! {cast, Req},
+ ok.
+
+init(Mod) ->
+ register(Mod, self()),
+ State = Mod:init(),
+ loop(Mod, State).
+
+loop(Mod, State) ->
+ receive
+ {call, From, Req} ->
+ {Res, State2} = Mod:handle_call(Req, State),
+ From ! {Mod, Res},
+ loop(Mod, State2);
+ {cast, Req} ->
+ State2 = Mod:handle_cast(Req, State),
+ loop(Mod, State2)
+ end.</code>
+ <p>and a callback module <c>ch2.erl</c>:</p>
+ <code type="none">
+-module(ch2).
+-export([start/0]).
+-export([alloc/0, free/1]).
+-export([init/0, handle_call/2, handle_cast/2]).
+
+start() ->
+ server:start(ch2).
+
+alloc() ->
+ server:call(ch2, alloc).
+
+free(Ch) ->
+ server:cast(ch2, {free, Ch}).
+
+init() ->
+ channels().
+
+handle_call(alloc, Chs) ->
+ alloc(Chs). % => {Ch,Chs2}
+
+handle_cast({free, Ch}, Chs) ->
+ free(Ch, Chs). % => Chs2</code>
+ <p>Note the following:</p>
+ <list type="bulleted">
+ <item>The code in <c>server</c> can be re-used to build many
+ different servers.</item>
+ <item>The name of the server, in this example the atom
+ <c>ch2</c>, is hidden from the users of the client functions.
+ This means the name can be changed without affecting them.</item>
+ <item>The protcol (messages sent to and received from the server)
+ is hidden as well. This is good programming practice and allows
+ us to change the protocol without making changes to code using
+ the interface functions.</item>
+ <item>We can extend the functionality of <c>server</c>, without
+ having to change <c>ch2</c> or any other callback module.</item>
+ </list>
+ <p>(In <c>ch1.erl</c> and <c>ch2.erl</c> above, the implementation
+ of <c>channels/0</c>, <c>alloc/1</c> and <c>free/2</c> has been
+ intentionally left out, as it is not relevant to the example.
+ For completeness, one way to write these functions are given
+ below. Note that this is an example only, a realistic
+ implementation must be able to handle situations like running out
+ of channels to allocate etc.)</p>
+ <code type="none">
+channels() ->
+ {_Allocated = [], _Free = lists:seq(1,100)}.
+
+alloc({Allocated, [H|T] = _Free}) ->
+ {H, {[H|Allocated], T}}.
+
+free(Ch, {Alloc, Free} = Channels) ->
+ case lists:member(Ch, Alloc) of
+ true ->
+ {lists:delete(Ch, Alloc), [Ch|Free]};
+ false ->
+ Channels
+ end. </code>
+ <p>Code written without making use of behaviours 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.</p>
+ <p>Using behaviours also makes it easier to read and understand
+ code written by other programmers. Ad hoc programming structures,
+ while possibly more efficient, are always more difficult to
+ understand.</p>
+ <p>The module <c>server</c> corresponds, greatly simplified,
+ to the Erlang/OTP behaviour <c>gen_server</c>.</p>
+ <p>The standard Erlang/OTP behaviours are:</p>
+ <taglist>
+ <tag><seealso marker="gen_server_concepts">gen_server</seealso></tag>
+ <item>For implementing the server of a client-server relation.</item>
+ <tag><seealso marker="fsm">gen_fsm</seealso></tag>
+ <item>For implementing finite state machines.</item>
+ <tag><seealso marker="events">gen_event</seealso></tag>
+ <item>For implementing event handling functionality.</item>
+ <tag><seealso marker="sup_princ">supervisor</seealso></tag>
+ <item>For implementing a supervisor in a supervision tree.</item>
+ </taglist>
+ <p>The compiler understands the module attribute
+ <c>-behaviour(Behaviour)</c> and issues warnings about
+ missing callback functions. Example:</p>
+ <code type="none">
+-module(chs3).
+-behaviour(gen_server).
+...
+
+3> c(chs3).
+./chs3.erl:10: Warning: undefined call-back function handle_call/3
+{ok,chs3}</code>
+ </section>
+
+ <section>
+ <title>Applications</title>
+ <p>Erlang/OTP comes with a number of components, each implementing
+ some specific functionality. Components are with Erlang/OTP
+ terminology called <em>applications</em>. Examples of Erlang/OTP
+ applications are Mnesia, which has everything needed for
+ programming database services, and Debugger which is used to
+ debug Erlang programs. The minimal system based on Erlang/OTP
+ consists of the applications Kernel and STDLIB.</p>
+ <p>The application concept applies both to program structure
+ (processes) and directory structure (modules).</p>
+ <p>The simplest kind of application does not have any processes,
+ but consists of a collection of functional modules. Such an
+ application is called a <em>library application</em>. An example
+ of a library application is STDLIB.</p>
+ <p>An application with processes is easiest implemented as a
+ supervision tree using the standard behaviours.</p>
+ <p>How to program applications is described in
+ <seealso marker="applications">Applications</seealso>.</p>
+ </section>
+
+ <section>
+ <title>Releases</title>
+ <p>A <em>release</em> is a complete system made out from a subset of
+ the Erlang/OTP applications and a set of user-specific
+ applications.</p>
+ <p>How to program releases is described in
+ <seealso marker="release_structure">Releases</seealso>.</p>
+ <p>How to install a release in a target environment is described
+ in the chapter about Target Systems in System Principles.</p>
+ </section>
+
+ <section>
+ <title>Release Handling</title>
+ <p><em>Release handling</em> is upgrading and downgrading between
+ different versions of a release, in a (possibly) running system.
+ How to do this is described in
+ <seealso marker="release_handling">Release Handling</seealso>.</p>
+ </section>
+</chapter>
+