Skip to content

Commit eec6237

Browse files
committed
Readme: comparing manual state management with Integrant
1 parent e6f1395 commit eec6237

File tree

5 files changed

+43
-22
lines changed

5 files changed

+43
-22
lines changed

webstore-demo/integrant-simple-server/README.md

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,10 @@
55
- [Introduction](#introduction)
66
- [Technical Description](#technical-description)
77
- [Application State Management](#application-state-management)
8-
- [Configuration Handling](#configuration-handling)
9-
- [(REPL Driven) Clojure Development](#repl-driven-clojure-development)
10-
- [Using a REPL Scratch File](#using-a-repl-scratch-file)
11-
- [You Can Do It Without Application State Management Libraries](#you-can-do-it-without-application-state-management-libraries)
12-
- [Editing Clojure Code Efficiently](#editing-clojure-code-efficiently)
13-
- [Using IntelliJ IDEA + Cursive and Emacs + Cider Interchangeably](#using-intellij-idea--cursive-and-emacs--cider-interchangeably)
14-
- [Rich Comments](#rich-comments)
15-
- [Debugger](#debugger)
16-
- [Logging](#logging)
17-
- [Linting](#linting)
18-
- [DynamoDB Functionality](#dynamodb-functionality)
19-
- [Local DynamoDB Docker Emulator](#local-dynamodb-docker-emulator)
20-
- [Using Cognitect AWS Clojure Library](#using-cognitect-aws-clojure-library)
21-
- [IntelliJ IDEA / Cursive Run Configuration](#intellij-idea--cursive-run-configuration)
22-
- [Unit Testing](#unit-testing)
23-
- [Building Fat Jar and Running It](#building-fat-jar-and-running-it)
24-
- [Next Steps for Myself](#next-steps-for-myself)
25-
- [For a Clojure Learner](#for-a-clojure-learner)
8+
- [Manual State Management](#manual-state-management)
9+
- [State Management Using Integrant](#state-management-using-integrant)
10+
- [Comparison](#comparison)
11+
- [Personal Experiences](#personal-experiences)
2612

2713

2814
# Introduction
@@ -47,8 +33,44 @@ Simple Server is implemented using [Clojure](https://clojure.org/) and [Ring](ht
4733

4834
# Application State Management
4935

50-
So, in this third Simple Server version I wanted to compare the workflow using no particular state management library (see: [simple-server](../simple-server)) and this new Simple Server version with the [Integrant library](https://github.com/weavejester/integrant). You can read my experiences without using any state management library in that previous exercise, see [README.md](../simple-server/README.md) in chapter "You Can Do It Without Application State Management Libraries". In this new README file in this chapter I focus on my experiences using Integrant.
36+
So, in this third Simple Server version I wanted to compare the workflow using no particular state management library (see: [simple-server](../simple-server)) and this new Simple Server version with the [Integrant library](https://github.com/weavejester/integrant). You can read my experiences without using any state management library in that previous exercise, see [README.md](../simple-server/README.md) in chapter "You Can Do It Without Application State Management Libraries". In this new README file in this chapter I focus on my experiences using Integrant and comparing these two strategies.
5137

52-
TODO: Experiences.
38+
## Manual State Management
39+
40+
In the code below you can see how I did state management manually in the previous exercise:
41+
42+
![alt text](doc/manual_state.png)
43+
44+
So, the core of the state management in this manual solution is the server atom which is just a map with three keys (in defonce since if we reload the namespace in REPL we don't want to lose the atom and the web server instance). The ```:server ``` key holds the actual server instance, as you can see in ```start-web-server``` function. The ```stop-web-server``` function stops the server instance and resets the atom value. The ```reset-web-server``` function just call these two functions. And we have a custom state management implemented without any state management libraries. You can easily reset the web server in REPL using the reset-web server function.
45+
46+
The above mentioned manual state management solution is just fine at least with smaller implementations that have just 1-2 states (e.g. just the web server - whether it is listening connections or not). But if you need a more complex state management, possibly with dependencies between different parts of the state, then you might benefit using a dedicated state management library.
47+
48+
## State Management Using Integrant
49+
50+
Let's see how the same thing could be implemented using Integrant. The first part of the solution is pretty much the same, we need to have methods for starting and stopping the web server:
51+
52+
![alt text](doc/integrant_state.png)
53+
54+
But this time we don't need any atom to store the web server instance since we let Integrant to take care of state managent - therefore our ```start-web-server``` function starts the web server and just returns the created (and started) web server instance.
55+
56+
Then the Integrant specific part.
57+
58+
![alt text](doc/integrant_config.png)
59+
60+
We first create a system configuration (function ```system-config```). Basically the only thing here that we really need is the ```::web-server``` part which has the initialization values for our web server. Then we have integrant hooks ```ig/init-key``` and ```ig/halt-key!```. These methods are called by Integrant when we reset the Integrant managed state of our application. As you can see, we just call the previous functions ```start-web-server``` and ```stop-web-server```.
61+
62+
In REPL driven development you can then use three ```integrant.repl``` namespace functions:
63+
64+
- go: start the system (in our case start the web server)
65+
- halt: halt the system (in our case stop the web server)
66+
- reset: reset the system
67+
68+
## Comparison
69+
70+
So, which one is better? I'm not sure. For smaller applications it might be feasible just to implement your custom state management - and one less dependency in your ```deps.edn``` file. But if you have a bigger application with a lot of states and dependencies between different parts of the states then you might benefit using a dedicated state management library. I actually ran a very informal gallup in Metosin Slack regarding whether Metosin programmers favor custom state management or use some state management library. Two developers favored custom state management, others some 8 guys (which clicked either emoji in Slack) favored state management, all of them Integrant. Considering that these guys are pretty seasoned Clojure programmers I would say that you won't miss your target if you choose Integrant.
71+
72+
# Personal Experiences
73+
74+
TODO: TODO: Personal Experiences.
5375

5476

41.6 KB
Loading
29.1 KB
Loading
96.9 KB
Loading

webstore-demo/integrant-simple-server/src/clj/simpleserver/core.clj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@
2323

2424
(defn -main []
2525
(log/info "System starting...")
26-
;; TODO: For debugging kube deployment, remove later
2726
(log/info "Config: " (clojure.pprint/pprint (system-config)))
2827
(ig/init (system-config)))
2928

29+
;; Rich comment.
3030
(comment
3131
(system-config)
32-
3332
)

0 commit comments

Comments
 (0)