Interface layers
In large program systems, groups of compilation units (in the case of Erlang, modules) usually form logical layers. A desired property of such systems is that code in one layer should only use the layer immediately below it, and conversely, provide functionality only for the layer immediately above it. This page shows how you can define such layers and find functions that access layers that they are not supposed to.
Defining interface layers
We use a list to represent the hierarchy of the interface layers, starting with the lowest layer. Layers are described with tuples {Name, ModSpecs} :: {atom(), [modspec()]}, where Name is the name of the layer, and ModSpecs is a list that can contain any of the following.
Erlang term | Description | Example | Example description |
atom() | the name of a loaded module | one1 | the module one1 |
{'gn',module,ModIdx} | the identifier of a module node | {'gn',module,2} | module #2 in the graph representation |
string() containing a regexp | a regular expression for module names | "^(/home/user)/[a-zA-Z0-9_/]+(/layer1)$" | files from a layer1 directory under /home/user |
string() | name of a file that contains regexps | "layer1_regexps.txt" | regexps inside layer1_regexps.txt |
Define additional relations
Sometimes, it is desirable to allow calls between layers that do not conform to the above. For that purpose, we use a list of {AllowFrom, AllowTo} :: {atom(), atom()} pairs, where AllowFrom and AllowTo are layer names.
Interface functions
We currently have three interface functions in the ri module: check_layered_arch/2, show_layered_arch/2 and show_layered_arch/3. The first two both take two parameters: {Name, ModSpecs} and {AllowFrom, AllowTo} as described above. The third has an extra parameter, which defines the name of the generated .dot file. The function ri:check_layered_arch/2 outputs the functions that violate the layer access restrictions, while ri:show_layered_arch/2 and ri:show_layered_arch/3 visualises the layers in a graph with the layer violations highlighted.
Examples
ri:check_layered_arch( [ {il1,["^(/home/user/layers/layer1)$"]}, {il2,["^(/home/user/layers/layer2)$"]}, {il3,["regexp3"]}], []).
ri:show_layered_arch( [ {il1,["^(/home/user/layers/layer1)$"]}, {il2,["^(/home/user/layers/layer2)$"]}, {il3,["regexp3"]}], []).
ri:show_layered_arch( [ {il1,["^(/home/user/layers/layer1)$"]}, {il2,["^(/home/user/layers/layer2)$"]}, {il3,["regexp3"]}], [{il1,il3}],"restrictions.dot").