docs: document inversion of control pattern

Bug: None
Change-Id: Ie895d32cd402b8596ca833d8bd43f172947052de
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2463556
Commit-Queue: Elly Fong-Jones <[email protected]>
Reviewed-by: Peter Kasting <[email protected]>
Cr-Commit-Position: refs/heads/master@{#817507}
diff --git a/docs/patterns/inversion-of-control.md b/docs/patterns/inversion-of-control.md
new file mode 100644
index 0000000..d9516f7
--- /dev/null
+++ b/docs/patterns/inversion-of-control.md
@@ -0,0 +1,376 @@
+## Inversion of Control
+
+"Inversion of control" is a design pattern used to allow users of a framework
+or library (often called clients) to customize the behavior of the framework.
+
+### Our Example
+
+Examples in this document will be given by extending or modifying this example
+API, which is hopefully self-explanatory:
+
+    class StringKVStore {
+     public:
+      StringKVStore();
+      virtual ~StringKVStore();
+
+      using KeyPredicate = base::RepeatingCallback<bool(const string&)>;
+
+      void Put(const string& key, const string& value);
+      void Remove(const string& key);
+      void Clear();
+
+      string Get(const string& key) const;
+      set<string> GetKeys() const;
+      set<string> GetKeysMatching(const KeyPredicate& predicate) const;
+
+      void SaveToPersistentStore();
+    };
+
+### What is inversion of control?
+
+Normally, client code calls into the library to do operations, so control flows
+from a high-level class to a low-level class:
+
+    void YourFunction() {
+      // GetKeys() calls into the StringKVStore library
+      for (const auto& key : kv_store_.GetKeys()) {
+        ...
+      }
+    }
+
+In "inverted" control flow, the library calls back into your code after you
+call into it, so control flows back from a low-level class to a high-level
+class:
+
+    bool IsKeyInteresting(const string& key) { ... }
+
+    void YourFunction() {
+      StringKVStore::KeyPredicate predicate =
+          base::BindRepeating(&IsKeyInteresting);
+      // GetKeysMatching() calls into the StringKVStore library, but it calls
+      // back into IsKeyInteresting defined in this file!
+      for (const auto& key : kv_store_.GetKeysMatching(predicate)) {
+        ...
+      }
+    }
+
+It is also often inverted in the Chromium dependency sense. For example, in
+Chromium, code in //content can't call, link against, or generally be aware of
+code in //chrome - the normal flow of data and control is only in one direction,
+from //chrome "down" to //content. When //content calls back into //chrome, that
+is an inversion of control.
+
+Abstractly, inversion of control is defined by a low-level class defining an
+interface that a high-level class supplies an implementation of. In the example
+fragment given above, `StringKVStore` defines an interface called
+`StringKVStore::KeyPredicate`, and `YourFunction` supplies an implementation of
+that interface - namely the bound instance of `IsKeyInteresting`. This allows
+the low-level class to use functionality of the high-level class without being
+aware of the specific high-level class's existence, or a high-level class to
+plug logic into a low-level class.
+
+There are a few main ways this is done in Chromium:
+
+* Callbacks
+* Observers
+* Listeners
+* Delegates
+
+**Inversion of control should not be your first resort. It is sometimes useful
+for solving specific problems, but in general it is overused in Chromium.**
+
+### Callbacks
+
+Callbacks are one of the simplest ways to do inversion of control, and often are
+all you need. Callbacks can be used to split out part of the framework's logic
+into the client, like so:
+
+    void StringKVStore::GetKeysMatching(const KeyPredicate& predicate) {
+      set<string> keys;
+      for (const auto& key : internal_keys()) {
+        if (predicate.Run(key))
+          keys.insert(key);
+      }
+      return keys;
+    }
+
+where `predicate` was supplied by the client of
+`StringKVStore::GetKeysMatching`. They can also be used for the framework
+library to notify clients of events, like so:
+
+    void StringKVStore::Put(const string& key, const string& value) {
+      ...
+      // In real code you would use CallbackList instead, but for explanatory
+      // purposes:
+      for (const auto& callback : key_changed_callbacks_)
+        callback.Run(...);
+    }
+
+making use of [Subscription].
+
+Callbacks can also be used to supply an implementation of something deliberately
+omitted, like so:
+
+    class StringKVStore {
+      using SaveCallback = base::RepeatingCallback<void(string, string)>;
+      void SaveToPersistentStore(const SaveCallback& callback);
+    };
+
+### Observers
+
+An "observer" receives notifications of events happening on an object. For
+example, an interface like this might exist:
+
+    class StringKVStore::Observer {
+     public:
+      virtual void OnKeyChanged(StringKVStore* store,
+                                const string& key,
+                                const string& from_value,
+                                const string& to_value) {}
+      virtual void OnKeyRemoved(StringKVStore* store,
+                                const string& key,
+                                const string& old_value) {}
+      ...
+    }
+
+and then on the StringKVStore class:
+
+    class StringKVStore {
+     public:
+      ...
+      void AddObserver(Observer* observer);
+      void RemoveObserver(Observer* observer);
+    }
+
+So an example of a `StringKVStore::Observer` might be:
+
+    class HelloKeyWatcher : public StringKVStore::Observer {
+     public:
+      void OnKeyChanged(StringKVStore* store,
+                        const string& key,
+                        const string& from_value,
+                        const string& to_value) override {
+        if (key == "hello")
+          ++hello_changes_;
+      }
+      void OnKeyRemoved(StringKVStore* store,
+                        const string& key,
+                        const string& old_value) override {
+        if (key == "hello")
+          hello_changes_ = 0;
+      }
+    }
+
+where the `StringKVStore` arranges to call the relevant method on each
+`StringKVStore::Observer` that has been added to it whenever a matching event
+happens.
+
+Use an observer when:
+
+* More than one client may care to listen to events happening
+* Clients passively observe, but do not modify, the state of the framework
+  object being observed
+
+### Listeners
+
+A listener is an observer that only observes a single type of event. These were
+very common in C++ and Java before the introduction of lambdas, but these days
+are not as commonly seen, and you probably should not introduce new listeners -
+instead, use a plain [Callback].
+
+Here's an example:
+
+    class StringKVStore::ClearListener {
+     public:
+      virtual void OnCleared(StringKVStore* store) = 0;
+    }
+
+Use a listener when:
+
+* There is only a single client listener instance at most per framework object
+* There is only a single event being listened for
+
+### Delegates
+
+A delegate is responsible for implementing part of the framework that is
+deliberately missing. While observers and listeners are generally passive with
+respect to the framework object they are attached to, delegates are generally
+active.
+
+One very common use of delegates is to allow clients to make policy decisions,
+like so:
+
+    class StringKVStore::Delegate {
+     public:
+      virtual bool ShouldPersistKey(StringKVStore* store, const string& key);
+      virtual bool IsValidValueForKey(StringKVStore* store,
+                                      const string& key,
+                                      const string& proposed_value);
+    };
+
+Another common use is to allow clients to inject their own subclasses of
+framework objects that need to be constructed by the framework, by putting
+a factory method on the delegate:
+
+    class StringKVStore::Delegate {
+     public:
+      virtual unique_ptr<StringKVStoreBackend>
+          CreateBackend(StringKVStore* store);
+    }
+
+And then these might exist:
+
+    class MemoryBackedStringKVStoreDelegate : public StringKVStore::Delegate;
+    class DiskBackedStringKVStoreDelegate : public StringKVStore::Delegate;
+    ...
+
+Use a delegate when:
+
+* There needs to be logic that happens synchronously with what's happening in
+  the framework
+* It does not make sense to have a decision made statically per instance of a
+  framework object
+
+### Observer vs Listener vs Delegate
+
+If every call to the client could be made asynchronous and the API would still
+work fine for your use case, you have an observer or listener, not a delegate.
+
+If there might be multiple interested client objects instead of one, you have an
+observer, not a listener or delegate.
+
+If any method on your interface has any return type other than `void`, you have
+a delegate, not an observer or listener.
+
+You can think of it this way: an observer or listener interface *notifies* the
+observer or listener of a change to a framework object, while a delegate usually
+helps *cause* the change to the framework object.
+
+### Callbacks vs Observers/Listeners/Delegates
+
+Callbacks have advantages:
+
+* No separate interface is needed
+* Header files for client classes are not cluttered with the interfaces or
+  methods from them
+* Client methods don't need to use specific names, so the name-collision
+  problems above aren't present
+* Client methods can be bound (using [Bind]) with any needed state, including
+  which object they are attached to, so there is no need to pass the framework
+  object of interest back into them
+* The handler for an event is placed in object setup, rather than being implicit
+  in the presence of a separate method
+* They sometimes save creation of "trampoline" methods that simply discard or
+  add extra parameters before invoking the real handling logic for an event
+* Forwarding event handlers is a lot easier, since callbacks can easily be
+  passed around by themselves
+* They avoid multiple inheritance
+
+They also have disadvantages:
+
+* They can lead to deeply-nested setup code
+* Callback objects are heavyweight (performance and memory wise) compared to
+  virtual method calls
+
+### Design Tips
+
+1. Observers should have empty method bodies in the header, rather than having
+   their methods as pure virtuals. This has two benefits: client classes can
+   implement only the methods for events they care to observe, and it is
+   obvious from the header that the base observer methods do not need to be
+   called.
+
+2. Similarly, delegates should have sensible base implementations of every
+   method whenever this is feasible, so that client classes (subclasses of the
+   delegate class) can concern themselves only with the parts that are
+   relevant to their use case.
+
+3. When inverting control, always pass the framework object of interest back to
+   the observer/listener/delegate; that allows the client, if it wants to, to
+   reuse the same object as the observer/listener/delegate for multiple
+   framework objects. For example, if ButtonListener (given above) didn't pass
+   the button in, the same ButtonListener instance could not be used to listen
+   to two buttons simultaneously, since there would be no way to tell which
+   button received the click.
+
+4. Large inversion-of-control interfaces should be split into smaller
+   interfaces when it makes sense to do so. One notorious Chromium example
+   is [WebContentsObserver], which observes dozens of different events.
+   Whenever *any* of these events happens, *every* registered
+   WebContentsObserver has to be notified, even though virtually none of them
+   might care about this specific event. Using smaller interfaces helps with
+   this problem and makes the intent of installing a specific observer clearer.
+
+5. The framework class *should not* take ownership of observers or listeners.
+   For delegates the decision is less clear, but in general, err on the side of
+   not taking ownership of delegates either. It is common to hold raw pointers
+   to observers and listeners, and raw or weak pointers to delegates, with
+   lifetime issues managed via AddObserver/RemoveObserver or the helper classes
+   discussed below.
+
+6. Depending on your application and how widely-used you expect your observer,
+   listener, or delegate to be, you should probably use names that are longer
+   and more specific than you might otherwise. This is because client classes
+   may be implementing multiple inversion-of-control interfaces, so it is
+   important that their method names not collide with each other. For example,
+   instead of having `PageObserver::OnLoadStarted`, you might have
+   `PageObserver::OnPageLoadStarted` to reduce the odds of an unpleasant
+   collision with `NetworkRequestObserver::OnLoadStarted` (or similar). Note
+   that callbacks entirely avoid this problem.
+
+7. A callback is probably a better fit for what you're trying to do than one
+   of the other patterns given above!
+
+### Inversion of Control in Chromium
+
+Some key classes in `//base`:
+
+* [ScopedObserver]
+* [ObserverList] and [CheckedObserver]
+* [Subscription] and [CallbackList]
+
+And some production examples:
+
+* [WebContentsObserver] and [WebContentsDelegate]
+* [BrowserListObserver]
+* [URLRequestJobFactory::ProtocolHandler]
+* [WidgetObserver] and [ViewObserver]
+
+### When Not To Use This Pattern
+
+Inverted control can be harder to reason about, and more expensive at runtime,
+than other approaches. In particular, beware of using delegates when static data
+would be appropriate. For example, consider this hypothetical interface:
+
+    class StringKVStore::Delegate {
+      virtual bool ShouldSaveAtDestruction() { return true; }
+    }
+
+It should be clear from the naming that this method will only be called once per
+StringKVStore instance and that its value cannot meaningfully change within the
+lifetime of a given instance; in this case, "should save at destruction" should
+instead be a parameter given to StringKVStore directly.
+
+A good rule of thumb is that any method on a delegate that:
+
+* Will only be called once for a given framework object, or
+* Has a value that can't meaningfully change for a given framework object, and
+* Serves primarily to return that value, rather than doing some other work
+  like constructing a helper object
+
+should be a property on the framework object instead of a delegate method.
+
+[Bind]: ../../base/bind.h
+[BrowserListObserver]: ../../chrome/browser/ui/browser_list_observer.h
+[CallbackList]: ../../base/callback_list.h
+[Callback]: ../../base/callback.h
+[CheckedObserver]: ../../base/observer_list_types.h
+[ObserverList]: ../../base/observer_list.h
+[ScopedObserver]: ../../base/scoped_observer.h
+[Subscription]: ../../base/callback_list.h
+[URLRequestJobFactory::ProtocolHandler]: ../../net/url_request/url_request_job_factory.h
+[Unretained]: ../../base/bind.h
+[ViewObserver]: ../../ui/views/view_observer.h
+[WebContentsDelegate]: ../../content/public/browser/web_contents_delegate.h
+[WebContentsObserver]: ../../content/public/browser/web_contents_observer.h
+[WidgetObserver]: ../../ui/views/widget/widget_observer.h