├── .github
└── workflows
│ └── gradle.yml
├── .gitignore
├── ACKNOWLEDGEMENTS.md
├── CODE_OF_CONDUCT.md
├── README.md
├── build.gradle
├── config
└── checkstyle
│ └── checkstyle.xml
├── docs
└── Domain-Model.puml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
└── java
│ └── com
│ └── harmellaw
│ ├── CriminalCase.java
│ ├── CriminalOffence.java
│ ├── PNCId.java
│ ├── PoliceInvestigation.java
│ ├── PreChargeDecision.java
│ └── Suspect.java
└── test
└── java
└── com
└── harmellaw
├── ACriminalCase.java
├── APoliceInvestigation.java
└── APreChargeDecision.java
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Gradle
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3 |
4 | name: Build
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up JDK 1.8
20 | uses: actions/setup-java@v1
21 | with:
22 | java-version: 1.8
23 | - name: Grant execute permission for gradlew
24 | run: chmod +x gradlew
25 | - name: Build with Gradle
26 | run: ./gradlew build
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /build/
3 |
4 | # Ignore Gradle GUI config
5 | gradle-app.setting
6 |
7 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
8 | !gradle-wrapper.jar
9 |
10 | # Cache of project
11 | .gradletasknamecache
12 |
13 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
14 | # gradle/wrapper/gradle-wrapper.properties
15 |
16 | # IDE config files
17 | /.idea/
18 |
--------------------------------------------------------------------------------
/ACKNOWLEDGEMENTS.md:
--------------------------------------------------------------------------------
1 | I couldn't have done this without help from many other people.
2 |
3 | Thankyou to every one of you.
4 |
5 | * My wife and kids for everything you do for me every single day
6 | * My ThoughtWorker colleagues who replied to my survey about how folks reason about and design domains these days
7 | * Rich Halford for your overpowering enthusiasm at the very outset
8 | * @bapostma for the C# version of the solutions
9 | * Bruck Eckell for your gift of the "beginners mind"
10 | * Barry Hawkins and Chris Phelps for your confidence in my ability to do this
11 | * Gayathri Thiyagarajan for teaching me more about DDD than anyone else
12 | * Mauro Vilasi and Jon Barber for your feedback on early ideas
13 | * Vanessa Formicola for yoru later feedback
14 | * Izzy Harris, Amalie Smidth, Tas Torkia, Jade Forsberg and Shazia Kasuji for your detailed and honest feedback on the beta version of the course
15 | * Melissa Duffield for your support in getting this course to
16 | * Lindsay Ventimiglia for showing me the ropes of the O'Reilly training platform, and for keeping me calm on the first official run
17 | * @jimtyhurst for fixing the out of date Gradle build file (and @goodmike and @bruce-koho for raising the problem in the first place)
18 | * Everyone who left feedback - thankyou!
19 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | Our Code of Conduct
2 | ===================
3 |
4 | The First Steps in DDD community is all about learning, discussion,
5 | inclusion and connection, and we want everyone to feel as comfortable as
6 | possible. Although we cannot guarantee you will have a good time, we can
7 | certainly do our best to make sure you don't have a *bad* time, and the
8 | baseline for this is that no one should ever be harrassed.
9 |
10 | To achieve this goal, all participants
11 | are required to agree with this code of conduct (CoC). Organizers will enforce
12 | this CoC at all times. We expect cooperation from all participants to
13 | help ensure a safe environment for everybody.
14 |
15 | This CoC applies for all aspects of this community (not just during
16 | formal training sessions).
17 |
18 | We do not tolerate harassment of participants in any form. Harassment includes
19 | offensive verbal comments related to disability, gender, gender identity and
20 | expression, age, sexual orientation, physical appearance, body size, race,
21 | ethnicity, religion, technology choices, sexual images in public spaces,
22 | deliberate intimidation, stalking, following, harassing photography or
23 | recording, sustained disruption of talks or other events, inappropriate
24 | physical contact, and unwelcome attention of any kind.
25 |
26 | Participants violating these rules are expected to immediately cease the
27 | offending behavior upon notification. Participants who continue to violate
28 | these rules after being notified may be sanctioned or expelled at the
29 | discretion of the community organisers.
30 |
31 | Points of Contact
32 | -----------------
33 |
34 | We recognize that managing harassment is not the job
35 | of its recipients. The community organisaer and delegated individuals (*contact
36 | persons*) will make themselves available to address any & all complaints of
37 | harassment, and the relevant contact information for them will be
38 | made available to upon request to
39 | [@andrewharmellaw](https://github.com/andrewharmellaw), the originator of this
40 | community.
41 |
42 | What You Can Expect
43 | -------------------
44 |
45 | If there is a problem and you reach out to one of the contact persons, you
46 | can expect that:
47 |
48 | 1. You will be heard and trusted.
49 |
50 | 2. Other organizers (if any) will be informed.
51 |
52 | 3. A discussion will be initiated between the contact person and/or
53 | organizers and the person in question, to stop the behavior in question
54 | and possibly include a warning to that person.
55 |
56 | If you're not sure that behavior counts as harrassment, please reach out to any
57 | contact person. We are happy to talk it over with you.
58 |
59 | Our Goal for this CoC
60 | ---------------------
61 |
62 | There are usually laws and rules and social norms about these issues. But
63 | those don't seem to be enough, as we've seen times. There are
64 | unspoken practices that are considered acceptable within subgroups, but never
65 | written down, and these produce behaviors that are considered acceptable as a
66 | result. Because no one says anything or puts a stake in the ground about these
67 | behaviors, it seems OK to those practicing them. Saying nothing doesn't work.
68 |
69 | We don't, however, want people to be terrified that they might accidentally
70 | say something wrong, and if they do make such a faux pas they will immediately
71 | be forcibly ejected. Simply punishing mistakes without giving someone the
72 | opportunity to learn is not the goal of this CoC.
73 |
74 | The CoC tells you when you've made a mistake, and empowers others to have a
75 | conversation with you about it. And most importantly, it tells newcomers &
76 | traditionally marginalized attendees that we value their safety. The focus is on
77 | the goal that "you will not be harassed."
78 |
79 | There are times when it doesn't matter what you do, someone might be having a
80 | bad day and feel anger or some other emotion regardless of who is nearby or
81 | what they do. The CoC shouldn't be a weapon in that situation, on either end.
82 | The CoC draws the line on harassment — it says what you cannot do (harass)
83 | but it doesn't say what you must do (speak a certain way).
84 |
85 | If You are Having a Hard Time Communicating
86 | -------------------------------------------
87 |
88 | These [Principles of Nonviolent Communication](https://www.cnvc.org/Training/NVC-Concepts)
89 | might be helpful:
90 |
91 | 1. Differentiate observation from evaluation.
92 |
93 | - Carefully observe what is happening, free of evaluation.
94 |
95 | - Specify behaviors and conditions that affect you.
96 |
97 | 2. Differentiate feeling from thinking.
98 |
99 | - Identify and express internal feeling states in a way that does not
100 | imply judgment, criticism, blame or punishment.
101 |
102 | 3. Frame your experience within universal human needs that are
103 | being met or not met in relation to what is happening and how you are feeling.
104 |
105 | - Examples: connection, sustenance, trust, and understanding.
106 |
107 | 4. Make a Request.
108 |
109 | - Clearly and specifically state what you *do* want, not what you don’t
110 | want.
111 |
112 | - Make a request and not a demand. If it's truly a request, there is no
113 | consequence for saying "no."
114 |
115 | - Before making the request, check your feelings to ensure you are not
116 | attempting to motivate, however subtly, through fear, guilt, shame, or
117 | obligation.
118 |
119 | - A genuine request allows the other person to give you a gift.
120 |
121 | The Four Agreements, By Don Miguel Ruiz
122 | ---------------------------------------
123 |
124 | 1. **Be Impeccable with your Word:** Speak with integrity. Say only what you mean. Avoid using the Word to speak against yourself or to gossip about others. Use the power of your Word in the direction of truth and love.
125 |
126 | 2. **Don’t Take Anything Personally:** Nothing others do is because of you. What others say and do is a projection of their own reality, their own dream. When you are immune to the opinions and actions of others, you won’t be the victim of needless suffering.
127 |
128 | 3. **Don’t Make Assumptions:** Find the courage to ask questions and to express what you really want. Communicate with others as clearly as you can to avoid misunderstandings, sadness and drama. With just this one agreement, you can completely transform your life.
129 |
130 | 4. **Always Do Your Best:** Your best changes from moment to moment; it is different when you are healthy as opposed to sick. Under any circumstance, simply do your best, and you will avoid self-judgment, self-abuse, and regret.
131 |
132 | Be Kind. Assume the best.
133 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # First Steps in Domain-Driven Design - Java Solution
2 |  [](https://snyk.io/test/github/andrewharmellaw/first-steps-in-ddd?targetFile=build.gradle)
3 |
4 | This is the starter project for the exercises in the "First Steps in Domain-Driven Design" course for O'Reilly. If you are more of a dotnet person, take a look at the [C# version of this codebase](https://github.com/First-Steps-in-DDD-Community/first-steps-in-ddd-solutions-dotnet/blob/main/README.md) (Thanks to @BAPostma for contributing this).
5 |
6 | You should be able to fork and then clone this repo to get an almost-empty gradle project ready to work with.
7 |
8 | ## Pre-requisites
9 | * Java JDK (at least Java 8)
10 | * IDE of your choice
11 | * Git client (unless you already have one in your IDE)
12 | * You don't need to have Gradle as the gradle wrapper is part of this project and will download gradle 7 for you. You might however want to use another gradle binary (such as the one which comes with IntelliJ IDEA) which should work fine
13 |
14 | ## What you get
15 | A directory `first-steps-in-ddd` containing this README.md, a gradle build file with JUnit 5 dependencies
16 | declared, standard `src` and `test` directory structure, and some example unit tests
17 | (`APoliceInvestigation.java`, `APreChargeDecision.java` and `ACriminalCase.java`) and associated starter
18 | classes (e.g. `PoliceInvestigation.java`, `PNCId.java`, `Suspect.java`) and an Enum, `CriminalOffence.java`.
19 |
20 | ## Up and running
21 | The training relies entirely on your writing unit tests (ideally you use test-driven development)
22 | so you want to be able to run them very quickly.
23 |
24 | Open the newly checked out project in your IDE (probably point it at the build.gradle, or simply the
25 | top-level project directory). Then check you can execute all the tests with the click of a single mouse
26 | button, or ideally a single keyboard shortcut.
27 |
28 | Additionally, it can be handy to check your build on the command line. Open a terminal and change to the
29 | top-level project directory. Then run the command `./gradlew build`. You ought to see your code and tests
30 | compile, and all but one of the tests run successfully.
31 |
32 | The failing test is where we will start exercise one.
33 |
34 | ## Get ahead of the game
35 | We're going to work on this code based on a [Domain Expert Statement from a Public Prosecutor](https://docs.google.com/document/d/1HpRJj1lk_M80Xvwzs5F-lZ1oACkVNeWRMG0s7BQxZzk/edit?usp=sharing). If you want to read it in advance, that'll help you in the first workshop exercise and beyond.
36 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | }
4 |
5 | group 'com.harmellaw'
6 | version '1.0-SNAPSHOT'
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | dependencies {
13 | implementation 'org.apache.commons:commons-collections4:4.4'
14 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
15 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
16 | }
17 |
18 | test {
19 | useJUnitPlatform()
20 | }
21 |
22 | apply plugin: 'checkstyle'
23 |
24 | checkstyle {
25 | toolVersion = '8.32'
26 | ignoreFailures=false
27 | maxWarnings = 0
28 | }
29 |
--------------------------------------------------------------------------------
/config/checkstyle/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
52 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
69 |
70 |
71 |
73 |
74 |
75 |
81 |
82 |
83 |
84 |
87 |
88 |
89 |
90 |
91 |
94 |
95 |
96 |
97 |
98 |
100 |
101 |
102 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
120 |
122 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
169 |
170 |
171 |
172 |
174 |
175 |
176 |
177 |
179 |
180 |
181 |
182 |
184 |
185 |
186 |
187 |
189 |
190 |
191 |
192 |
194 |
195 |
196 |
197 |
199 |
200 |
201 |
202 |
204 |
205 |
206 |
207 |
209 |
210 |
211 |
212 |
214 |
215 |
216 |
217 |
219 |
221 |
223 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
253 |
254 |
255 |
258 |
259 |
260 |
261 |
266 |
267 |
268 |
269 |
272 |
273 |
274 |
275 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
289 |
290 |
291 |
292 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
308 |
309 |
310 |
311 |
312 |
--------------------------------------------------------------------------------
/docs/Domain-Model.puml:
--------------------------------------------------------------------------------
1 | @startuml
2 | hide empty members
3 | hide empty methods
4 |
5 | class CriminalCase {
6 | }
7 |
8 | class CriminalOffence {
9 | }
10 |
11 | class PNCId {
12 | }
13 |
14 | class PoliceInvestigation {
15 | }
16 |
17 | class PreChargeDecision {
18 | }
19 |
20 | class Suspect {
21 | }
22 |
23 | Suspect *-- "*" CriminalOffence
24 |
25 | PoliceInvestigation *-- "*" Suspect
26 |
27 | PoliceInvestigation *-- "*" PNCId
28 |
29 | @enduml
30 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/First-Steps-in-DDD-Community/first-steps-in-ddd-solutions/866c9ad85ac580e84482bde7ee852eaad3ff4221/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * This file was generated by the Gradle 'init' task.
3 | *
4 | * The settings file is used to specify which projects to include in your build.
5 | *
6 | * Detailed information about configuring a multi-project build in Gradle can be found
7 | * in the user guide at https://docs.gradle.org/4.8/userguide/multi_project_builds.html
8 | */
9 |
10 | rootProject.name = 'first-steps-in-ddd'
11 |
--------------------------------------------------------------------------------
/src/main/java/com/harmellaw/CriminalCase.java:
--------------------------------------------------------------------------------
1 | package com.harmellaw;
2 |
3 | public class CriminalCase {
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/java/com/harmellaw/CriminalOffence.java:
--------------------------------------------------------------------------------
1 | package com.harmellaw;
2 |
3 | /*
4 | * List from https://www.cps.gov.uk/sites/default/files/documents/publications/annex_1a_table_of_offences_scheme_c.pdf
5 | */
6 | public enum CriminalOffence {
7 |
8 | DANGEROUS_DRIVING("Dangerous driving"),
9 | ENDANGERING_AN_AIRCRAFT("Endangering an aircraft"),
10 | FALSE_ACCOUNTING("False accounting"),
11 | IMPERSONATING_CUSTOMS_OFFICER("Impersonating Customs officer"),
12 | KEEPING_A_DISORDERLY_HOUSE("Keeping a disorderly house"),
13 | CORRUPTION_IN_PUBLIC_OFFICE("Corruption in public office"),
14 | CUTTING_AWAY_BUOYS_ETC("Cutting away buoys etc"),
15 | FALSE_EVIDENCE_BEFORE_EUROPEAN_COURT("False evidence before European Court"),
16 | FIRING_ON_REVENUE_VESSEL("Firing on Revenue vessel"),
17 | FRAUDULENT_EVASION_OF_AGRICULTURAL_LEVY("Fraudulent evasion of agricultural levy"),
18 | OBSTRUCTING_ENGINE_OR_CARRIAGE_ON_RAILWAY("Obstructing engine or carriage on railway");
19 |
20 | private final String value;
21 |
22 | CriminalOffence(String value) {
23 | this.value = value;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/harmellaw/PNCId.java:
--------------------------------------------------------------------------------
1 | package com.harmellaw;
2 |
3 | public class PNCId {
4 |
5 | public final String value;
6 |
7 | public PNCId(String value) {
8 | this.value = value;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/harmellaw/PoliceInvestigation.java:
--------------------------------------------------------------------------------
1 | package com.harmellaw;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | public class PoliceInvestigation {
7 |
8 | public PNCId pncId;
9 | public Set suspects = new HashSet<>();
10 |
11 | public PoliceInvestigation(PNCId pncId, Suspect suspect) {
12 | if (pncId == null) throw new IllegalArgumentException("You must provide a PNC Id");
13 | if (suspect == null) throw new IllegalArgumentException("You must provide a suspect");
14 |
15 | this.pncId = pncId;
16 | this.suspects.add(suspect);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/harmellaw/PreChargeDecision.java:
--------------------------------------------------------------------------------
1 | package com.harmellaw;
2 |
3 | public class PreChargeDecision {
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/java/com/harmellaw/Suspect.java:
--------------------------------------------------------------------------------
1 | package com.harmellaw;
2 |
3 | public class Suspect {
4 |
5 | private final CriminalOffence offence;
6 |
7 | public Suspect(CriminalOffence offence) {
8 | this.offence = offence;
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/com/harmellaw/ACriminalCase.java:
--------------------------------------------------------------------------------
1 | package com.harmellaw;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 |
5 | public class ACriminalCase {
6 |
7 | @BeforeEach
8 | public void setup() {
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/com/harmellaw/APoliceInvestigation.java:
--------------------------------------------------------------------------------
1 | package com.harmellaw;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertNotNull;
4 | import static org.junit.jupiter.api.Assertions.assertThrows;
5 | import static org.junit.jupiter.api.Assertions.assertTrue;
6 |
7 | import org.junit.jupiter.api.BeforeEach;
8 | import org.junit.jupiter.api.Test;
9 |
10 | public class APoliceInvestigation {
11 |
12 | PNCId pncId;
13 | Suspect suspect;
14 | PoliceInvestigation anInvestigation;
15 |
16 | @BeforeEach
17 | public void setup() {
18 | pncId = new PNCId("1234-ESDT");
19 | suspect = new Suspect(CriminalOffence.FALSE_ACCOUNTING);
20 | anInvestigation = new PoliceInvestigation(pncId, suspect);
21 | }
22 |
23 | @Test
24 | public void mustHaveAPoliceNationalComputerId() {
25 | assertNotNull(anInvestigation.pncId);
26 | }
27 |
28 | @Test
29 | public void cannotBeCreatedWithAnEmptyPoliceNationalComputerId() {
30 | Exception exception = assertThrows(IllegalArgumentException.class, ()
31 | -> anInvestigation = new PoliceInvestigation(null, suspect));
32 | assertTrue(exception.getMessage().contains("You must provide a PNC Id"));
33 | }
34 |
35 | @Test
36 | public void cannotBeCreatedWithNoSuspect() {
37 | Exception exception = assertThrows(IllegalArgumentException.class, ()
38 | -> anInvestigation = new PoliceInvestigation(pncId, null));
39 | assertTrue(exception.getMessage().contains("You must provide a suspect"));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/com/harmellaw/APreChargeDecision.java:
--------------------------------------------------------------------------------
1 | package com.harmellaw;
2 |
3 | import static org.junit.jupiter.api.Assertions.fail;
4 |
5 | import org.junit.jupiter.api.BeforeEach;
6 | import org.junit.jupiter.api.Disabled;
7 | import org.junit.jupiter.api.Test;
8 |
9 | public class APreChargeDecision {
10 |
11 | @BeforeEach
12 | public void setup() {
13 | }
14 |
15 | @Disabled("So the CI build stays green. Remove this to get coding.")
16 | @Test
17 | public void shouldRecordAlternativeOffenceAdviceAgainstSuspects() {
18 | fail();
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------