more work on architecture session of doc

This commit is contained in:
Gavin King 2023-06-21 17:37:34 +02:00
parent 8809e5720c
commit 88e07652c9
3 changed files with 32 additions and 9 deletions

View File

@ -514,7 +514,7 @@ interface Queries {
} }
---- ----
The Metamodel Generator checks that the parameters of this method match the parameters of the HQL or SQL query, that the query is syntactically legal, and generates a query method with a similar signature and return type in the corresponding static metamodel class `Queries_`. The Metamodel Generator checks that the parameters of this method match the parameters of the HQL or SQL query, and that the query is syntactically legal, and generates a query method with a similar signature and return type in the corresponding static metamodel class `Queries_`.
You can call the generated query method like this: You can call the generated query method like this:
[source,java] [source,java]
@ -566,6 +566,12 @@ If we also set up the {query-validator}[Query Validator], our HQL query will eve
Let's now consider a different approach to code organization, one we treat with suspicion. Let's now consider a different approach to code organization, one we treat with suspicion.
[WARNING]
====
In the section that follows, we're going to give you our _opinion_.
If you're only interested in facts, or if you prefer not to read things that might cut against the opinion you currently hold, please feel free to skip straight to the <<entities,next chapter>>.
====
[[archtecture]] [[archtecture]]
=== Architecture and the persistence layer === Architecture and the persistence layer
@ -576,7 +582,7 @@ In particular, frameworks which wrap JPA seem to add bloat while subtracting som
The stodgy, dogmatic, _conventional_ wisdom, which we hesitate to challenge for simple fear of pricking ourselves on the erect hackles that inevitably accompany such dogma-questioning is: The stodgy, dogmatic, _conventional_ wisdom, which we hesitate to challenge for simple fear of pricking ourselves on the erect hackles that inevitably accompany such dogma-questioning is:
> code which interacts with the database belongs in a separate _persistence layer_. > Code which interacts with the database belongs in a separate _persistence layer_.
We lack the courage—perhaps even the conviction—to tell you categorically to _not_ follow this recommendation. We lack the courage—perhaps even the conviction—to tell you categorically to _not_ follow this recommendation.
But we do ask you to consider the cost in boilerplate of any architectural layer, and whether the benefits this cost buys are really worth it in the context of your system. But we do ask you to consider the cost in boilerplate of any architectural layer, and whether the benefits this cost buys are really worth it in the context of your system.
@ -619,16 +625,18 @@ If these repository frameworks offered anything actually _useful_—and not obvi
Ultimately, we're not sure you need a separate persistence layer at all. Ultimately, we're not sure you need a separate persistence layer at all.
At least _consider_ the possibility that it might be OK to call the `EntityManager` directly from your business logic. At least _consider_ the possibility that it might be OK to call the `EntityManager` directly from your business logic.
_Sssssssss. Heresy!_ > Sssssssss. Heresy!
OK, look, if it makes you feel better, one way to view `EntityManager` is to think of it as a single _generic_ "repository" that works for every entity in your system. OK, look, if it makes you feel better, one way to view `EntityManager` is to think of it as a single _generic_ "repository" that works for every entity in your system.
From this point of view, JPA _is_ your persistence layer! From this point of view, JPA _is_ your persistence layer.
We might even analogize `EntityManager` to `List`. And there's few good reasons to wrap this abstraction in a second abstraction that's _less_ generic.
Then DAO-style repositories would be like having separate `StringList`, `IntList`, `PersonList`, and `BookList` classes.
They're a parallel class hierarchy that makes the data model harder to evolve over time.
image::images/architecture.png[API overview,pdfwidth="100%",width=1100,align="center"] image::images/architecture.png[API overview,pdfwidth="100%",width=1100,align="center"]
// We might even analogize `EntityManager` to `List`.
// Then DAO-style repositories would be like having separate `StringList`, `IntList`, `PersonList`, and `BookList` classes.
// They're a parallel class hierarchy that makes the data model harder to evolve over time.
// Of course, such decisions are highly context-dependent: surely _some_ programs out there really do benefit from isolating the persistence logic into some sort of distinct layer; on the other hand, we're equally sure that there are others which simply _don't_. // Of course, such decisions are highly context-dependent: surely _some_ programs out there really do benefit from isolating the persistence logic into some sort of distinct layer; on the other hand, we're equally sure that there are others which simply _don't_.
Even where a distinct persistence layer _is_ appropriate, DAO-style repositories aren't the obviously-most-correct way to factorize the equation: Even where a distinct persistence layer _is_ appropriate, DAO-style repositories aren't the obviously-most-correct way to factorize the equation:
@ -637,7 +645,15 @@ Even where a distinct persistence layer _is_ appropriate, DAO-style repositories
- most queries are extremely specific to a particular fragment of program logic, and aren't reused in different places across the system. - most queries are extremely specific to a particular fragment of program logic, and aren't reused in different places across the system.
Indeed, repositories, by nature, exhibit very low _cohesion_. Indeed, repositories, by nature, exhibit very low _cohesion_.
They're also extremely highly _coupled_ to their clients, with a very large API surface. A layer of repository objects might make sense if you have multiple implementations of each repository, but in practice almost nobody ever does.
That's because they're also extremely highly _coupled_ to their clients, with a very large API surface.
A layer is only easily replaceable if it has a narrow API.
[TIP]
====
Some people do indeed use mock repositories for testing, but we really struggle to see any value in this.
If you don't want to run your tests against your real database, it's usually very easy to "mock" the database by running tests against an in-memory Java database like H2.
====
// So even in cases where separation _is_ of benefit, we go on to question the notion that this must be achieved via a layer of container-managed objects. // So even in cases where separation _is_ of benefit, we go on to question the notion that this must be achieved via a layer of container-managed objects.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 277 KiB

View File

@ -102,4 +102,11 @@ table:
footer: footer:
border-width: 0 border-width: 0
quote: quote:
font-style: italic font-style: italic
font-color: #b22222
font-size: 1.1em
# background-color: #f1f1f1
border-color: #000000
border-radius: 2
border-style: dotted
padding: [10,20,10,25]