Skip to content

Commit 98313f7

Browse files
committed
. d Improve Loader and Saver description
1 parent 300e220 commit 98313f7

File tree

2 files changed

+45
-11
lines changed

2 files changed

+45
-11
lines changed

approvaltests-util/docs/reference/LoadersAndSavers.md

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
<!-- toc -->
66
## Contents
7-
8-
* [ExecutableCommand](#executablecommand)
97
* [Loaders](#loaders)<!-- endToc -->
108
## What it is
119

@@ -15,11 +13,7 @@ Loaders tend to work similarly in functionality to a stored procedure.
1513

1614
Savers allow you to save changes
1715

18-
### ExecutableCommand
19-
20-
`ExecutableCommand`s extend Loaders to allow for easy testing.
21-
22-
## Loaders
16+
## Interfaces
2317

2418
The Loader interface looks like:
2519
<!-- snippet: loader_interface -->
@@ -30,15 +24,53 @@ public T load();
3024
<sup><a href='/approvaltests-util/src/main/java/com/spun/util/persistence/Loader.java#L5-L7' title='Snippet source file'>snippet source</a> | <a href='#snippet-loader_interface' title='Start of snippet'>anchor</a></sup>
3125
<!-- endSnippet -->
3226

33-
The purpose for this is to allow you to split your method into two methods:
27+
And the Saver interface looks like:
28+
snippet: saver_interface
3429

35-
1. Small method that gathers the loaders and calls the business logic
36-
1. Larger method that contains your business logic and calls the loaders
30+
## Loaders
31+
A `Loader` tends to wrap data access layers to a: database, file system, or Web service.
32+
By wrapping the data retrieval in a `Loader` interface it becomes easy to swap it out for testing and other polymorphism.
33+
This also helps to separate your business logic from the implementation of your service layer.
34+
35+
## Savers
3736

38-
For example:
37+
The `Saver` also tends to wrap data access layers to a: database, file system, or Web service.
38+
This is the "write" as opposed to the `Loader`'s "read".
3939

40+
The `Saver` returns the saved object.
41+
This is needed because some savers do not mutate the object, but actually create a new instance.
42+
Often saving mutates or does not alter the saved object at all.
43+
In these instances the `Saver` simply returns what is passed in.
44+
45+
## Common Usage Patterns
46+
Most current code hides the data access methods. For example:
47+
```java
48+
public JSON loadCustomer(QueryParameter p) {
49+
// ... lots of logic
50+
}
51+
```
52+
Using the `Loader`s and `Saver`s you can convert this to two methods, the second of which is very easy to test and extend.
53+
```java
54+
public JSON loadCustomer(QueryParameter p) {
55+
return loadCustomer(new CustomerQuery(p), new CustomerSaver());
56+
}
57+
public JSON loadCustomer(Loader<Customer> customerLoader, Saver<Customer> customerSaver) {
58+
// ... lots of logic
59+
}
60+
```
61+
62+
By adding this small seam the main business logic is much easier to test as it is isolated away from the database and service layer.
63+
64+
## Testing
65+
The simplest way to mock a `Loader` or `Saver` is with a lambda.
66+
For example, if we wanted to test what happens when the query does not find a customer, we could do the following call:
67+
```java
68+
loadCustomer(c -> null, s -> s);
69+
```
4070

71+
## ExecutableCommand
4172

73+
`ExecutableCommand`s extend `Loader`s to allow for easy testing of the actual `Loader`.
4274

4375
---
4476

approvaltests-util/src/main/java/com/spun/util/persistence/Saver.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@
22

33
public interface Saver<T>
44
{
5+
// begin-snippet: saver_interface
56
public T save(T save);
7+
// end-snippet
68
}

0 commit comments

Comments
 (0)