|
| 1 | +## Day 21: Refactor the tests and production code to Output-based tests. |
| 2 | + |
| 3 | +### Refactor to Output-Based |
| 4 | +- Instead of hiding side effects behind an interface and injecting that interface into `AuditManager`, we can move those side effects out of the class entirely : |
| 5 | + - `AuditManager`: responsible for making a decision about what to do with the files |
| 6 | + - A new class, `Persister` acts on that decision and applies updates to the filesystem |
| 7 | + |
| 8 | +#### AuditManager |
| 9 | +In terms of contract we would like something like this: |
| 10 | +- `FileUpdate addRecord(FileContent[] files, String visitorName, LocalDateTime timeOfVisit)` |
| 11 | +- We choose to write the code `from scratch` aside from existing code |
| 12 | + - When we do it on legacy code, it's called [`Sprout Class`](https://understandlegacycode.com/blog/key-points-of-working-effectively-with-legacy-code/#1-the-sprout-technique) |
| 13 | + |
| 14 | +🔴 Let's express this expectation from a test |
| 15 | + |
| 16 | +- Of course, we do not compile here... |
| 17 | + - We have just prototyped a first version of what we might want (it can evolve while writing the code) |
| 18 | +- We generate the classes from our test |
| 19 | +- Here is the generated skeleton |
| 20 | + |
| 21 | +🔴 The test is still red but for a good reason: because of the assertion (no compilation error anymore) |
| 22 | + |
| 23 | +🟢 Make it pass as fast as possible |
| 24 | + |
| 25 | +- We hard code the value for now |
| 26 | + - We can check that our flow is correct |
| 27 | + |
| 28 | +🔵 Let's refactor it |
| 29 | + |
| 30 | +- Based on the existing logic we would like to design something that looks like this: |
| 31 | + - sortFiles -> formatDate -> createRecord -> createFileUpdate (based on maxEntriesPerFile) |
| 32 | +- We will iterate on the code |
| 33 | +- Our test is still green, so let's move on |
| 34 | +- We improved the algorithm |
| 35 | +- Other tests are missing to `triangulate` the rest of the implementation |
| 36 | + - Let's add them incrementally |
| 37 | + |
| 38 | +> It is the same logic here for this test case |
| 39 | +
|
| 40 | +- We refactor the tests before adding a new test case |
| 41 | + |
| 42 | +🔴 Let's add a test that writes in the `Current Audit File` |
| 43 | + |
| 44 | +- Of course, we need to triangulate our algorithm with this test |
| 45 | + |
| 46 | +🟢 Iterate on the `addRecord` method |
| 47 | + |
| 48 | +🔴 By incrementing on the code, we have broken a test `addsNewVisitorToANewFileBecauseNoFileToday` |
| 49 | + |
| 50 | +- We fix it as fast as possible to go back in a safe state |
| 51 | + |
| 52 | +🔵 It's time to play 🥳 |
| 53 | + |
| 54 | +- We extract some methods and rename some variables |
| 55 | +- We can definitely improve the `createNewFileOrUpdate` method |
| 56 | +- We have lost some features in the battle |
| 57 | + - Let's implement the `Persister` class |
| 58 | + |
| 59 | +#### Persister - Bonus |
| 60 | +The Persister is responsible for |
| 61 | +- accessing files from a given Directory |
| 62 | +- applying update instruction (a.k.a update the file content) |
| 63 | + |
| 64 | +#### AddRecordUseCase |
| 65 | +We need to have some glue to control the flow of our application. Let's create a `UseCase` for that. |
| 66 | + |
| 67 | +Our logic is now in a class of its own using the Persister as a dependency. |
| 68 | + |
| 69 | +>**Tip of the day: Isolate your business logic from dependencies outside your system.** |
| 70 | +
|
| 71 | +### Share your experience |
| 72 | + |
| 73 | +How does your code look like? |
| 74 | + |
| 75 | +Please let everyone know in the discord. |
0 commit comments