3. Create and Test Domain.jl
To get experience with Julia and modules, we will build an application where we can register and retrieve persons.
You start with creating the sub-module file Domain.jl. Then you define in Domain.jl:
- the objects Address and Person.
- the enumerator AddressType with the values EMAIL and WORK.
- the local function create_key, which will create a unique key based on the time of creation and address.
- the objects that are accessible by other modules.
Finally, you define the test code in the file runtests.jl.
Contents
- 3. Create and Test Domain.jl
- Domain.jl - Domain Objects
- Activity 3.1: Create the File Domain.jl in the src-Folder
- Activity 3.2: Pasting the Domain Code into Domain.jl
- Activity 3.3: Update Accounts.jl
- Dependencies
- Activity 3.4: Adding Dates as Dependency
- Activity 3.5: Testing your Code
- Activity 3.6: runtests.jl
- Activity 3.7: Update your GitHub Repository
- Summary
Domain.jl - Domain Objects
On the Domain page, you define the custom data structures that make-up your domain.
To define a data structure and type, use the keyword struct
. The body consists of the fields of the data structure. A struct is a non-mutable object unless you precede it with the keyword mutable
.
Use constructors to define standard values. It simplifies the creating of an object.
module Domain #1
using Dates #2
export Person, Address, AddressType, EMAIL, WORK #3
# local function to generate an unique id
create_key(name::String) = string(hash(name * string(time()))) #4
# enumerated type for an address.
@enum AddressType EMAIL WORK #5
struct Address #6
id::String
created::DateTime
address_type::AddressType
address::String
#constructors
Address(address_type, address) = new(create_key(address), now(), address_type, address)
end # Address
struct Person #7
id::String
created::DateTime
name::String
addresses::Array{Address, 1}
#constructors
Person(name) = new(create_key(name), now(), name, [])
Person(name, addresses) = new(create_key(name), now(), name, addresses)
end # Person
end
#1 Module names start with a capital letter. See the Blue: a Style Guide for Julia.
#2 If you need date functions like time(), date(), or now() you have to load the Dates package.
#3 With the keyword export
you define what elements are default available to users.
#4 We use the hash function to generate a unique id. You use *
to concatenate Strings in Julia. The function string
converts the date-time value to a String value.
#5 The AddressTypes that you allow in an Address object.
#6 The structure of the Address
datatype. The constructor Address(address_type, address)
allows the user to only specify the AddressType and the address. The values for the fields id
and created
are generated by the Julia code.
#7 The Person datatype. The values for the fields id
and created
are generated by Julia code. When you don't specify an address, the software creates an empty array. Later on, you can add addresses using the push!
function.
Activity 3.1: Create the File Domain.jl in the src-Folder
One of the parts of the Onion architecture is the Domain, materialized in the file Domain.jl. The Domain only communicates with Julia or Julia modules or packages.
Prerequisites (activities of chapter 2)
- Activity 2.1: Setup the Development Environment.
- Activity 2.2: Create the Accounts module.
- Activity 2.3: Create a Repository on GitHub.
In this activity you will:
- Create the file Domain.jl.
Step | Action | Comment |
---|---|---|
1 | cd ~/.julia/dev/Accounts | Go to the .julia/dev/Accounts folder |
2 | $ code . | Start VSCode. |
3 | Right click on: src | |
4 | Select: New file | |
5 | Type: Domain.jl | A file that represents a module starts with a capital letter. |
6 | Press: <Enter> | A new document appears in the pane next to the navigation pane. |
In the navigation pane you see the next files in the folder src:
v Accounts
v src
- Accounts.jl
- Domain.jl
Activity 3.2: Pasting the Domain Code into Domain.jl
We define the Domain as a Julia sub-module. In a module, you declare the export and import items.
Export items are items that are used by other modules and Julia programs. An item can be an object (struct) or a function.
Import items are the items that you use from other modules like the Dates
module of Julia. Later on, you will learn how to declare this kind of dependencies in the file Project.toml.
If you don't change the names and their types, you could consider the module as an interface. The advantage is that you can change the implementation of an item without affecting other external parts.
Prerequisites
In this activity you will:
- Add the Domain example code to the file Domain.jl.
- Save the file.
Step | Action | Comment |
---|---|---|
1 | $ cd ~/.julia/dev/Accounts | |
2 | $ code . | Open VSCode. |
3 | Select the code from the section Domain.jl-Domain-objects | |
4 | Ctrl-C | Copy the code to the clipboard. |
5 | Paste the code in the file Domain.jl | |
6 | Ctrl-S | Save the file. |
7 | Close VSCode | Or continue with Activity 3.3 step 3. |
Activity 3.3: Update Accounts.jl
The sub-modules that you create are listed and instantiated in the main-module Accounts.jl.
Prerequisites
In this activity you will:
- Declare Domain as a sub-module of Accounts in Accounts.jl.
Step | Action | Comment |
---|---|---|
1 | $ cd ~/.julia/dev/Accounts | |
2 | $ code . | Open VSCode. |
3 | Open file: Accounts.jl | |
4 | Delete all lines | |
5 | Replace the code into the file with the fo;;owimg code: | |
module Accounts
include("Domain.jl"); using .Domain #1
end
#1 the function include
loads the code of the specified file. using .Domain
activates the module. The dot refers to a sub-module of Accounts. The ;
separates the two Julia statements.
Step | Action | Comment |
---|---|---|
6 | Ctrl-S | Save the file. |
7 | Close VSCode | Or continue with Activity 3.4 step 3. |
Dependencies
You declare all dependencies of your module in the file Project.toml
under the section [deps]
. The now()
-function belongs to Dates
module. Dates is a Julia module and you load with using Dates
.
name = "Accounts"
uuid = "a1b4bf14-7ec5-4e42-8992-fb1d0e08b0e4"
authors = ["Rob Bontekoe <rbontekoe@appligate.nl> and contributors"]
version = "0.1.0"
[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
[compat]
julia = "1"
[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
[targets]
test = ["Test"]
Activity 3.4: Adding Dates as Dependency
You define dependencies on other packages in the file Project.toml. If you have activated the Accounts environment (Pkg.activate(".") then when you add a package, Julia will update Project.toml for you. If the file Project.toml does not exist, Julia will create it.
Prerequisites
In this activity you will:
- Activate the
Accounts
environment. - Add the dependency
Dates
to the environment. - Inspect the status of the active environment.
Step | Action | Comment |
---|---|---|
1 | $ cd ~/.julia/dev/Accounts | |
2 | $ code . | Start VSCode. |
1 | Crt+Shift-P | Show All Commands. |
2 | Select: Julia: start REPL | Open REPL. |
3 | jullia> ] | Type ']' to activate the package manager. |
4 | pkg> activate . | Activate the Accounts environment. |
5 | (Accounts) pkg> status | Show Accounts loaded packages (dependencies) |
6 | (Accounts) pkg> add Dates | Add the Dates module. |
7 | (Accounts) pkg> st | Show your dependencies. You can abbreviate your commands. Use the arrow-up button to retrieve previous commands. |
Project Accounts v0.1.0
Status `~/.julia/dev/Accounts/Project.toml`
[ade2ca70] Dates
Step | Action | Comment |
---|---|---|
6 | Press: <BackSpace> | Return to the Julia prompt. |
7 | Close VSCode | Or continue with Activity 3.5 step 3. |
Activity 3.5: Testing your Code
One way to test your model is to put the test code in a file and execute the code line by line.
Prerequisites
- The previous activity 3.4.
- Step 3 (optional): Show Inline Results. during the installation of VSCode.
In this acticity you will:
- Create the file
test_domain.jl
. - Save the file.
- Execute the code line by line.
Step | Action | Comment |
---|---|---|
1 | $ cd ~/.julia/dev/Accounts | |
2 | $ code . | Start VSCode. |
3 | Right click on: src | |
4 | Select: New file | |
5 | Type: test_domain.jl | |
6 | Press: <Enter> | Create the file. |
7 | Copy the following example code into the file: | |
using Pkg; Pkg.activate(".")
import Accounts: Domain
using .Domain
donald_email = Address(EMAIL, "donald@duckcity.com")
donald_work = Address(WORK,
"""
Donalds Hardware Store
attn. Donald Duck
1190 Seven Seas Dr
FL 32830 Lake Buena Vista
USA
"""
)
addresses = [donald_email, donald_work]
donald = Person("Donald Duck", addresses)
email_address = filter(x -> x.address_type == EMAIL, donald.addresses)
@info email_address[1].address
Step | Action | Comment |
---|---|---|
8 | Ctrl-S | Save the file. |
9 | Select the first line | |
10 | Alt-Enter | The line will execute. |
11 | Repeat until the last line. | |
12 | Close VSCode | Or continue with Activity 3.6 step 3. |
When you hover over the result (to the right of the blue separator), you will see it in a popup.
Hovering over any variable will show its value.
Activity 3.6: runtests.jl
It is even better to put you test code in the file runtests.jl
. The folder test
contains the file.
Prerequisites
In this activity you will:
- Add unit test code to the file
runtests.jl
. - Test the module
Accounts
.
Step | Action | Comment |
---|---|---|
1 | $ cd ~/.julia/dev/Accounts | |
2 | $ code. | Start VSCode. |
3 | Select the folder: test | |
v Accounts
> src
v test
- runtests.jl
Step | Action | Comment |
---|---|---|
4 | Open the file: runtests.jl. | |
5 | Copy and paste the following code in runtests.jl | See: runtests.jl |
using Accounts
using Test
import Accounts: Domain
using .Domain
@testset "Domain.jl" begin
donald_email = Address(EMAIL, "donald@duckcity.com")
donald = Person("Donald duck", [donald_email])
email_addresses = filter(x -> x.address_type == EMAIL, donald.addresses)
@test email_addresses[1].address == "donald@duckcity.com"
end
Step | Action | Comment |
---|---|---|
5 | Ctrl-S | Save the file. |
7 | julia> ] | Activate the package manager. |
8 | pkg> activate . | Activate the Accounts environment. |
9 | (Accounts) Pkg> st | Check whether Dates is loaded. See Activity 3.4 - Adding Dates as Dependency. |
10 | (Accounts) Pkg> test Accounts | Run the test code. The result is: |
Test Summary: | Pass Total
Domain.jl | 1 1
Testing Accounts tests passed
Step | Action | Comment |
---|---|---|
11 | Close VSCode | Or continue with Activity 3.7 step 3. |
Activity 3.7: Update your GitHub Repository
It is time to push our changes to the GitHub repository. VSCode supports Git.
Prerequisites
In this activity you will:
- Open the Git-pane.
- Add a message.
- Stage your changes.
- Commit your changes.
- Push your changes to GitHub repository Accounts.jl.
Step | Action | Comment |
---|---|---|
1 | Shift+Ctrl-G | Open the Git-pane when it is not visible. |
2 | Place your cursor in the field Messages | |
3 | Type: Add Domain.jl sub-module | |
4 | In the line Changes, click on symbol: + | Stage all your changes. |
5 | At the top of the pane, click on: ✓ | Click on the checkmark ✓ (Commit) at the top. |
6 | Click on: ∙∙∙ | Open Views and More Actions menu. It is located in the upper right corner of the pane. |
7 | Select: Push | Push your changes to GitHub. |
You see a list of changed (ocher) and new (green) files (Domain.jl and test_domain.jl) in the section Staged Changes
of the pane.
Project.toml
src/Accounts.jl
src/Domain.jl
src/test_domain.jl
test/runtests.jl
Step | Action | Comment |
---|---|---|
5 | Click on: Commit to master | |
6 | Click on the Push button | The Push-button is located at the lower right corner. |
7 | Go to GitHub and check whether your changes are visible | |
8 | Close VSCode |
Summary
We apply the Onion Architecture to build our model that consists of the layers Domain, API, and Infrastructure. We define them as Julia sub-modules. We can modify the implementation of a module without dramatic consequences for other program code.
A module is a block of code between the keywords module <name module>
and end
. The module name starts with a capital letter. Also, the name of the file begins with an uppercase letter.
We start with the Domain. The code consists of self-defined data structures, local functions, and enumerations of values, which you want to allow in the module.
The Domain only communicates with Julia and packages.
An example of a data structure in the course is the type Address
. Here we mention the fields names with their data type. The constructors determine how we can create the data type.
We also defined the fields id and created. The hash function determines the unique value of the id based on the combination of address and time. It plays a role in CQRS and Event Sourcing. CQRS stands for Command Query Responsibility Segregation.
We could use the field created for data analysis in the future.
Unit code is placed in the file runtests.jl in the folder test.
Dependency on other modules or packages is in the file Project.toml.
Shortcuts for VSCode
Step | Action | Command |
---|---|---|
Ctrl+Shift-P | Show All Commands. | |
Ctrl+Shift-G | Open Git Control Source. | |
Ctrl+Shift-E | Open Explorer. |
You can also activate the commands from the icon bar in the most left column.