Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 1 | # Service Development Guidelines |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 2 | |
rockot | f59d2d6 | 2017-04-01 02:49:08 | [diff] [blame] | 3 | [TOC] |
| 4 | |
| 5 | ## Overview |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 6 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 7 | The top-level `//services` directory contains the sources, public Mojo interface |
| 8 | definitions, and public client libraries for a number of essential services, |
| 9 | designated as **Chrome Foundation Services**. If you think of Chrome as a |
| 10 | "portable OS," Chrome Foundation Services can be thought of as the core system |
| 11 | services of that OS. |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 12 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 13 | Each subdirectory here corresponds to a service that: |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 14 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 15 | - generally focuses on a subset of functionality or features which are |
| 16 | thematically or functionally related in a way that makes sense given the name |
| 17 | of the service |
| 18 | - could logically run in an isolated process for security or performance |
| 19 | isolation, depending on the constraints of the host OS |
Colin Blundell | 3294539 | 2017-06-28 08:52:17 | [diff] [blame] | 20 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 21 | *** aside |
| 22 | Note that there are other parts of the tree which aggregate |
| 23 | slightly-less-than-foundational service definitions, such as services specific |
Ken Rockot | 216eb5d | 2020-02-19 17:09:55 | [diff] [blame] | 24 | to the Chrome browser defined in `//chrome/services` or reusable services for |
| 25 | Content or its embedders, defined in `//components/services`. The motivations, |
| 26 | advice, and standards discussed in this document apply to all service |
| 27 | definitions in the Chromium tree. |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 28 | *** |
Colin Blundell | 3294539 | 2017-06-28 08:52:17 | [diff] [blame] | 29 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 30 | One of the main motivations for expressing Chromium as a collection of services |
| 31 | is long-term maintainability and code health. Because service API boundaries are |
| 32 | strictly limited to Mojo interfaces, state owned and managed by each service is |
| 33 | strongly isolated from other components in the system. |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 34 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 35 | Another key motivation is general modularity and reusability: in the past there |
| 36 | have been a number of missed opportunities for potential new features or |
| 37 | Chromium-based products due to the browser's generally monolothic and inflexible |
Ken Rockot | 216eb5d | 2020-02-19 17:09:55 | [diff] [blame] | 38 | system design. With the services providing scaffolding for system components, it |
| 39 | becomes progressively easier to build out newer use cases with *e.g.* a smaller |
| 40 | resource footprint, or a different process model, or even a more granular binary |
| 41 | distribution. |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 42 | |
| 43 | ## Service Standards |
| 44 | |
| 45 | As outlined above, individual services are intended for graceful reusability |
| 46 | across a broad variety of use cases. To enable this goal, we have rigorous |
| 47 | standards on services' structure and public API design. Before doing significant |
| 48 | work in `//services` (or other places where services are defined), please |
| 49 | internalize these standards. All Chromium developers are responsible for |
| 50 | upholding them! |
| 51 | |
| 52 | ### Public Service APIs |
| 53 | |
| 54 | In creating and maintaining a service's public API, please respect the following |
| 55 | principles: |
| 56 | |
| 57 | - The purpose of a service should be readily apparent. |
| 58 | - The supported client use cases of the service should be easy for a new |
| 59 | consumer to understand. |
| 60 | - The service should use idioms and design patterns consistent with other |
| 61 | services. |
| 62 | - From the service's public API documentation and tests, it should be feasible |
| 63 | to develop a new implementation of the service which satisfies existing |
| 64 | clients and doesn't require mimicking internal implementation details of the |
| 65 | existing service. |
| 66 | - Perhaps most important of all, a service's public API should be designed with |
| 67 | multiple hypothetical clients in mind, *not* focused on supporting only a |
| 68 | single narrow use known at development time. **Always be thinking about the |
| 69 | future!** |
| 70 | |
| 71 | If you're working on a new service and have concerns or doubts about API design, |
| 72 | please post to |
| 73 | [[email protected]](https://groups.google.com/a/chromium.org/forum#!forum/services-dev) |
| 74 | and ask for help. The list is generally quite responsive, and it's loaded with |
| 75 | people who have done a lot of work on services. |
| 76 | |
| 77 | ### Service API Design Tips |
| 78 | |
| 79 | #### Using Interface Factories to Establish Context |
| 80 | |
| 81 | One common pitfall when designing service APIs is to write something like: |
| 82 | |
| 83 | ``` cpp |
| 84 | interface GoatTeleporter { |
| 85 | // Sets the client interface pipe for this teleporter. Must be called before |
| 86 | // other interface methods. |
| 87 | SetClient(GoatTeleporterClient client); |
| 88 | |
| 89 | TeleportGoat(string name); |
| 90 | }; |
| 91 | |
| 92 | interface GoatTeleporterClient { |
| 93 | TeleporterReady(); |
| 94 | }; |
rockot | f59d2d6 | 2017-04-01 02:49:08 | [diff] [blame] | 95 | ``` |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 96 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 97 | The problem with this approach is that a client may easily fail to call |
| 98 | `SetClient` before calling `TeleportGoat`. When such ordering requirements are |
| 99 | necessary, the service can benefit clients by designing an API that is harder |
| 100 | to fail at. For example: |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 101 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 102 | ``` cpp |
| 103 | interface GoatTeleporterFactory { |
| 104 | GetGoatTeleporter(GoatTeleporter& request, GoatTeleporterClient client); |
| 105 | }; |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 106 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 107 | interface GoatTeleporter { |
| 108 | TeleportGoat(string name); |
| 109 | }; |
| 110 | ``` |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 111 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 112 | Instead of exposing `GoatTeleporter` directly to other services, the service can |
| 113 | expose `GoatTeleporterFactory` instead. Now it's impossible for a client to |
| 114 | acquire a functioning `GoatTeleporter` pipe without also providing a |
| 115 | corresponding client pipe to complement it. |
ben | ffa42c6 | 2016-04-09 05:10:13 | [diff] [blame] | 116 | |
Ken Rockot | 216eb5d | 2020-02-19 17:09:55 | [diff] [blame] | 117 | ### Interface Naming |
jam | 3009e4c | 2016-06-09 16:34:05 | [diff] [blame] | 118 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 119 | Just some basic tips for service and interface naming: |
jam | b249fa9 | 2017-02-01 23:19:42 | [diff] [blame] | 120 | |
Ken Rockot | 216eb5d | 2020-02-19 17:09:55 | [diff] [blame] | 121 | - Strive to give your service's main interface a name that directly conveys the |
| 122 | general purpose of the service (*e.g.*, `NetworkService`, `StorageService`) |
| 123 | rather than a meaningless codename like `Cromulator`. |
ben | a6e9b7f | 2016-06-11 00:58:46 | [diff] [blame] | 124 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 125 | - Strive to avoid conceptual layering violations in naming and documentation -- |
| 126 | *e.g.*, avoid referencing Blink or Content concepts like "renderers" or |
| 127 | "frame hosts". |
rockot | f59d2d6 | 2017-04-01 02:49:08 | [diff] [blame] | 128 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 129 | - Use the names `FooClient` and `FooObserver` consistently in interfaces. If |
| 130 | there is an expected 1:1 correspondence between a Foo and its client interface |
| 131 | counterpart, that counterpart should most likely be called `FooClient`. If |
| 132 | there is expected to be 1-to-many correspondence between a Foo and its |
| 133 | counterpart clients, the client interface may be better named `FooObserver`. |
blundell | 77afe7a6 | 2017-05-02 09:08:49 | [diff] [blame] | 134 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 135 | ### Service Directory & Dependency Structure |
ben | a6e9b7f | 2016-06-11 00:58:46 | [diff] [blame] | 136 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 137 | Services typically follow a canonical directory structure: |
ben | a6e9b7f | 2016-06-11 00:58:46 | [diff] [blame] | 138 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 139 | ``` |
| 140 | //services/service_name/ # Private implementation |
| 141 | public/ |
| 142 | mojom/ # Mojom interfaces |
| 143 | cpp/ # C++ client libraries (optional) |
| 144 | java/ # Java client libararies (optional, rare) |
| 145 | js/ # JS client libraries (optional, rare) |
| 146 | ``` |
jam | b249fa9 | 2017-02-01 23:19:42 | [diff] [blame] | 147 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 148 | As a general rule, **nothing below `/public` can depend on the private service |
| 149 | implementation** (*i.e.* things above `/public`). Enforcing this principle makes |
| 150 | it much easier to keep the service's state well-isolated from the rest of the |
| 151 | system. |
jam | b249fa9 | 2017-02-01 23:19:42 | [diff] [blame] | 152 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 153 | Generally the language-specific client libraries are built against only the |
| 154 | public mojom API of the service (and usually few other common dependencies like |
Ken Rockot | 216eb5d | 2020-02-19 17:09:55 | [diff] [blame] | 155 | `//base` and `//mojo`). |
jam | b249fa9 | 2017-02-01 23:19:42 | [diff] [blame] | 156 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 157 | Even in the private service implementation, services should not depend on very |
| 158 | large components like Content, Chrome, or Blink. |
blundell | 77afe7a6 | 2017-05-02 09:08:49 | [diff] [blame] | 159 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 160 | *** aside |
| 161 | NOTE: Exceptions to the above rule are made in rare cases where Blink or V8 is |
| 162 | actually required as part of the service implementation. For example |
| 163 | `"data_decoder"` uses Blink implementation to decode common image formats, and |
| 164 | `"proxy_resolver"` uses V8 to execute proxy autoconfig scripts. |
| 165 | *** |
| 166 | |
| 167 | ### Service Documentation |
| 168 | |
| 169 | - Every service should have a top-level `README.md` that explains the purpose and |
| 170 | supported usage models of the service. |
| 171 | |
| 172 | - Every public interface should be documented within its Mojom file at both the |
| 173 | interface level and indivudal message level. |
| 174 | |
| 175 | - Interface documentation should be complete enough to serve as test |
| 176 | specifications. If the method returns information of a user's accounts, what |
| 177 | should happen if the user is not signed in? If the method makes a request for |
| 178 | an access token, what happens if a client makes a second method call before |
| 179 | the first one has completed? If the method returns a nullable object, under |
| 180 | which conditions will it be null? |
| 181 | |
| 182 | - Avoid writing interface documentation which is unnecessarily prescriptive |
| 183 | about implementation details. Keep in mind that these are **interface** |
| 184 | definitions, not implementations thereof. |
| 185 | |
| 186 | - Avoid writing documentation which is tailored to a specific client. |
| 187 | |
| 188 | ### Service Testing |
| 189 | |
| 190 | - Try to cover service implementation details with unit tests tied as closely |
| 191 | as possible to the private implementation object or method being tested, |
| 192 | rather than exercising implementation details through public API surface. |
| 193 | |
| 194 | - For integration tests, try to have tests cover as much of the public API |
| 195 | surface as possible while mocking out as little of the underlying service as |
| 196 | possible. |
| 197 | |
| 198 | - Treat the public API tests as "conformance tests" which clearly demonstrate |
| 199 | what expectations and guarantees are supposed to be upheld by *any* |
| 200 | implementation of the service's APIs. |
| 201 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 202 | ## Adding a New Service |
| 203 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 204 | Please start a thread on |
Mathias Bynens | e7ee6ef | 2024-04-01 18:33:12 | [diff] [blame] | 205 | [[email protected]](https://groups.google.com/a/chromium.org/g/services-dev) |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 206 | if you want to propose the introduction of a new service. |
| 207 | |
| 208 | If you are servicifying an existing Chromium feature, please check out |
| 209 | [Servicifying Chromium Features](/docs/servicification.md). |
| 210 | |
| 211 | ## Other Docs |
| 212 | |
| 213 | Here are some other external documents that aren't quite fully captured by any |
| 214 | documents in the Chromium tree. Beware of obsolete information: |
| 215 | |
| 216 | - [High-level Design Doc](https://docs.google.com/document/d/15I7sQyQo6zsqXVNAlVd520tdGaS8FCicZHrN0yRu-oU) |
Mathias Bynens | e7ee6ef | 2024-04-01 18:33:12 | [diff] [blame] | 217 | - [Servicification Homepage](https://www.chromium.org/servicification/) |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 218 | |
| 219 | ## Additional Support |
| 220 | |
| 221 | You can always post to |
Mathias Bynens | e7ee6ef | 2024-04-01 18:33:12 | [diff] [blame] | 222 | [services-dev@chromium.org](https://groups.google.com/a/chromium.org/g/services-dev) |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 223 | with questions or concerns about anything related to service development. |