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