745dab2c0a5c64d1de5eb42458ba4b540c35618a
Home.md
... | ... | @@ -59,3 +59,4 @@ try to separate three different aspects. |
59 | 59 | - Ecosystem: [[DevEnvironmentLauncherEcosystem]] |
60 | 60 | - Gaiwan Stack: [[GaiwanStack/Launchpad]] |
61 | 61 | - [[WellKnownIdentifier]] - Predictable commonly used identifiers to access resources |
62 | +- [[ReloadableComponentSystem]] - Declarative system of components with start/stop/restart and code reloading |
ReloadableComponentSystem.md
... | ... | @@ -0,0 +1,83 @@ |
1 | +# Reloadable Component System |
|
2 | + |
|
3 | +## Introduction |
|
4 | + |
|
5 | +A system consists of components working together. These components need to be |
|
6 | +initialized (started) and wired together, and when the system is torn down the |
|
7 | +individual components need to be torn down (stopped). The order in which they |
|
8 | +are started and stopped depends on the dependencies between the components. |
|
9 | + |
|
10 | +Components are often stateful, leading to specific concerns when doing |
|
11 | +[[Interactive Programming]] against a live process. One needs to resolve issues |
|
12 | +arising from stale state, and allow for dynamic reconfiguration and reloading |
|
13 | +when in the course of development the system structure or configuration changes. |
|
14 | + |
|
15 | +## Pattern Description |
|
16 | + |
|
17 | +In a **Reloadable Component Systems** there are **Components**, which have |
|
18 | +`start` and `stop` routines. The start routine accepts configuration and |
|
19 | +dependent components, the `stop` routine accepts the previously started |
|
20 | +component. These components are assembled and provided configuration values in a |
|
21 | +**System Description**. |
|
22 | + |
|
23 | +The System can then be started as a whole, which will start all components in |
|
24 | +topological order, and stopped again, which does a clean shutdown in reverse |
|
25 | +topological order. |
|
26 | + |
|
27 | +A **refresh** or **reset** consists of doing a full code unload/reload in |
|
28 | +between stopping the system and restarting it, with the system now freshly |
|
29 | +booting from the newly loaded code. |
|
30 | + |
|
31 | +## Relationship to Dependency Injection |
|
32 | + |
|
33 | +While Component Systems in Clojure share similarities with, and can be said to |
|
34 | +be a type of, dependency injection, they serves a more specialized purpose and |
|
35 | +boast a unique history within the Clojure ecosystem. |
|
36 | + |
|
37 | +Much of this has to do with the dynamic nature of Clojure, and the cultural |
|
38 | +preference and excellent affordances for [[Interactive Programming]] (i.e. using |
|
39 | +a REPL). This means a system doesn't just need to be able to start up once, it |
|
40 | +also needs to be torn down cleanly, restart, receive new configuration while |
|
41 | +it's running, and start or stop incrementally (intentionally or because of |
|
42 | +failures of certain components to start). Different solutions in the Clojure |
|
43 | +space have differing degrees of support for these dynamic use cases. |
|
44 | + |
|
45 | +Frameworks like Java Spring use XML configuration to declare system and |
|
46 | +component structure and dependencies, by providing class names and construction |
|
47 | +hints. This is a highly static approach, which doesn't provide support for full |
|
48 | +lifecycle management, code reloading, or facilitate dynamic reconfiguration. |
|
49 | + |
|
50 | +## Alessandra Sierra's Component library and Reloaded Workflow Article |
|
51 | + |
|
52 | +This pattern and its particular purpose in the context of Clojure was first |
|
53 | +described by Alessandra Sierra's, who provided an initial implementation in the |
|
54 | +[Component](https://github.com/stuartsierra/component) library, and published |
|
55 | +the accompanying [Clojure Workflow Reloaded](https://cognitect.com/blog/2013/06/04/clojure-workflow-reloaded) |
|
56 | +article. |
|
57 | + |
|
58 | +It highlighted the main purpose of a Reloadable Component System: eliminating |
|
59 | +stale REPL state. |
|
60 | + |
|
61 | +> ... some aspects of Clojure's runtime are not quite as late-binding as one might |
|
62 | +> wish for interactive development. For example, the effect of a changed macro |
|
63 | +> definition will not be seen until code which uses the macro has been |
|
64 | +> recompiled. Changes to methods of a defrecord or deftype will not have any |
|
65 | +> effect on existing instances of that type. |
|
66 | + |
|
67 | +Part of the solution is found in |
|
68 | +[tools.namespace](https://github.com/clojure/tools.namespace), which allows |
|
69 | +reloading a set of namespaces in dependency order. However as Sierra points out |
|
70 | +`tools.namespace` alone is not enough. It is also imperative that the version of |
|
71 | +the application that's running, and any in-memory state it holds, matches with |
|
72 | +version of the application that is encoded in the source files. |
|
73 | + |
|
74 | +So the proposed approach is to combine tools.namespace with a "component" |
|
75 | +(system lifecycle) library. It shuts down the system, removing any stale state, |
|
76 | +then reloads all code, and then uses the newly loaded code to construct a new |
|
77 | +system state. |
|
78 | + |
|
79 | +## History |
|
80 | + |
|
81 | +### 2024-06-10 |
|
82 | + |
|
83 | +- First public version (Ariel Alexis, editing by Arne Brasseur) |
SystemLifecycleManagement.md
... | ... | @@ -1,80 +0,0 @@ |
1 | -# Managed Component System |
|
2 | - |
|
3 | -## Introduction |
|
4 | - |
|
5 | -A system consists of components working together. These components need to be |
|
6 | -initialized (started) and wired together, and when the system is torn down the |
|
7 | -individual components need to be torn down (stopped). The order in which they |
|
8 | -are started and stopped depends on the dependencies between the components. |
|
9 | - |
|
10 | -Components are often stateful, leading to specific concerns when doing |
|
11 | -[[Interactive Programming]] against a live process. One needs to resolve issues |
|
12 | -arising from stale state, and allow for dynamic reconfiguration and reloading |
|
13 | -when in the course of development the system structure or configuration changes. |
|
14 | - |
|
15 | -## Pattern Description |
|
16 | - |
|
17 | -In **System Lifecycle Management** there are **Components**, which have `start` |
|
18 | -and `stop` routines. The start routine accepts configuration and dependent |
|
19 | -components, the `stop` routine accepts the previously started component. These |
|
20 | -components are assembled and provided configuration values in a **System |
|
21 | -Description**. |
|
22 | - |
|
23 | -The **System Description** can then be started as a whole, which will start all |
|
24 | -components in topological order. |
|
25 | - |
|
26 | -Various extensions and variations exist, but these are the key ingredients. |
|
27 | - |
|
28 | -## Relationship to Dependency Injection |
|
29 | - |
|
30 | -While system lifecycle management in Clojure shares similarities with, and can |
|
31 | -be said to be a type of, dependency injection, it serves a more specialized |
|
32 | -purpose and boasts a unique history within the Clojure ecosystem. |
|
33 | - |
|
34 | -Much of this has to do with the dynamic nature of Clojure, and the cultural |
|
35 | -preference and excellent affordances for [[Interactive Programming]] (i.e. using |
|
36 | -a REPL). This means a system doesn't just need to be able to start up once, it |
|
37 | -also needs to be torn down cleanly, restart, receive new configuration while |
|
38 | -it's running, and start or stop incrementally (intentionally or because of |
|
39 | -failures of certain components to start). Different solutions in the Clojure |
|
40 | -space have differing degrees of support for these dynamic use cases. |
|
41 | - |
|
42 | -Frameworks like Java Spring use XML configuration to declare system and |
|
43 | -component structure and dependencies, by providing class names and construction |
|
44 | -hints. This is a highly static approach, which doesn't provide support for full |
|
45 | -lifecycle management, or facilitate dynamic reconfiguration. |
|
46 | - |
|
47 | -## Alessandra Sierra's Component library and Reloaded Workflow Article |
|
48 | - |
|
49 | -The cultural notion in the Clojure ecosystem of a "component" library and its |
|
50 | -purpose originated with Alessandra Sierra's |
|
51 | -[Component](https://github.com/stuartsierra/component) library, and the |
|
52 | -accompanying [Clojure Workflow Reloaded](https://cognitect.com/blog/2013/06/04/clojure-workflow-reloaded) |
|
53 | -article. |
|
54 | - |
|
55 | -It highlighted the main purpose of system lifecycle management: eliminating |
|
56 | -stale REPL state. |
|
57 | - |
|
58 | -> ... some aspects of Clojure's runtime are not quite as late-binding as one might |
|
59 | -> wish for interactive development. For example, the effect of a changed macro |
|
60 | -> definition will not be seen until code which uses the macro has been |
|
61 | -> recompiled. Changes to methods of a defrecord or deftype will not have any |
|
62 | -> effect on existing instances of that type. |
|
63 | - |
|
64 | -Part of the solution is found in |
|
65 | -[tools.namespace](https://github.com/clojure/tools.namespace), which allows |
|
66 | -reloading a set of namespaces in dependency order. However as Sierra points out |
|
67 | -tools.namespace alone is not enough. It is also imperative that the version of |
|
68 | -the application that's running, and any in-memory state it holds, matches with |
|
69 | -version of the application that is encoded in the source files. |
|
70 | - |
|
71 | -So the proposed approach is to combine tools.namespace with a "component" |
|
72 | -(system lifecycle) library. It shuts down the system, removing any stale state, |
|
73 | -then reloads all code, and then uses the newly loaded code to construct a new |
|
74 | -system state. |
|
75 | - |
|
76 | -## History |
|
77 | - |
|
78 | -### 2024-06-10 |
|
79 | - |
|
80 | -- First public version (Ariel Alexis, editing by Arne Brasseur) |