\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
\PassOptionsToPackage{hyphens}{url}
%
\documentclass[]{article}
\usepackage{lmodern}
\usepackage{amssymb,amsmath}
\usepackage{ifxetex,ifluatex}
\usepackage{fixltx2e} % provides \textsubscript
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
  \usepackage[T1]{fontenc}
  \usepackage[utf8]{inputenc}
  \usepackage{textcomp} % provides euro and other symbols
\else % if luatex or xelatex
  \usepackage{unicode-math}
  \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
\fi
% use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
% use microtype if available
\IfFileExists{microtype.sty}{%
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
\IfFileExists{parskip.sty}{%
\usepackage{parskip}
}{% else
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}
}
\usepackage{hyperref}
\hypersetup{
            pdftitle={CSci 658: Software Language Engineering Pipes and Filters Architectural Pattern},
            pdfauthor={H. Conrad Cunningham},
            pdfborder={0 0 0},
            breaklinks=true}
\urlstyle{same}  % don't use monospace font for urls
\usepackage{color}
\usepackage{fancyvrb}
\newcommand{\VerbBar}{|}
\newcommand{\VERB}{\Verb[commandchars=\\\{\}]}
\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
% Add ',fontsize=\small' for more characters per line
\newenvironment{Shaded}{}{}
\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{#1}}
\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
\newcommand{\BuiltInTok}[1]{#1}
\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{#1}}}
\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{#1}}
\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{#1}}
\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{#1}}}
\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}}
\newcommand{\ExtensionTok}[1]{#1}
\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}}
\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{#1}}
\newcommand{\ImportTok}[1]{#1}
\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}}
\newcommand{\NormalTok}[1]{#1}
\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{#1}}
\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{#1}}
\newcommand{\RegionMarkerTok}[1]{#1}
\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{#1}}
\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{#1}}
\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
\setlength{\emergencystretch}{3em}  % prevent overfull lines
\providecommand{\tightlist}{%
  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\setcounter{secnumdepth}{0}
% Redefines (sub)paragraphs to behave more like sections
\ifx\paragraph\undefined\else
\let\oldparagraph\paragraph
\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
\fi
\ifx\subparagraph\undefined\else
\let\oldsubparagraph\subparagraph
\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
\fi

% set default figure placement to htbp
\makeatletter
\def\fps@figure{htbp}
\makeatother

\usepackage{caption}
\DeclareCaptionLabelFormat{nolabel}{}
\captionsetup{labelformat=nolabel}

\title{CSci 658: Software Language Engineering\\
Pipes and Filters Architectural Pattern}
\author{\textbf{H. Conrad Cunningham}}
\date{\textbf{17 February 2018}}

\begin{document}
\maketitle

{
\setcounter{tocdepth}{4}
\tableofcontents
}
Copyright (C) 2017, 2018, \href{http://www.cs.olemiss.edu/~hcc}{H.
Conrad Cunningham}\\
Professor of \href{https://www.cs.olemiss.edu}{Computer and Information
Science}\\
\href{http://www.olemiss.edu}{University of Mississippi}\\
211 Weir Hall\\
P.O. Box 1848\\
University, MS 38677\\
(662) 915-5358

\textbf{Advisory}: The HTML version of this document may require use of
a browser that supports the display of MathML. A good choice as of
February 2018 is a recent version of Firefox from Mozilla.

\textbf{Slides}: \href{sle_Pipes_Filters_Pattern.ppt}{Pipe and Filters
Architectural Pattern (Powerpoint)}

\hypertarget{pipes-and-filters-architectural-pattern}{%
\section{Pipes and Filters Architectural
Pattern}\label{pipes-and-filters-architectural-pattern}}

\hypertarget{definition}{%
\subsection{Definition}\label{definition}}

``The \emph{Pipes and Filters} architectural pattern provides a
structure for systems that process a stream of data. Each processing
step is encapsulated in a filter component. Data {[}are{]} passed
through pipes between adjacent filters. Recombining filters allows you
to build families of related filters.'' {[}Buschmann 1996{]}

\hypertarget{context}{%
\subsection{Context}\label{context}}

The context consists of programs that must process streams of data.

\hypertarget{problem}{%
\subsection{Problem}\label{problem}}

Suppose we need to build a system to solve a problem:

\begin{itemize}
\item
  that must be built by several developers
\item
  that decomposes naturally into several independent processing steps
\item
  for which the requirements are likely to change
\end{itemize}

The design of the components and their interconnections must consider
the following forces {[}Buschmann 1996{]}:

\begin{itemize}
\item
  It should be possible to enhance the system by substituting new
  filters for existing ones or by recombining the steps into a different
  communication structure.
\item
  Components implementing small processing steps are easier to reuse
  than components implementing large steps.
\item
  If two steps are not adjacent, then they share no information.
\item
  Different sources of input data exist.
\item
  It should be possible to display or store the final results of the
  computation in various ways.
\item
  If the user stores intermediate results in files, then the likelihood
  of errors increases and the file system may become cluttered with
  junk.
\item
  Parallel execution of the steps should be possible.
\end{itemize}

\hypertarget{solution}{%
\subsection{Solution}\label{solution}}

\begin{itemize}
\item
  Divide the task into a sequence of processing steps.
\item
  Let each step be implemented by a filter program that consumes from
  its input and produces data on its output incrementally.
\item
  Connect the output of one step as the input to the succeeding step by
  means of a pipe.
\item
  Enable the filters to execute concurrently.
\item
  Connect the input to the sequence to some data source, such as a file.
\item
  Connect the output of the sequence to some data sink, such as a file
  or display device.
\end{itemize}

\hypertarget{structure}{%
\subsection{Structure}\label{structure}}

The \emph{filters} are the processing units of the pipeline. A filter
may enrich, refine, or transform its input data {[}Buschmann 1996{]}.

\begin{itemize}
\item
  It may enrich the data by computing new information from the input
  data and adding it to the output data stream.
\item
  It may refine the data by concentrating or extracting information from
  the input data stream and passing only that information to the output
  stream.
\item
  It may transform the input data to a new form before passing it to the
  output stream.
\item
  It may, of course, do some combination of enrichment, refinement, and
  transformation.
\end{itemize}

A filter may be active (the more common case) or passive.

\begin{itemize}
\item
  An \emph{active} filter runs as a separate process or thread; it
  actively \emph{pulls} data from the input data stream and
  \emph{pushes} the transformed data onto the output data stream.
\item
  A \emph{passive} filter is activated by either being called:

  \begin{itemize}
  \item
    as a function, a \emph{pull} of the output from the filter
  \item
    as a procedure, a \emph{push} of output data into the filter
  \end{itemize}
\end{itemize}

The \emph{pipes} are the connectors--between a data source and the first
filter, between filters, and between the last filter and a data sink. As
needed, a pipe synchronizes the active elements that it connects
together.

A \emph{data source} is an entity (e.g., a file or input device) that
provides the input data to the system. It may either actively push data
down the pipeline or passively supply data when requested, depending
upon the situation.

A \emph{data sink} is an entity that gathers data at the end of a
pipeline. It may either actively pull data from the last filter element
or it may passively respond when requested by the last filter element.

(See the Class-Responsibility-Collaborator (CRC) cards for these
elements on page 56 of the Buschmann et al book.)

\hypertarget{implementation}{%
\subsection{Implementation}\label{implementation}}

Implementation of the pipes-and-filters architecture is usually not
difficult. It often includes the following steps {[}Buschmann et al{]}:

\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
  \emph{Divide the functionality of the problem into a sequence of
  processing steps.}

  Each step should only depend upon the outputs of the previous step in
  the sequence. The steps will become the filters in the system.

  In dividing up the functionality, be sure to consider variations or
  later changes that might be needed--a reordering of the steps or
  substitution of one processing step for another.
\item
  \emph{Define the type and format of the data to be passed along each
  pipe.}

  For example, Unix pipes carry an unstructured sequence of bytes.
  However, many Unix filters read and write streams of ASCII characters
  that are structured into lines (with the newline character as the line
  terminator).

  Another important formatting issue is how the end of the input is
  marked. A filter might rely upon a system end-of-input condition or it
  may need to implement their own ``sentinel'' data value to mark the
  end.
\item
  \emph{Determine how to implement each pipe connection.}

  For example, a pipe connecting active filters might be implemented
  with operating system or programming language runtime facility such as
  a message queue, a Unix-style pipe, or a synchronized-access bounded
  buffer.

  A pipe connecting to a passive filter might be implemented as a direct
  call of the adjacent filter: a push connection as a call of the
  downstream filter as a procedure or a pull connection as a call of the
  upstream filter as a function.
\item
  \emph{Design and implement the filters.}

  The design of a filter is based on the nature of the task to be
  performed and the natures of the pipes to which it can be connected.

  \begin{itemize}
  \item
    An active filter needs to run with its own \emph{thread of control}.
    It might run as as a ``heavyweight'' operating system process (i.e.,
    having its own address space) or as a ``lightweight'' thread (i.e.,
    sharing an address space with other threads).
  \item
    A passive filter does not require a separate thread of control
    (although it could be implemented with a separate thread).
  \end{itemize}

  The selection of the \emph{size of the buffer} inside a pipe is an
  important performance tradeoff. Large buffers may use up much
  available memory but likely will involve less synchronization and
  context-switching overhead. Small buffers conserve memory at the cost
  of increased overhead.

  To make filters flexible and, hence, increase their potential
  reusability, they often will need different \emph{processing options}
  that can be set when they are initiated. For example, Unix filters
  often take command line parameters, access environment variables, or
  read initialization files.
\item
  \emph{Design for robust handling of errors.}

  Error handling is difficult in a pipes-and-filters system since there
  is no global state and often multiple asynchronous threads of
  execution. At the least, a pipes-and-filters system needs mechanisms
  for detecting and reporting errors. An error should not result in
  incorrect output or other damage to the data.

  For example, a Unix program can use the \texttt{stderr} channel to
  report errors to its environment.

  More sophisticated pipes-and-filters systems should seek to recover
  from errors. For example, the system might discard bad input and
  resynchronize at some well-defined point later in the input data.
  Alternatively, the system might back up the input to some well-defined
  point and restart the processing, perhaps using a different processing
  method for the bad data.
\item
  \emph{Configure the pipes-and-filters system and initiate the
  processing.}

  One approach is to use a standardized main program to create, connect,
  and initiate the needed pipe and filter elements of the pipeline.

  Another approach is to use an end-user tool, such as a command shell
  or a visual pipeline editor, to create, connect, and initiate the
  needed pipe and filter elements of the pipeline.
\end{enumerate}

\hypertarget{example}{%
\subsection{Example}\label{example}}

An example pipes-and-filter system might be a retargetable compiler for
a programming language. The system might consist of a pipeline of
processing elements similar to the following:

\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
  A \emph{source} element reads the program text (i.e., source code)
  from a file (or perhaps a sequence of files) as a stream of
  characters.
\item
  A \emph{lexical analyzer} converts the stream of characters into a
  stream of lexical tokens for the language--keywords, identifier
  symbols, operator symbols, etc.
\item
  A \emph{parser} recognizes a sequence of tokens that conforms to the
  language grammar and translates the sequence to an abstract syntax
  tree.
\item
  A \emph{``semantic'' analyzer} reads the abstract syntax tree and
  writes an appropriately augmented abstract syntax tree.

  Note: This element handles context-sensitive syntactic issues such as
  type checking and type conversion in expressions.
\item
  A \emph{global optimizer} (usually optionally invoked) reads an
  augmented syntax tree and outputs one that is equivalent but
  corresponds to program that is more efficient in space and time
  resource usage.

  Note: A global optimizer may transform the program by operations such
  as factoring out common subexpressions and moving statements outside
  of loops.
\item
  An \emph{intermediate code generator} translates the augmented syntax
  tree to a sequence of instructions for a virtual machine.
\item
  A \emph{local optimizer} converts the sequence of intermediate code
  (i.e., virtual machine) instructions into a more efficient sequence.

  Note: A local optimizer may transform the program by removing unneeded
  loads and stores of data.
\item
  A \emph{backend code generator} translates the sequence of virtual
  machine instructions into a sequence of instructions for some real
  machine platform (i.e., for some particular hardware processor
  augmented by operating system calls and a runtime library).
\item
  If the previous step generated symbolic assembly code, then an
  \emph{assembler} is needed to translate the sequence of symbolic
  instructions into a relocatable binary module.
\item
  If the previous steps of the pipeline generated a sequence of separate
  binary modules, then a \emph{linker} might be needed to bind the
  separate modules with library modules to form a single executable
  (i.e., object code) module.
\item
  A \emph{sink} element outputs the resulting binary module into a file.
\end{enumerate}

The pipeline can be reconfigured to support a number of different
variations:

\begin{itemize}
\item
  If source code preprocessing is to be supported (e.g., as in C), then
  a \emph{preprocessor} filter (or filters) can be inserted in front of
  the lexical analyzer.
\item
  If the language is to be interpreted rather than translated into
  object code, then the backend code generator (and all components after
  it in the pipeline) can be replaced by an \emph{interpreter} that
  implements the virtual machine.
\item
  If the compiler is to be retargeted to a different platform, then a
  backend code generator (and assembler and linker) for the new platform
  can be substituted for the old one.
\item
  If the compiler is to be modified to support a different language with
  the same lexical structure, then only the parser, semantic analyzer,
  global optimizer, and intermediate code generator need to be replaced.

  Note: If the parser is driven by tables that describe the grammar,
  then it may be possible to use the same parser with a different table.
\item
  If a load-and-go compiler is desired, the file-output sink can be
  replaced by a \emph{loader} that loads the executable module into an
  address space in the computer's main memory and starts the module
  executing.
\end{itemize}

Of course, a pure active-filters system as described above for a
compiler may not be very efficient or convenient.

\begin{itemize}
\item
  Sometimes a system of filters can be made more efficient by directly
  sharing a global state. Otherwise the global information must be
  encoded by one filter, passed along a pipe to an adjacent filter,
  decoded by that filter, and so forth on downstream.

  In the compiler pipeline, the symbol table is a key component of the
  global state that is constructed by the lexical analyzer and needed by
  the phases downstream through (at least) the intermediate code
  generator.
\item
  Sometimes performance can be improved by combining adjacent active
  filters into one program and replacing the pipe by an upstream
  function call (a passive pull connection) or a downstream procedure
  call (a passive push connection).

  In the compiler pipeline, it may be useful to combine the phases from
  lexical analysis through intermediate code generation into one program
  because they share the symbol table. Performance can be further
  improved by having the parser directly call the lexical analyzer when
  the next token is needed.
\item
  Although a piece of information may not be required at some step, the
  availability of that information may be useful. For example, the
  symbol table information is not usually required during backend code
  generation, interpretation, or execution. However, some of the symbol
  table information, such as variable and procedure names, may be useful
  in generation of error messages and execution traces or for use by a
  runtime debugging tools.
\end{itemize}

\hypertarget{variants}{%
\subsection{Variants}\label{variants}}

So far we have focused on single-input single-output filters. A
generalization of the pipes-and-filters pattern allows filters with
multiple input and/or multiple output pipes to be connected in any
directed graph structure.

In general, such dataflow systems are difficult to design so that they
compute the desired result and terminate cleanly. However, if we
restrict ourselves to directed acyclic graph structures, the problem is
considerably simplified.

In the UNIX operating system shell, the \texttt{tee} filter provides a
mechanism to split a stream into two streams, named pipes provide
mechanisms for constructing network connections, and filters with
multiple input files/streams provide mechanisms for joining two streams.

Consider the following UNIX shell commands. On a Solaris ``Unix''
machine (late 1990's), this sequence sets up a pipe to build a sorted
list of all words that occur more than once in a file:

\begin{Shaded}
\begin{Highlighting}[]
    \CommentTok{# create two named pipes}
    \FunctionTok{mknod}\NormalTok{ pipeA p}
    \FunctionTok{mknod}\NormalTok{ pipeB p}
    \CommentTok{# set up side chain computation (running in the background)}
    \FunctionTok{cat}\NormalTok{ pipeA }\OperatorTok{>}\NormalTok{pipeB }\KeywordTok{&}
    \CommentTok{# set up main pipeline computation}
    \FunctionTok{cat}\NormalTok{ filename }\KeywordTok{|} \FunctionTok{tr}\NormalTok{ -cs }\StringTok{"[:alpha:]"} \StringTok{"[\textbackslash{}n*256]"}\NormalTok{ \textbackslash{}}
                 \KeywordTok{|} \FunctionTok{tr} \StringTok{"[:upper:]"} \StringTok{"[:lower:]"} \KeywordTok{|} \FunctionTok{sort} \KeywordTok{|} \FunctionTok{tee}\NormalTok{ pipeA }\KeywordTok{|} \FunctionTok{uniq}\NormalTok{ \textbackslash{}}
                 \KeywordTok{|} \FunctionTok{comm}\NormalTok{ -13 - pipeB }\KeywordTok{|} \FunctionTok{uniq} 
\end{Highlighting}
\end{Shaded}

\begin{itemize}
\item
  The \texttt{mknod} commands set up two named pipes, \texttt{pipeA} and
  \texttt{pipeB}, for connecting to a ``side chain'' computation.
\item
  The ``side chain'' command starts a \texttt{cat} program running in a
  \emph{background} fork (note the \texttt{\&}). The program takes its
  input from the pipe named \texttt{pipeA} and writes its output to the
  pipe named \texttt{pipeB}.
\item
  The main pipeline uses a \texttt{cat} filter as a source for the
  stream. The next two stages use filter \texttt{tr} to translate each
  sequence of non-alphabetic characters to a single newline character
  and to map all uppercase characters to lowercase, respectively. The
  words are now in a standard form--in lowercase, one per line.
\item
  The fourth stage of the main pipeline sorts the words into ascending
  order using the \texttt{sort} filter.
\item
  After the sort, the main pipeline uses a \texttt{tee} filter to
  replicate the stream, sending one copy down the main pipeline and
  another copy onto the side chain via \texttt{pipeA}.
\item
  The side chain simply copies the words from \texttt{pipeA} onto
  \texttt{pipeB}. Meanwhile the main pipeline uses the \texttt{uniq}
  filter to remove adjacent duplicate words.
\item
  The main pipeline stream and the side chain stream are then joined by
  the \texttt{comm} filter. The \texttt{comm} filter takes two inputs,
  one from main pipeline's stream (note the \texttt{-} parameter) and
  another from \texttt{pipeB}.
\item
  Invoking the \texttt{comm} filter with the \texttt{-13} option cause
  it to output the lines that appear in the second stream (i.e.,
  \texttt{pipeB}) but not the first stream (i.e., the main pipeline).
  Thus, the output is an alphabetical list of words that appear more
  than once in the input file.
\item
  The final stage, another \texttt{uniq} filter, removes duplicates from
  the final output.
\end{itemize}

\hypertarget{consequences}{%
\subsection{Consequences}\label{consequences}}

\hypertarget{benefits}{%
\subsubsection{Benefits}\label{benefits}}

The pipes-and-filters architectural pattern has the following benefits
{[}Buschmann et al{]}:

\begin{itemize}
\item
  \emph{Intermediate files unnecessary, but possible.} File system
  clutter is avoided and concurrent execution is made possible.
\item
  \emph{Flexibility by filter exchange.} It is easy to exchange one
  filter element for another with the same interfaces and functionality.
\item
  \emph{Flexibility by recombination.} It is not difficult to
  reconfigure a pipeline to include new filters or perhaps to use the
  same filters in a different sequence.
\item
  \emph{Reuse of filter elements.} The ease of filter recombination
  encourages filter reuse. Small, active filter elements are normally
  easy to reuse if the environment makes them easy to connect.
\item
  \emph{Rapid prototyping of pipelines.} Flexibility of exchange and
  recombination and ease of reuse enables the rapid creation of
  prototype systems.
\item
  \emph{Efficiency by parallel processing.} Since active filters run in
  separate processes or threads, pipes-and-filters systems can take
  advantage of a multiprocessor.
\end{itemize}

\hypertarget{liabilities}{%
\subsubsection{Liabilities}\label{liabilities}}

The pipes-and-filters architectural pattern has the following
liabilities {[}Buschmann et al{]}:

\begin{itemize}
\item
  \emph{Sharing state information is expensive or inflexible.} The
  information must be encoded, transmitted, and then decoded.
\item
  \emph{Efficiency gain by parallel processing is often an illusion.}
  The costs of data transfer, synchronization, and context switching may
  be high. Non-incremental filters, such as the Unix \texttt{sort}, can
  become the bottleneck of a system.
\item
  \emph{Data transformation overhead.} The use of a single data channel
  between filters often means that much transformation of data must
  occur, for example, translation of numbers between binary and
  character formats.
\item
  \emph{Error handling.} It is often difficult to detect errors in
  pipes-and-filters systems. Recovering from errors is even more
  difficult.
\end{itemize}

\hypertarget{acknowledgements}{%
\subsection{Acknowledgements}\label{acknowledgements}}

In Spring 2017, I adapted these notes from my previous notes on the
topic. I wrote the first version during Spring 1998 for my Software
Architecture course based primarily on the ``Pipes and Filters''
sections of the following books:

\begin{itemize}
\item
  Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, and
  Michael Stal. \emph{Pattern-Oriented Software Architecture: A System
  of Patterns}, Wiley, 1996.
\item
  Mary Shaw and David Garlan. \emph{Software Architecture: Perspectives
  on an Emerging Discipline}, Prentice-Hall, 1996.
\end{itemize}

In Spring 2018 I revised the notes slightly to fit in with the other
documents for the CSci 658 course.

I maintain these notes as text in Pandoc's dialect of Markdown using
embedded LaTeX markup for the mathematical formulas and then translate
the notes to HTML, PDF, and other forms as needed.

\hypertarget{references}{%
\subsection{References}\label{references}}

\begin{description}
\tightlist
\item[{[}Buschmann 1996{]} -- ``Siemens'' book]
Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, and
Michael Stal, \emph{Pattern -Oriented Software Architecture : A System
of Patterns}, Wiley, 1996.
\end{description}

\hypertarget{concepts}{%
\subsection{Concepts}\label{concepts}}

TODO

\end{document}
