Use Case 1 - Adding a new employee
A new employee is added by the receipt of an AddEmp
transaction. This transaction contains the employee's name, addess, and assigned employee number. The transaction has the following three forms:
$ AddEmp <EmpId> "<name>" "<address>" H <hourly-rate>
$ AddEmp <EmpId> "<name>" "<address>" S <monthly-salary>
$ AddEmp <EmpId> "<name>" "<address>" C <monthly-salary> <commission-rate>
The employee's record is created with its field assigned appropriately.
Alternative:
An error in the transaction structure
If the transaction structure is inappropriate, it is printed out in an error message, and no action is taken.
Requirement Analysis
The Use Case describes various ways how Employee-data can be added to the system.
AddEmp
could be implemented as a polyadic function that receives 5-6 arguments,
describing an Employee's personal information and the salary the Employee_receives, and
the type of _salary (H
, S
or C
). If the salary type is C
, an Employee requires an additional commission-rate
.
Obviously, errors happening during transactions must be treated with care, appropriate error messages should be displayed.
This is particularly important for the input provided by the client, e.g. salary types must be validated as well as the
rates; also, check if empId
s already exist and prevent multiple occurences of the same empId
.
Takeaways
- validate user input:
empId
: existing? valid format?salaryType
: is it one ofH
,C
,S
?salary
should be greater than0
- display error messages if a transaction failed
Actors
Accountant - adds a new Employee to the system.
The Actor carrying out the Use Case is an Accountant. Of course, any other "role" would be eligible, but since the system exists in a Domain dealing with Accounting, I assume Accountant describes (a part of the) target audience of the system quite well.
Specifications
- For , is a set of arbitrary characters . Then
""
=, an emptystring
. - "empId"
- "salary type"
- "salary type"
<commission-rate>
- "rate"
<hourly-rate>
<monthly-salary>
Design
The main program receives the input and forwards it to the Application Layer. A Repository manages transaction-calls for an Employee
-Entity. This will be orchestrated by Payroll
,
a Domain Model part of the Domain Layer.
Domain Objects
- The
Employee
-Entity providing information aboutsalary
,salary-type
etc. - The
EmployeeRepository
accesses the required infrastructure for persistingEmployee
-Entities. The Repository should give the client the illusion that objects queried from it are in memory [📖DDD, p. 157]. Thus, the reconstitution as well as the creation ofEmployee
-instances will be delegated to a Factory Method as part of theEmployee
-class. At this point, I do not see the need for a more complex factory that assembles intricate aggregates, but providing a Factory Method as part of this Domain Object (and Domain Objects in general) can help with leveraging responsibilities for constructing and reconstitution of said Domain Objects to the Domain Object itself [📖DDD, p. 139]. Following the Dependency Inversion Principle, theEmployeeRepository
will provide the Interface to which the object in the Infrastructure Layer has to conform to.
Layers
Client Layer
- We will receive input from here. This layer will be substituted by the test classes
Application Layer
- Will consume the input and forward it to the Domain Layer. This layer will be substituted by the test classes. Thus, the test cases replace the controller method. It will accepts primitive data types which are forwarded to the
Employee
's Factory Method.Employee
-instances will be forwarded to thePayroll
'saddEmployee
-method
Domain Layer
Payroll
exists in the Domain Layer in the form of a Facade.- The
EmployeeRepository
handles Domain Objects so it's associated with this domain and will a such become part of the Domain Layer.
Infrastructure Layer
- The
EmployeeRepository
accesses lower-level objects facilitatingwrite
-operations for a data storage of an arbitrary type. The lower-level objects will be part of this layer. For this implementation, we will focus on the interface and provide simple file-based operations, but implement a Table Data Gateway that provides access toEmployee
-data. The Domain Layer will provide the interface for such anEmployeeGateway
according to the Dependency-Inversion Principle.
Resulting UML
Implementation
- The Employee.
- Employee.php
- EmployeeTest.php
I have deliberately put the Employee
into the Company
namespace. According to the description of the software,
the Payroll
-system will make sure to pay an Employee
- and I see an Employee
in the context of a Company, although putting Employee
into the Company
-namespace hints to resembling a parent("company")-child("employee") relationship. Such namespaces often share symptoms of vacuous modelling - just like an Anemic Domain Model is of little functional and conceptual value. In general, Vernon suggests to "relax the rules a bit between child and parent Modules." [📖IDDD].
Even if the Use Case does not explicitly state such a context, at least the semantics indicate it. Is Company
then eligible to understand the context of Employee
? Not necessarily. But the discussion should be held with domain experts understanding the project to the fullest. Is the Software used with Public Administrations? Then Company might not be the best fit for the managed Employee
.