add_entity makes it easy to create a class that encapsulates the data and behaviours of an Entity in a domain.

add_entity(name, domain, commands = NULL, queries = NULL)

Arguments

name

(character) Entity name.

domain

(character) Entity domain name.

commands

(character) Optional: names of public method that perform an action.

queries

(character) Optional: names of public method that return data to the caller.

Details

What does add_entity do?

Given the Entity name, and its domain name, and optionally commands and queries methods,

When add_entity is called

add_entity(name = 'Order', domain = 'Pizza Ordering', commands = 'add_item_to_order', queries = 'review_order')

Then the function:

  • Generates boilerplate code for the Entity and saves it at R/pizza_ordering-entity-Order.R;

  • Generates a unit-test for the Entity and saves it at tests/testthat/test-pizza_ordering-entity-Order.R; and

  • Opens the files (only in interactive mode).

Tip: You don’t need to remember the naming style for the different DDD components.

Instead, ddd takes care of naming style for all domain objects.

This way DDD file names, classes and functions are congruent with each other.

What are the main components of an Entity?

The boilerplate code for the Order Entity class produced by add_entity looks like this:

R/pizza_ordering-entity-Order.R

#' @title Order Domain Entity
#' @family Pizza Ordering
#' @noRd
Order <- R6::R6Class("Order", inherit = AbstractEntity, lock_objects = FALSE, cloneable = FALSE)

# Public Methods ----------------------------------------------------------
Order$set("public", "initialize", overwrite = TRUE, function(uid){
    super$initialize(uid)
    return(self)
})

Order$set(which = "public", overwrite = TRUE, name = "add_item_to_order", value = function(...){
    # TODO: Write command code here
    return(self)
})

Order$set(which = "public", overwrite = TRUE, name = "review_order", value = function(){
    # TODO: Write query code here
    query_result <- mtcars
    return(query_result)
})

Notice the three public methods created by add_entity:

  1. initialize is a constructor for new entities.

    • By DDD definition, every Entity must have a unique id (uid) which distinguishes it from other Entities.

  2. add_item_to_order is a command boilerplate. You’ll need to:

    • Replace ... with explicit (if any) input arguments; and

    • Implement the method behaviour. Remember, command doesn’t return data.

  3. review_order is a query boilerplate. You’ll need to:

    • Replace its content to retrieve data from the object

    • Remember, query does not change the state of the system.

The boilerplate code for the Order Entity unit-test produced by add_entity looks like this:

tests/testthat/test-pizza_ordering-entity-Order.R

context('unit test for entity Order')

# Setup -------------------------------------------------------------------
entity_uid <- "738a742a"


# General -----------------------------------------------------------------
test_that('calling Order$new instantiates an object with a unique id', {
    expect_s3_class(entity <<- Order$new(uid = entity_uid), "Order")
})

# Public Methods ----------------------------------------------------------

test_that('calling add_item_to_order changes the state of the object', {
    expect_s3_class(entity$add_item_to_order(), "Order")
})

test_that('calling review_order returns the desired results', {
    expect_equivalent(entity$review_order(), mtcars)
})

Workflow:

  1. Optional: Call ddd::use_ddd maximum once per project; this will make the project independent of ddd

  2. Call ddd::add_entity with its respective arguments

  3. Call devtools::document (or Ctrl+Shift+D on windows) to include the Entity in the project NAMESPACE file

  4. Call devtools::test (or Ctrl+Shift+T on windows) to validate that the Entity’s unit-test pass

See also

Other domain object generators: add_domain_service(), add_value_object()