{"id":13801093,"url":"https://github.com/stuartsierra/component","last_synced_at":"2025-10-22T02:19:32.737Z","repository":{"id":11334628,"uuid":"13760299","full_name":"stuartsierra/component","owner":"stuartsierra","description":"Managed lifecycle of stateful objects in Clojure","archived":false,"fork":false,"pushed_at":"2025-10-18T17:27:41.000Z","size":157,"stargazers_count":2124,"open_issues_count":3,"forks_count":93,"subscribers_count":58,"default_branch":"master","last_synced_at":"2025-10-19T10:36:59.422Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stuartsierra.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-10-22T01:48:47.000Z","updated_at":"2025-10-18T04:50:37.000Z","dependencies_parsed_at":"2022-08-07T06:01:21.097Z","dependency_job_id":null,"html_url":"https://github.com/stuartsierra/component","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/stuartsierra/component","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuartsierra%2Fcomponent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuartsierra%2Fcomponent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuartsierra%2Fcomponent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuartsierra%2Fcomponent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stuartsierra","download_url":"https://codeload.github.com/stuartsierra/component/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuartsierra%2Fcomponent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280365627,"owners_count":26318388,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-22T02:00:06.515Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T00:01:19.423Z","updated_at":"2025-10-22T02:19:32.691Z","avatar_url":"https://github.com/stuartsierra.png","language":"Clojure","funding_links":[],"categories":["Dependency injection","Awesome ClojureScript","\u003ca name=\"Clojure\"\u003e\u003c/a\u003eClojure"],"sub_categories":["State Management"],"readme":"# Component\n\n'Component' is a tiny Clojure framework for managing the lifecycle and\ndependencies of software components which have runtime state.\n\nThis is primarily a design pattern with a few helper functions. It can\nbe seen as a style of dependency injection using immutable data\nstructures.\n\nSee the [video from Clojure/West 2014](https://www.youtube.com/watch?v=13cmHf_kt-Q) (YouTube, 40 minutes)\n\n\n## Releases and Dependency Information\n\n* I publish releases to [Clojars]\n\n* Latest stable release is [1.1.0](https://github.com/stuartsierra/component/tree/component-1.1.0)\n\n* [All releases](https://clojars.org/com.stuartsierra/component)\n\n* [Change Log](CHANGES.md)\n\n[Leiningen] dependency information:\n\n    [com.stuartsierra/component \"1.1.0\"]\n\n[deps.edn] dependency information:\n\n    com.stuartsierra/component {:mvn/version \"1.1.0\"}\n\n[Maven] dependency information:\n\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.stuartsierra\u003c/groupId\u003e\n      \u003cartifactId\u003ecomponent\u003c/artifactId\u003e\n      \u003cversion\u003e1.1.0\u003c/version\u003e\n    \u003c/dependency\u003e\n\n[Clojars]: http://clojars.org/\n[deps.edn]: http://www.gradle.org/\n[Leiningen]: http://leiningen.org/\n[Maven]: http://maven.apache.org/\n\n\n\n## Dependencies and Compatibility\n\nStarting with version 0.3.0 of 'Component', Clojure or ClojureScript\nversion 1.7.0 or higher is required for Conditional Read support.\n\nVersion 0.2.3 of 'Component' is compatible with\nClojure versions 1.4.0 and higher.\n\n'Component' requires my [dependency] library\n\n[dependency]: https://github.com/stuartsierra/dependency\n\n\n\n## Discussion\n\nPlease post questions on the [Clojure Mailing List](https://groups.google.com/forum/#!forum/clojure)\n\n\n\n## Introduction\n\nFor the purposes of this framework, a *component* is a collection of\nfunctions or procedures which share some runtime state.\n\nSome examples of components:\n\n* Database access: query and insert functions sharing a database\n  connection\n\n* External API service: functions to send and retrieve data sharing an\n  HTTP connection pool\n\n* Web server: functions to handle different routes sharing all the\n  runtime state of the web application, such as a session store\n\n* In-memory cache: functions to get and set data in a shared mutable\n  reference such as a Clojure Atom or Ref\n\nA *component* is similar in spirit to the definition of an *object* in\nObject-Oriented Programming. This does not alter the primacy of pure\nfunctions and immutable data structures in Clojure as a language. Most\nfunctions are just functions, and most data are just data. Components\nare intended to help manage stateful resources within a functional\nparadigm.\n\n\n### Advantages of the Component Model\n\nLarge applications often consist of many stateful processes which must\nbe started and stopped in a particular order. The component model\nmakes those relationships explicit and declarative, instead of\nimplicit in imperative code.\n\nComponents provide some basic guidance for structuring a Clojure\napplication, with boundaries between different parts of a system.\nComponents offer some encapsulation, in the sense of grouping together\nrelated entities. Each component receives references only to the\nthings it needs, avoiding unnecessary shared state. Instead of\nreaching through multiple levels of nested maps, a component can have\neverything it needs at most one map lookup away.\n\nInstead of having mutable state (atoms, refs, etc.) scattered\nthroughout different namespaces, all the stateful parts of an\napplication can be gathered together. In some cases, using components\nmay eliminate the need for mutable references altogether, for example\nto store the \"current\" connection to a resource such as a database. At\nthe same time, having all state reachable via a single \"system\" object\nmakes it easy to reach in and inspect any part of the application from\nthe REPL.\n\nThe component dependency model makes it easy to swap in \"stub\" or\n\"mock\" implementations of a component for testing purposes, without\nrelying on time-dependent constructs, such as `with-redefs` or\n`binding`, which are often subject to race conditions in\nmulti-threaded code.\n\nHaving a coherent way to set up and tear down **all** the state\nassociated with an application enables rapid development cycles\nwithout restarting the JVM. It can also make unit tests faster and\nmore independent, since the cost of creating and starting a system is\nlow enough that every test can create a new instance of the system.\n\n\n### Disadvantages of the Component Model\n\nFirst and foremost, this framework works best when all parts of an\napplication follow the same pattern. It is not easy to retrofit the\ncomponent model to an existing application without major refactoring.\n\nIn particular, the 'component' library assumes that all application\nstate is passed as arguments to the functions that use it. As a\nresult, this framework may be awkward to use with code which relies on\nglobal or singleton references.\n\nFor small applications, declaring the dependency relationships among\ncomponents may actually be more work than manually starting all the\ncomponents in the correct order. You can still use the 'Lifecycle'\nprotocol without using the dependency-injection features, but the\nadded value of 'component' in that case is small.\n\nThe \"system object\" produced by this framework is a large and complex\nmap with a lot of duplication. The same component may appear in\nmultiple places in the map. The actual memory cost of this duplication\nis negligible due to persistent data structures, but the system map is\ntypically too large to inspect visually.\n\nYou must explicitly specify all the dependency relationships among\ncomponents: the code cannot discover these relationships\nautomatically.\n\nFinally, the 'component' library forbids cyclic dependencies among\ncomponents. I believe that cyclic dependencies usually indicate\narchitectural flaws and can be eliminated by restructuring the\napplication. In the rare case where a cyclic dependency cannot be\navoided, you can use mutable references to manage it, but this is\noutside the scope of 'component'.\n\n\n\n\n## Usage\n\n```clojure\n(ns com.example.your-application\n  (:require [com.stuartsierra.component :as component]))\n```\n\n\n### Creating Components\n\nTo create a component, define a Clojure record that implements the\n`Lifecycle` protocol.\n\n```clojure\n(defrecord Database [host port connection]\n  ;; Implement the Lifecycle protocol\n  component/Lifecycle\n\n  (start [component]\n    (println \";; Starting database\")\n    ;; In the 'start' method, initialize this component\n    ;; and start it running. For example, connect to a\n    ;; database, create thread pools, or initialize shared\n    ;; state.\n    (let [conn (connect-to-database host port)]\n      ;; Return an updated version of the component with\n      ;; the run-time state assoc'd in.\n      (assoc component :connection conn)))\n\n  (stop [component]\n    (println \";; Stopping database\")\n    ;; In the 'stop' method, shut down the running\n    ;; component and release any external resources it has\n    ;; acquired.\n    (.close connection)\n    ;; Return the component, optionally modified. Remember that if you\n    ;; dissoc one of a record's base fields, you get a plain map.\n    (assoc component :connection nil)))\n```\n\nOptionally, provide a constructor function that takes arguments for\nthe essential configuration parameters of the component, leaving the\nruntime state blank.\n\n```clojure\n(defn new-database [host port]\n  (map-\u003eDatabase {:host host :port port}))\n```\n\nDefine the functions implementing the behavior of the component to\ntake an **instance** of the component as an argument.\n\n```clojure\n(defn get-user [database username]\n  (execute-query (:connection database)\n    \"SELECT * FROM users WHERE username = ?\"\n    username))\n\n(defn add-user [database username favorite-color]\n  (execute-insert (:connection database)\n    \"INSERT INTO users (username, favorite_color)\"\n    username favorite-color))\n```\n\nDefine other components in terms of the components on which they\ndepend.\n\n```clojure\n(defrecord ExampleComponent [options cache database scheduler]\n  component/Lifecycle\n\n  (start [this]\n    (println \";; Starting ExampleComponent\")\n    ;; In the 'start' method, a component may assume that its\n    ;; dependencies are available and have already been started.\n    (assoc this :admin (get-user database \"admin\")))\n\n  (stop [this]\n    (println \";; Stopping ExampleComponent\")\n    ;; Likewise, in the 'stop' method, a component may assume that its\n    ;; dependencies will not be stopped until AFTER it is stopped.\n    this))\n```\n\n**Do not pass component dependencies in a constructor.**\nSystems are responsible for injecting runtime dependencies into the\ncomponents they contain: see the next section.\n\n```clojure\n(defn example-component [config-options]\n  (map-\u003eExampleComponent {:options config-options\n                          :cache (atom {})}))\n```\n\n\n### Systems\n\nComponents are composed into systems. A system is a component which\nknows how to start and stop other components. It is also responsible\nfor injecting dependencies into the components which need them.\n\nThe easiest way to create a system is with the `system-map` function,\nwhich takes a series of key/value pairs just like the `hash-map` or\n`array-map` constructors. Keys in the system map are keywords. Values\nin the system map are *instances* of components, usually records or\nmaps.\n\n```clojure\n(defn example-system [config-options]\n  (let [{:keys [host port]} config-options]\n    (component/system-map\n      :db (new-database host port)\n      :scheduler (new-scheduler)\n      :app (component/using\n             (example-component config-options)\n             {:database  :db\n              :scheduler :scheduler}))))\n```\n\nSpecify the dependency relationships among components with the `using`\nfunction. `using` takes a component and a collection of keys naming\nthat component's dependencies.\n\nIf the component and the system use the same keys, then you can\nspecify dependencies as a *vector* of keys:\n\n```clojure\n    (component/system-map\n      :database (new-database host port)\n      :scheduler (new-scheduler)\n      :app (component/using\n             (example-component config-options)\n             [:database :scheduler]))\n             ;; Both ExampleComponent and the system have\n             ;; keys :database and :scheduler\n```\n\nIf the component and the system use *different* keys, then specify\nthem as a map of `{:component-key :system-key}`.\nThat is, the `using` keys match the keys in the component,\nthe values match keys in the system.\n\n```clojure\n    (component/system-map\n      :db (new-database host port)\n      :sched (new-scheduler)\n      :app (component/using\n             (example-component config-options)\n             {:database  :db\n              :scheduler :sched}))\n        ;;     ^          ^\n        ;;     |          |\n        ;;     |          \\- Keys in the system map\n        ;;     |\n        ;;     \\- Keys in the ExampleComponent record\n```\n\nThe system map provides its own implementation of the Lifecycle\nprotocol which uses this dependency information (stored as metadata on\neach component) to start the components in the correct order.\n\nBefore starting each component, the system will `assoc` its\ndependencies based on the metadata provided by `using`.\n\nAgain using the example above, the ExampleComponent would be started\n*as if* you did this:\n\n```clojure\n(-\u003e example-component\n    (assoc :database (:db system))\n    (assoc :scheduler (:sched system))\n    (start))\n```\n\nStop a system by calling the `stop` method on it. This will stop each\ncomponent, in *reverse* dependency order, and then re-assoc the\ndependencies of each component. **Note:** `stop` is not the exact\ninverse of `start`; component dependencies will still be associated.\n\nIt doesn't matter *when* you associate dependency metadata on a\ncomponent, as long as it happens before you call `start`. If you know\nthe names of all the components in your system in advance, you could\nchoose to add the metadata in the component's constructor:\n\n```clojure\n(defrecord AnotherComponent [component-a component-b])\n\n(defrecord AnotherSystem [component-a component-b component-c])\n\n(defn another-component []   ; constructor\n  (component/using\n    (map-\u003eAnotherComponent {})\n    [:component-a :component-b]))\n```\n\nAlternately, component dependencies can be specified all at once for\nall components in the system with `system-using`, which takes a map\nfrom component names to their dependencies.\n\n```clojure\n(defn example-system [config-options]\n  (let [{:keys [host port]} config-options]\n    (-\u003e (component/system-map\n          :config-options config-options\n          :db (new-database host port)\n          :sched (new-scheduler)\n          :app (example-component config-options))\n        (component/system-using\n          {:app {:database  :db\n                 :scheduler :sched}}))))\n```\n\n\n### Entry Points in Production\n\nThe 'component' library does not dictate how you store the system map\nor use the components it contains. That's up to you.\n\nThe typical approach differs in development and production:\n\nIn **production**, the system map is ephemeral. It is used to start\nall the components running, then it is discarded.\n\nWhen your application starts, for example in a `main` function,\nconstruct an instance of the system and call `component/start` on it.\nThen hand off control to one or more components that represent the\n\"entry points\" of your application.\n\nFor example, you might have a web server component that starts\nlistening for HTTP requests, or an event loop component that waits for\ninput. Each of these components can create one or more threads in its\nLifecycle `start` method. Then `main` could be as trivial as:\n\n```clojure\n(defn main [] (component/start (new-system)))\n```\n\n**Note:** You will still need to keep the main thread of your\napplication running to prevent the JVM from shutting down. One way is\nto block the main thread waiting for some signal to shut down; another\nway is to `Thread/join` the main thread to one of your components'\nthreads.\n\nThis also works well in conjunction with command-line drivers such as\n[Apache Commons Daemon](http://commons.apache.org/proper/commons-daemon/).\n\n\n### Entry Points for Development\n\nIn **development**, it is useful to have a reference to the system map\nto examine it from the REPL.\n\nThe easiest way to do this is to `def` a Var to hold the system map in\na development namespace. Use `alter-var-root` to start and stop it.\n\nExample REPL session:\n\n```clojure\n(def system (example-system {:host \"dbhost.com\" :port 123}))\n;;=\u003e #'examples/system\n\n(alter-var-root #'system component/start)\n;; Starting database\n;; Opening database connection\n;; Starting scheduler\n;; Starting ExampleComponent\n;; execute-query\n;;=\u003e #examples.ExampleSystem{ ... }\n\n(alter-var-root #'system component/stop)\n;; Stopping ExampleComponent\n;; Stopping scheduler\n;; Stopping database\n;; Closing database connection\n;;=\u003e #examples.ExampleSystem{ ... }\n```\n\nSee the [reloaded] template for a more elaborate example.\n\n[reloaded]: https://github.com/stuartsierra/reloaded\n\n\n### Web Applications\n\nMany Clojure web frameworks and tutorials are designed around an\nassumption that a \"handler\" function exists as a global `defn`,\nwithout any context. With this assumption, there is no easy way to use\nany application-level context in the handler without making it also a\nglobal `def`.\n\nThe 'component' approach assumes that any \"handler\" function receives\nits state/context as an argument, without depending on any global state.\n\nTo reconcile these two approaches, create the \"handler\" function as a\n*closure* over one or more components in a Lifecycle `start` method.\nPass this closure to the web framework as the \"handler\".\n\nMost web frameworks or libraries that have a static `defroutes` or\nsimilar macro will provide an equivalent non-static `routes` which can\nbe used to create a closure.\n\nIt might look something like this:\n\n```clojure\n(defn app-routes\n  \"Returns the web handler function as a closure over the\n  application component.\"\n  [app-component]\n  ;; Instead of static 'defroutes':\n  (web-framework/routes\n   (GET \"/\" request (home-page app-component request))\n   (POST \"/foo\" request (foo-page app-component request))\n   (not-found \"Not Found\")))\n\n(defrecord WebServer [http-server app-component]\n  component/Lifecycle\n  (start [this]\n    (assoc this :http-server\n           (web-framework/start-http-server\n             (app-routes app-component))))\n  (stop [this]\n    (stop-http-server http-server)\n    this))\n\n(defn web-server\n  \"Returns a new instance of the web server component which\n  creates its handler dynamically.\"\n  []\n  (component/using (map-\u003eWebServer {})\n                   [:app-component]))\n```\n\n\n## More Advanced Usage\n\n### Errors\n\nWhile starting/stopping a system, if any component's `start` or `stop`\nmethod throws an exception, the `start-system` or `stop-system`\nfunction will catch and wrap it in an `ex-info` exception with the\nfollowing keys in its `ex-data` map:\n\n* `:system` is the current system, including all the components which\n  have already been started.\n\n* `:component` is the component which caused the exception, with its\n  dependencies already `assoc`'d in.\n\nThe original exception which the component threw is available as\n`.getCause` on the exception.\n\nThe 'Component' library makes no attempt to recover from errors in a\ncomponent, but you can use the `:system` attached to the exception to\nclean up any partially-constructed state.\n\nSince component maps may be large, with a lot of repetition, you\nprobably don't want to log or print this exception as-is. The\n`ex-without-components` helper function will remove the larger objects\nfrom an exception.\n\nThe `ex-component?` helper function tells you if an exception was\noriginated or wrapped by 'Component'.\n\n\n### Idempotence\n\nYou may find it useful to define your `start` and `stop` methods to be\nidempotent, i.e., to have effect only if the component is not already\nstarted or stopped.\n\n```clojure\n(defrecord IdempotentDatabaseExample [host port connection]\n  component/Lifecycle\n  (start [this]\n    (if connection  ; already started\n      this\n      (assoc this :connection (connect host port))))\n  (stop [this]\n    (if (not connection)  ; already stopped\n      this\n      (do (.close connection)\n          (assoc this :connection nil)))))\n```\n\nThe 'Component' library does not require that stop/start be\nidempotent, but idempotence can make it easier to clean up state after\nan error, because you can call `stop` indiscriminately on everything.\n\nIn addition, you could wrap the body of `stop` in a try/catch that\nignores all exceptions. That way, errors stopping one component will\nnot prevent other components from shutting down cleanly.\n\n```clojure\n(try (.close connection)\n  (catch Throwable t\n    (log/warn t \"Error when stopping component\")))\n```\n\n\n### Stateless Components\n\nThe default implementation of `Lifecycle` is a no-op. If you omit the\n`Lifecycle` protocol from a component, it can still participate in the\ndependency injection process.\n\nComponents which do not need a lifecycle can be ordinary Clojure maps.\n\nYou **cannot** omit just one of the `start` or `stop` methods: any\ncomponent which implements `Lifecycle` must supply both.\n\n\n### Reloading\n\nI developed this pattern in combination with my \"reloaded\" [workflow].\nFor development, I might create a `user` namespace like this:\n\n[workflow]: http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded\n\n```clojure\n(ns user\n  (:require [com.stuartsierra.component :as component]\n            [clojure.tools.namespace.repl :refer (refresh)]\n            [examples :as app]))\n\n(def system nil)\n\n(defn init []\n  (alter-var-root #'system\n    (constantly (app/example-system {:host \"dbhost.com\" :port 123}))))\n\n(defn start []\n  (alter-var-root #'system component/start))\n\n(defn stop []\n  (alter-var-root #'system\n    (fn [s] (when s (component/stop s)))))\n\n(defn go []\n  (init)\n  (start))\n\n(defn reset []\n  (stop)\n  (refresh :after 'user/go))\n```\n\n\n### Subsystems\n\nWhat if you want to start just some of the components in your system?\n\nSystems are not designed to be in a \"partially started\" state, and the\nconsequences are confusing.\n\nInstead, create a new system containing just the components you\nneed. The `subsystem` function (added in 1.1.0) acts like Clojure's\n`select-keys` function, but for systems, and it automatically includes\nall transitive dependencies.\n\nNote: Although the `start-system` function takes an argument naming\nthe components to be started, this is more of an implementation\ndetail. It does **not** take dependencies into account.  Use\n`subsystem` and `start` instead.\n\n\n## Usage Notes\n\n\n### Do not pass the system around\n\nThe top-level \"system\" record is used only for starting and stopping\nother components, and for convenience during interactive development.\n\nSee \"Entry Points in ...\" above.\n\n\n### No function should take the entire system as an argument\n\nApplication functions should never receive the whole system as an\nargument. This is unnecessary sharing of global state.\n\nRather, each function should be defined in terms of **at most one**\ncomponent.\n\nIf a function depends on several components, then it should have its\nown component with dependencies on the things it needs.\n\n\n### No component should be aware of the system which contains it\n\nEach component receives references only to the components on which it\ndepends.\n\n\n### Do not nest systems\n\nIt's technically possible to nest one `system-map` in another, but the\neffects on dependencies are subtle and confusing.\n\nInstead, give all your components unique keys and merge them into one\nsystem.\n\n\n### Other kinds of components\n\nThe \"application\" or \"business logic\" may itself be represented by one\nor more components.\n\nComponent records may, of course, implement other protocols besides\n`Lifecycle`.\n\nAny type of object, not just maps and records, can be a component if\nit has no lifecycle and no dependencies. For example, you could put a\nbare Atom or core.async Channel in the system map where other\ncomponents can depend on it.\n\n\n### Test doubles\n\nDifferent implementations of a component (for example, a stub version\nfor testing) can be injected into a system with `assoc` before calling\n`start`.\n\n\n### Notes for Library Authors\n\n'Component' is intended as a tool for applications, not reusable\nlibraries. I would not expect a general-purpose library to impose any\nparticular framework on the applications which use it.\n\nThat said, library authors can make it trivially easy for applications\nto use their libraries in combination with the 'Component' pattern by\nfollowing these guidelines:\n\n* Never create global mutable state (for example, an Atom or Ref\n  stored in a `def`).\n\n* Never rely on dynamic binding to convey state (for example, the\n  \"current\" database connection) unless that state is necessarily\n  confined to a single thread.\n\n* Never perform side effects at the top level of a source file.\n\n* Encapsulate all the runtime state needed by the library in a single\n  data structure.\n\n* Provide functions to construct and destroy that data structure.\n\n* Take the encapsulated runtime state as an argument to any library\n  functions which depend on it.\n\n\n### Customization\n\nA system map is just a record that implements the Lifecycle protocol\nvia two public functions, `start-system` and `stop-system`. These two\nfunctions are just special cases of two other functions,\n`update-system` and `update-system-reverse`. (Added in 0.2.0)\n\nYou could, for example, define your own lifecycle functions as new\nprotocols. You don't even have to use protocols and records;\nmultimethods and ordinary maps would work as well.\n\nBoth `update-system` and `update-system-reverse` take a function as\nan argument and call it on each component in the system. Along the\nway, they `assoc` in the updated dependencies of each component.\n\nThe `update-system` function iterates over the components in\ndependency order: a component will be called *after* its dependencies.\nThe `update-system-reverse` function goes in reverse dependency order:\na component will be called *before* its dependencies.\n\nCalling `update-system` with the `identity` function is equivalent to\ndoing just the dependency injection part of 'Component' without\n`Lifecycle`.\n\n\n\n## References / More Information\n\n* [video from Clojure/West 2014](https://www.youtube.com/watch?v=13cmHf_kt-Q) (YouTube, 40 minutes)\n* [tools.namespace](https://github.com/clojure/tools.namespace)\n* [On the Perils of Dynamic Scope](http://stuartsierra.com/2013/03/29/perils-of-dynamic-scope)\n* [Clojure in the Large](http://www.infoq.com/presentations/Clojure-Large-scale-patterns-techniques) (video)\n* [Relevance Podcast Episode 32](http://thinkrelevance.com/blog/2013/05/29/stuart-sierra-episode-032) (audio)\n* [My Clojure Workflow, Reloaded](http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded)\n* [reloaded](https://github.com/stuartsierra/reloaded) Leiningen template\n* [Lifecycle Composition](http://stuartsierra.com/2013/09/15/lifecycle-composition)\n\n\n\n## Copyright and License\n\nThe MIT License (MIT)\n\nCopyright © 2015 Stuart Sierra\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstuartsierra%2Fcomponent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstuartsierra%2Fcomponent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstuartsierra%2Fcomponent/lists"}