26. The Payroll Case Study: Iteration 1

image

© Jennifer M. Kohnke

Everything which is in any way beautiful is beautiful in itself, and terminates in itself, not having praise as part of itself.

—Marcus Aurelius, circa A.D. 170

The following case study describes the first iteration in the development of a simple batch payroll system. You will find the user stories in this case study to be simplistic. For example, taxes are simply not mentioned. This is typical of an early iteration. It will provide only a very small part of the business value the customers need.

In this chapter, we do the kind of quick analysis and design session that often takes place at the start of a normal iteration. The customer has selected the stories for the iteration, and now we have to figure out how we are going to implement them. Such design sessions are short and cursory, just like this chapter. The UML diagrams you see here are no more than hasty sketches on a whiteboard. The real design work will take place in the next chapter, when we work through the unit tests and implementations.

Rudimentary Specification

Following are some notes we took while conversing with our customer about the stories that were selected for the first iteration.

• Some employees work by the hour. They are paid an hourly rate that is one of the fields in their employee record. They submit daily time cards that record the date and the number of hours worked. If they work more than 8 hours per day, they are paid 1.5 times their normal rate for those extra hours. They are paid every Friday.

• Some employees are paid a flat salary. They are paid on the last working day of the month. Their monthly salary is one of the fields in their employee record.

• Some of the salaried employees are also paid a commission based on their sales. They submit sales receipts that record the date and the amount of the sale. Their commission rate is a field in their employee record. They are paid every other Friday.

• Employees can select their method of payment. They may have their paychecks mailed to the postal address of their choice, have their paychecks held for pickup by the paymaster, or request that their paychecks be directly deposited into the bank account of their choice.

• Some employees belong to the union. Their employee record has a field for the weekly dues rate. Their dues must be deducted from their pay. Also, the union may assess service charges against individual union members from time to time. These service charges are submitted by the union on a weekly basis and must be deducted from the appropriate employee’s next pay amount.

• The payroll application will run once each working day and pay the appropriate employees on that day. The system will be told what date the employees are to be paid to, so it will generate payments for records from the last time the employee was paid up to the specified date.

We could begin by generating the database schema. Clearly, this problem calls for some kind of relational database, and the requirements give us a very good idea of what the tables and fields might be. It would be easy to design a workable schema and then start building some queries. However, this approach will generate an application for which the database is the central concern.

Databases are implementation details! Consideration of the database should be deferred as long as possible. Far too many applications were designed with the database in mind from the beginning and so are inextricably tied to those databases. Remember the definition of abstraction: “the amplification of the essential and the elimination of the irrelevant.” At this stage of the project, the database is irrelevant; it is merely a technique used for storing and accessing data, nothing more.

Analysis by Use Cases

Instead of starting with the data of the system, let’s start by considering the behavior of the system. After all, it is the system’s behavior that we are being paid to create.

One way to capture and analyze the behavior of a system is to create use cases. As originally described by Jacobson, use cases are very similar to the notion of user stories in XP.1 A use case is like a user story that has been elaborated with a little more detail. Such elaboration is appropriate once the user story has been selected for implementation in the current iteration.

When we perform use case analysis, we look to the user stories and acceptance tests to find out the kinds of stimuli that the users of this system provide. Then we try to figure out how the system responds to those stimuli. For example, here are the user stories that our customer has chosen for the next iteration:

  1. Add a new employee
  2. Delete an employee
  3. Post a time card
  4. Post a sales receipt
  5. Post a union service charge
  6. Change employee details (e.g., hourly rate, dues rate, etc.)
  7. Run the payroll for today

Let’s convert each of these user stories into an elaborated use case. We don’t need to go into too much detail: just enough to help us think through the design of the code that fulfills each story.

Adding Employees


Use Case 1: Add New Employee

A new employee is added by the receipt of an AddEmp transaction. This transaction contains the employee’s name, address, and assigned employee number. The transaction has three forms:

  1. AddEmp <EmpID> "<name>" "<address>" H <hrly-rate>
  2. AddEmp <EmpID> "<name>" "<address>" S <mtly-slry>
  3. AddEmp <EmpID> "<name>" "<address>" C <mtly-slry> <com-rate>

The employee record is created with its fields assigned appropriately.

Alternative 1: 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.


Use case 1 hints at an abstraction. The AddEmp transaction has three forms, all of which share the <EmpID>, <name>, and <address> fields. We can use the COMMAND pattern to create an AddEmployeeTransaction abstract base class with three derivatives: AddHourlyEmployeeTransaction, AddSalariedEmployeeTransaction, and AddCommissionedEmployeeTransaction (see Figure 26-1).

Figure 26-1. AddEmployeeTransaction class hierarchy

image

This structure conforms nicely to the Single-Responsibility Principle (SRP) by splitting each job into its own class. The alternative would be to put all these jobs into a single module. Although doing so might reduce the number of classes in the system and therefore make the system simpler, it would also concentrate all the transaction-processing code in one place, creating a large and potentially error-prone module.

Use case 1 specifically talks about an employee record, which implies some sort of database. Again. our predisposition to databases may tempt us into thinking about record layouts or the field structure in a relational database table, but we should resist these urges. What the use case is really asking us to do is create an employee. What is the object model of an employee? A better question might be: What do the three transactions create? In my view, they create three kinds of employee objects, mimicking the three kinds of AddEmp transactions. Figure 26-2 shows a possible structure.

Figure 26-2. Possible Employee class hierarchy

image

Deleting Employees


Use Case 2: Deleting an Employee

Employees are deleted when a DelEmp transaction is received. The form of this transaction is as follows:

DelEmp <EmpID>

When this transaction is received, the appropriate employee record is deleted.

Alternative 1: Invalid or unknown EmpID

If the <EmpID> field is not structured correctly or does not refer to a valid employee record, the transaction is printed with an error message, and no other action is taken.


Other than the obvious DeleteEmployeeTransaction class, I’m not getting any particular insight from use case 2. Let’s move on.

Posting Time Cards


Use Case 3: Post a Time Card

On receipt of a TimeCard transaction, the system will create a time card record and associate it with the appropriate employee record.

TimeCard <empid> <date> <hours>

Alternative 1: The selected employee is not hourly

The system will print an appropriate error message and take no further action.

Alternative 2: An error in the transaction structure

The system will print an appropriate error message and take no further action.


This use case points out that some transactions apply only to certain kinds of employees, strengthening the idea that each kind should be represented by different classes. In this case, there is also an association implied between time cards and hourly employees. Figure 26-3 shows a possible static model for this association.

Figure 26-3. Association between HourlyEmployee and TimeCard

image

Posting Sales Receipts


Use Case 4: Post a Sales Receipt

On receipt of the SalesReceipt transaction, the system will create a new salesreceipt record and associate it with the appropriate commissioned employee.

SalesReceipt <EmpID> <date> <amount>

Alternative 1: The selected employee not commissioned

The system will print an appropriate error message and take no further action.

Alternative 2: An error in the transaction structure

The system will print an appropriate error message and take no further action.


This use case is very similar to use case 3 and implies the structure shown in Figure 26-4.

Figure 26-4. Commissioned employees and sales receipts

image

Posting a Union Service Charge


Use Case 5: Post a Union Service Charge

On receipt of this transaction, the system will create a service-charge record and associate it with the appropriate union member.

ServiceCharge <memberID> <amount>

Alternative 1: Poorly formed transaction

If the transaction is not well formed or if the <memberID> does not refer to an existing union member, the transaction is printed with an appropriate error message.


This use case shows that union members are not accessed through employee IDs. The union maintains its own identification numbering scheme for union members. Thus, the system must be able to associate union members and employees. There are many ways to provide this kind of association, so to avoid being arbitrary, let’s defer this decision until later. Perhaps constraints from other parts of the system will force our hand one way or another.

One thing is certain. There is a direct association between union members and their service charges. Figure 26-5 shows a possible static model for this association.

Figure 26-5. Union members and service charges

image

Changing Employee Details


Use Case 6: Changing Employee Details

Upon receipt of this transaction, the system will alter one of the details of the appropriate employee record. There are several possible variations to this transaction.

image

Alternative 1: Transaction errors

If the structure of the transaction is improper, <EmpID> does not refer to a real employee, or <memberID> already refers to a member, the system will print a suitable error and take no further action.


This use case is very revealing. It has told us all the employee aspects that must be changeable. The fact that we can change an employee from hourly to salaried means that the diagram in Figure 26-2 is certainly invalid. Instead, it would probably be more appropriate to use the STRATEGY pattern for calculating pay. The Employee class could hold a strategy class named PaymentClassification, as in Figure 26-6. This is an advantage because we can change the PaymentClassification object without changing any other part of the Employee object. When an hourly employee is changed to a salaried employee, the HourlyClassification of the corresponding Employee object is replaced with a SalariedClassification object.

Figure 26-6. Revised class diagram for Payroll: the core model

image

PaymentClassification objects come in three varieties. The HourlyClassification objects maintain the hourly rate and a list of TimeCard objects. The Salaried-Classification objects maintain the monthly salary figure. The Commissioned-Classification objects maintain a monthly salary, a commission rate, and a list of SalesReceipt objects.

The method of payment must also be changeable. Figure 26-6 implements this idea by using the STRATEGY pattern and deriving three kinds of PaymentMethod classes. If the Employee object contains a MailMethod object, the corresponding employee will have paychecks mailed to the address recorded in the MailMethod object. If the Employee object contains a DirectMethod object, the corresponding employee’s pay will be directly deposited into the bank account recorded in the DirectMethod object. If the Employee contains a HoldMethod object, the corresponding employee’s paychecks will be sent to the paymaster to be held for pickup.

Finally, Figure 26-6 applies the NULL OBJECT pattern to union membership. Each Employee object contains an Affiliation object, which has two forms. If the Employee contains a NoAffiliation object, the corresponding employee’s pay is not adjusted by any organization other than the employer. However, if the Employee object contains a UnionAffiliation object, that employee must pay the dues and service charges that are recorded in that UnionAffiliation object.

This use of these patterns makes this system conform well to the Open/Closed Principle (OCP). The Employee class is closed against changes in payment method, payment classification, and union affiliation. New methods, classifications, and affiliations can be added to the system without affecting Employee.

Figure 26-6 is becoming our core model, or architecture. It’s at the heart of everything that the payroll system does. There will be many other classes and designs in the payroll application, but they will all be secondary to this fundamental structure. Of course, this structure is not cast in stone. We will be modifying it along with everything else.

Payday


Use Case 7: Run the Payroll for Today

On receipt of the payday transaction, the system finds all those employees that should be paid on the specified date. The system then determines how much they are owed and pays them according to their selected payment method. An audit-trail report is printed showing the action taken for each employee.

Payday <date>


Although it is easy to understand the intent of this use case, it is not so simple to determine what impact it has on the static structure of Figure 26-6. We need to answer several questions.

First, how does the Employee object know how to calculate its pay? Certainly, the system must tally up an hourly employee’s time cards and multiply by the hourly rate. Similarly, the system must tally up a commissioned employee’s sales receipts, multiply by the commission rate, and add the base salary. But where does this get done? The ideal place seems to be in the PaymentClassification derivatives. These objects maintain the records needed to calculate pay, so they should probably have the methods for determining pay. Figure 26-7 shows a collaboration diagram that describes how this might work.

Figure 26-7. Calculating an employee’s pay

image

When asked to calculate pay, the Employee object refers this request to its PaymentClassification object. The algorithm used depends on the type of PaymentClassification that the Employee object contains. Figures 26-8 through 26-10 show the three possible scenarios.

Figure 26-8. Calculating an hourly employee’s pay

image

Figure 26-9. Calculating a commissioned employee’s pay

image

Figure 26-10. Calculating a salaried employee’s pay

image

Reflection: Finding the Underlying Abstractions

So far, we have learned that a simple use case analysis can provide a wealth of information and insights into the design of a system. Figures 26-6 through 26-10 resulted from thinking about the use cases, that is, thinking about behavior.

image

To use the OCP effectively, we must hunt for abstractions and find those that underlie the application. Often, these abstractions are not stated or even alluded to by the requirements of the application or even the use cases. Requirements and use cases may be too steeped in details to express the generalities of the underlying abstractions.

Employee Payment

Let’s look again at the requirements. We see statements like this: “Some employees work by the hour” and “Some employees are paid a flat salary” and “Some . . . employees are paid a commission.” This hints at the following generalization: All employees are paid, but they are paid by different schemes. The abstraction here is that all employees are paid. Our model of the PaymentClassification in Figures 26-7 through 26-10 expresses this abstraction nicely. Thus, this abstraction has already been found among our user stories by doing a very simple use case analysis.

Payment Schedule

Looking for other abstractions, we find “They are paid every Friday,” “They are paid on the last working day of the month,” and “They are paid every other Friday.” This leads us to another generality: All employees are paid according to a schedule. The abstraction here is the notion of the schedule. It should be possible to ask an Employee object whether a certain date is its payday. The use cases barely mention this. The requirements associate an employee’s schedule and payment classification. Specifically, hourly employees are paid weekly, salaried employees are paid monthly, and employees receiving commissions are paid biweekly; however, is this association essential? Might not the policy change one day, so that employees could select a particular schedule or employees belonging to different departments or different divisions could have different schedules? Might not schedule policy change independent of payment policy? Certainly, this seems likely.

If, as the requirements imply, we delegated the issue of schedule to the Payment-Classification class, our class could not be closed against issues of change in schedule. When we changed payment policy, we would also have to test schedule; when we changed schedules, we would also have to test payment policy. Both OCP and SRP would be violated.

An association between schedule and payment policy could lead to bugs in which a change to a particular payment policy caused incorrect scheduling of certain employees. Bugs like this may make sense to programmers, but they strike fear in the hearts of managers and users. They fear, and rightly so, that if schedules can be broken by a change to payment policy, any change made anywhere might cause problems in any other unrelated part of the system. They fear that they cannot predict the effects of a change. When effects cannot be predicted, confidence is lost, and the program assumes the status of “dangerous and unstable” in the minds of its managers and users.

Despite the essential nature of the schedule abstraction, our use case analysis failed to give us any direct clues about its existence. To spot it required careful consideration of the requirements and an insight into the wiles of the user community. Overreliance on tools and procedures and underreliance on intelligence and experience are recipes for disaster.

Figures 26-11 and 26-12 show the static and dynamic models for the schedule abstraction. As you can see, we’ve used the STRATEGY pattern yet again. The Employee class contains the abstract PaymentSchedule class. The three varieties of PaymentSchedule correspond to the three known schedules by which employees are paid.

Figure 26-11. Static model of a Schedule abstraction

image

Figure 26-12. Dynamic model of a Schedule abstraction

image

Payment Methods

Another generalization we can make from the requirements is that all employees receive their pay by some method. The abstraction is the PaymentMethod class. Interestingly enough, this abstraction is already expressed in Figure 26-6.

Affiliations

The requirements imply that employees may have affiliations with a union; however, the union may not be the only organization that has a claim to some of an employee’s pay. Employees might want to make automatic contributions to certain charities or have their dues to professional associations paid automatically. The generalization therefore becomes that the employee may be affiliated with many organizations that should be automatically paid from the employee’s paycheck.

The corresponding abstraction is the Affiliation class that is shown in Figure 26-6. That figure, however, does not show the Employee containing more than one Affiliation, and it shows the presence of a NoAffiliation class. This design does not quite fit the abstraction we now think we need. Figures 26-13 and 26-14 show the static and dynamic models that represent the Affiliation abstraction.

Figure 26-13. Static structure of Affiliation abstraction

image

Figure 26-14. Dynamic structure of Affiliation abstraction

image

The list of Affiliation objects has obviated the need to use the NULL OBJECT pattern for unaffiliated employees. Now, the list of affiliations for an employee who has no affiliation will simply be empty.

Conclusion

This is a good start on a design. By elaborating the user stories into use cases and hunting through those use cases for abstractions, we’ve created a shape for the system. An archicture is burgeoning. Note, however, that this architecture has been created by looking at only the first few user stories. We did not do a comprehensive review of every requirement in the system. Nor did we demand that every user story and use case be perfect. We also did not do an exhaustive design of the system, complete with class and sequence diagrams for every jot and title that we could think of.

Thinking about design is important. Thinking about design in small, incremental steps is critical. Doing too much is worse than doing too little. In this chapter, the amount we did was just about right. It feels unfinished, but it’s enough for us to understand and make progress with.

Bibliography

[Jacobson92] Ivar Jacobson, Object-Oriented Software Engineering: A Use Case Driven Approach, Addison-Wesley, 1992.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.8.247