xref: /aosp_15_r20/external/pigweed/docs/facades.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _docs-facades:
2
3==================
4Facades & backends
5==================
6This page explains what "facades" and "backends" mean in the context of Pigweed
7and provides guidelines on when to use them.
8
9.. _docs-facades-definition:
10
11------------------------------
12What are facades and backends?
13------------------------------
14.. _top-down approach: https://en.wikipedia.org/wiki/Bottom%E2%80%93up_and_top%E2%80%93down_design
15
16Let's take a `top-down approach`_, starting with high-level definitions.
17In the context of a Pigweed module:
18
19* A facade is an API contract of a module that must be satisfied at compile-time,
20  i.e. a swappable dependency that changes the implementation of an API at
21  compile-time.
22* A backend is an implementation of a facade's contract.
23
24Usually, the facade and the backend are in different modules. One module
25exposes the facade contract, and another module is the backend that implements
26the facade contract. The naming pattern that Pigweed follows is
27``{facade_name}_{backend_name}``.
28
29Facades, by design, don't need to be configured until they're actually used.
30This makes it significantly easier to bring up features piece-by-piece.
31
32Example: pw_log and pw_log_string
33=================================
34Here's a step-by-step walkthrough of how a real backend module implements
35another module's facade.
36
37.. _//pw_log/public/pw_log/log.h: https://cs.opensource.google/pigweed/pigweed/+/main:pw_log/public/pw_log/log.h
38.. _//pw_log_string/public_overrides/pw_log_backend/log_backend.h: https://cs.opensource.google/pigweed/pigweed/+/main:pw_log_string/public_overrides/pw_log_backend/log_backend.h
39
40* :ref:`module-pw_log` is a module that exposes a facade. The macros listed in
41  :ref:`module-pw_log-macros` represent the API of the module.
42* The ``#include "pw_log/log_backend.h"`` line in `//pw_log/public/pw_log/log.h`_
43  represents the facade contract of ``pw_log``.
44* :ref:`module-pw_log_string` is a backend module, It implements the
45  ``pw_log/log_backend.h`` facade contract in
46  `//pw_log_string/public_overrides/pw_log_backend/log_backend.h`_.
47* In the build system there is a variable of some sort that specifies the
48  backend. In Bazel there's a `label
49  flag <https://bazel.build/extending/config#label-typed-build-settings>`_
50  at ``//pw_log:backend``. In CMake there's a ``pw_log_BACKEND`` variable set
51  to ``pw_log_string``. In GN there's a ``pw_log_BACKEND`` variable set to
52  ``dir_pw_log_string``.
53
54.. note::
55
56   There are a few more steps needed to get ``pw_log_string`` hooked up as the
57   backend for ``pw_log`` but they aren't essential for the current discussion.
58   See :ref:`module-pw_log_string-get-started-gn` for the details.
59
60Example: Swappable OS libraries
61===============================
62The facade and backend system is similar to swappable OS libraries: you can
63write code against ``libc`` (for example) and it will work so long as you have
64an object to link against that has the symbols you're depending on. You can
65swap in different versions of ``libc`` and your code doesn't need to know about
66it.
67
68A similar example from Windows is ``d3d9.dll``. Developers often swap this DLL
69with a different library like ReShade to customize shading behavior.
70
71Can a module have multiple facades?
72===================================
73Yes. The module-to-facade relationship is one-to-many. A module can expose
740, 1, or many facades. There can be (and usually are) multiple backend modules
75implementing the same facade.
76
77Is the module facade the same thing as its API?
78===============================================
79No. It's best to think of them as different concepts. The API is the interface
80that downstream projects interact with. There's always a one-to-one relationship
81between a module and its API. A facade represents the build system "glue" that
82binds a backend to an API.
83
84This is a common point of confusion because there are a few modules that
85blur this distinction. Historically, the facade comprised the API as well as
86the build system concept. We're moving away from this perspective.
87
88Are Pigweed facades the same as the GoF facade design pattern?
89==============================================================
90.. _facade pattern: https://en.wikipedia.org/wiki/Facade_pattern
91
92There are some loose similarities but it's best to think of them as different
93things. The goal of the Gang of Four `facade pattern`_ is to compress some
94ugly, complex API behind a much smaller API that is more aligned with your
95narrow business needs. The motivation behind some Pigweed facades is loosely
96the same: we don't want a device HAL to leak out into your include paths when
97a facade is implemented.
98
99------------------------------
100Why does Pigweed have facades?
101------------------------------
102Pigweed's facades are basically a pattern that builds off the ideas of
103`link-time substitution <https://bramtertoolen.medium.com/91ffd4ef8687>`_.
104Link-time substitution only allows you to replace one source file with another,
105whereas facades enable substituting program elements defined in *header files*.
106
107Pigweed facades enable implementation flexibility with zero performance cost.
108There are two ways to look at this. Continuing with the ``pw_log`` example:
109
110* Organizations can reuse more code across projects by adopting the ``pw_log``
111  API as their logging layer. Facades enable each project to customize how
112  its logs are handled.
113* For projects that want to integrate with ``pw_log`` but cannot adopt its
114  API, facades can wrap the existing API which enables Pigweed to be compatible
115  with the existing system.
116
117Two of the major aspects of "implementation flexibility" enabled by facades are:
118
119* Portability. For example, ``pw_sync`` needs platform-specific
120  implementations to work correctly.
121* Customized behavior. For example, you can make a fully portable ``pw_log``
122  implementation, but what makes it special is the ability to tune it to your
123  needs.
124
125Why compile-time?
126=================
127Resolving facades and backends at compile-time enables:
128
129* Call-site control from backends.
130* Static allocation of backend-provided types.
131* Explicit backend includes so it’s visually obvious you’re poking through
132  abstraction.
133
134--------------------------------
135When to use facades and backends
136--------------------------------
137If you're trying to use a Pigweed module, and that module exposes a facade,
138then you've got no choice: you've got to hook up a backend to fulfill that
139facade contract or else the module won't work.
140
141When to roll your own facades and backends
142==========================================
143* You need a global function or macro.
144* You absolutely must avoid the overhead of virtual functions.
145
146When to NOT roll your own facades and backends
147==============================================
148* If you can afford the runtime cost of dependency injection, use that.
149  In all other cases where link-time subsitution will work, use that.
150  Only if the API contract requires a backend to provide a header (which
151  link-time substitution doesn't let you do) should you reach for a facde.
152* You're trying to use globals to avoid dependency injection. Use
153  the dependency injection! It makes testing much easier.
154* Your needs can be served by a standard mechanism like virtual interfaces.
155  Use the standard mechanism.
156