Thursday, June 20, 2013

Domain-Driven Design: Accounting Domain Model

In my previous post, I talked about two things that helped me improve my implementation of domain-driven design. In this post, I'll try to use the ubiquitous language and develop an accounting model.

Disclaimer: Note that I'm no accountant by any means.

This is based on "Accounting for Non-accountants" by Daniel R. Cruz (as listed here) — a text book from De la Salle University Press that I was fortunate enough to read. Thanks to Garen and her MBA studies.

There are eight steps in the accounting cycle. For purposes of this post, I'll limit only to journalizing and posting.

Journalizing
Record transactions in journal.
Posting
Post transactions to ledger accounts.

An accounting plug-in/sub-module would enable users to enter transactions and generate journal entries. These entries can be exported (posted) to the real or main accounting system which would tally the account balances of the enterprise using transactions from different systems/sources.

So, what's a journal entry? Here's what Wikipedia gives us:

A journal entry, in accounting, is a logging of transactions into accounting journal items. The journal entry can consist of several items, each of which is either a debit or a credit. The total of the debits must equal the total of the credits or the journal entry is said to be "unbalanced".

Journal Entries

Let's start modeling this. The JournalEntry is an entity. An aggregate can be formed around a journal entry and its items. The JournalEntry is the aggregate root. Note how I'm trying to use the ubiquitous language in naming our entities.

package accounting.domain.model;

@Entity
public class JournalEntry {
  private Date date;
  private String description;
  private List<JournalEntryItem> items = new ArrayList<JournalEntryItem>();

  public JournalEntry() {
  }

  public List<JournalEntryItem> getItems() {
    return this.items;
  }

  public void setItems(List<JournalEntryItem> items) {
    // TO DO: Ensure items are "balanced"
    this.items = items;
  }
}
package accounting.domain.model;

@Entity
public class JournalEntryItem {
  public JournalEntryItem(…) {…}
}

At this point, we can see that keeping the items "balanced" has not yet been implemented. We can add a validate method to the JournalEntry entity, and have it called before it gets persisted. But what about keeping the entity valid all the time by doing something like this?

@Entity
public class JournalEntry {
  private Date date;
  private String description;
  private List<JournalEntryItem> items;

  public JournalEntry(…, JournalEntryItem items[]) {
    if (!JournalEntry.isBalanced(items)) {
      throw new IllegalArgumentException(
          "The total of debits must equal the total of credits");
    }
    this.items = Arrays.asList(items);
    …
  }

  public static boolean isBalanced(JournalEntryItem items[]) {
    … total = ….ZERO;
    for (JournalEntryItem item : items) {
      if (item.type() == Type.DEBIT) {
        total = total.subtract(item.amount());
      } else { // item.type() == Type.CREDIT
        total = total.add(item.amount());
      }
    }
    return total.equals(….ZERO);
  }

  // getters and setters removed

  public List<JournalEntryItem> items() {
    return Collections.unmodifiableList(this.items);
  }

  public String description() { return this.description; }
  public Date date() { return this.date; }
}

Here's how the expanded journal entry item can be implemented.

@Entity
public class JournalEntryItem {
  public static enum Type {
    DEBIT, CREDIT
  }

  private String accountId;
  private Type type;
  private … amount;

  public JournalEntryItem(String accountId, Type type, … amount) {
    // TO DO: Throw IllegalArgumentException if any argument is null
  }

  public String accountId() { return this.accountId; }
  public Type type() { return this.type; }
  public boolean isCredit() { return this.type == Type.CREDIT; }
  public boolean isDebit() { return this.type == Type.DEBIT; }
}

The amount in the entry item was simplified for brevity. In a real implementation, it would be a value object representing money (an amount of a certain currency).

Based on the domain language, journal entries are created via business transactions, like buying merchandise inventory using cash, business owner depositing money to corporate bank account as capital, create invoice, receiving payment for invoice, paying bills, etc.

Now, let's give it a test run. Let's say the business purchased merchandise inventory worth $4,000, paying $3,000 in cash, and the balance on credit. This shall be represented as:

new JournalEntry(…, new JournalEntryItem[] {
    new JournalEntryItem("Inventory", ….DEBIT, 4000),
    new JournalEntryItem(    "Cash",     ….CREDIT, 3000),
    new JournalEntryItem(    "A/P",      ….CREDIT, 1000) // accounts payable
});

The Accounting Equation

To understand why certain business transactions result into journal entries with debit/credit against certain accounts, we need to understand the accounting equation.

Assets = Equity

Assets can be in any form of property owned or controlled by the business, whather tangible or intangible. Equity refers to the owners or claimants to the assets or properties of the business. Therefore, if the business has $100,000 worth of assets, there must necessarily be $100,000 worth of claimants.

- "Accounting for Non-accountants" by Daniel R. Cruz

The basic accounting equation is:

Assets = Liabilities + Capital

In actual businesses, there are normally two types of claimants to the assets of the business. The claim(s) of the owner(s) who invested in the business is called owners' equity or capital. The claim(s) of the creditor(s) who extended financial assistance to the business, whether in cash or in kind, is called creditors' equity or liability(ies). Total owners' equity (capital) plus total creditors' equity (liabilities) equals total equity.

If the business has $100,000 worth of assets and total capital investment of the owner is $60,000, then total liabilities (or claimants) must necessarily be $40,000. The left and right sides of the equation must always balance for every business transaction as well as for the summary of all transactions.

- "Accounting for Non-accountants" by Daniel R. Cruz

There are five accounting elements. Accounts are classified under one of the five elements. Depending on the account's classification, an increase or decrease may mean a debit or credit.

IncreaseDecrease
AssetDebitCredit
LiabilityCreditDebit
Income/RevenueCreditDebit
ExpenseDebitCredit
Equity/CapitalCreditDebit

Let's go back to the previous example, where the business buys merchandise inventory worth $4,000, paying $3,000 in cash, and the rest on credit.

  • The "inventory" account is an asset account. Buying merchandise inventory increases it. Thus, there's a debit entry item against it.
  • The "cash" account is an asset account. Paying in cash decreases it. Thus, there's a credit entry item against it.
  • The "A/P" (accounts payable) account is a liability account. Paying on credit increases the accounts payable. Thus, there's a credit entry item against it.

Let's have another business transaction example. Let's say the business sold merchandise inventory (Cost of Goods Sold or CGS) worth $500 for $900, receiving $600 in cash, and the balance on credit (Accounts Receivable or A/R). How would this look using our domain model?

// for the sale of goods transaction
new JournalEntry(…, new JournalEntryItem[] {
    new JournalEntryItem("CGS",  ….DEBIT, 500), // cost of goods sold
    new JournalEntryItem(  "Inventory", ….CREDIT, 500)
});
// for the sale on account and cash sales transaction
new JournalEntry(…, new JournalEntryItem[] {
    new JournalEntryItem("Cash", ….DEBIT, 600),
    new JournalEntryItem("A/R",  ….DEBIT, 300), // accounts receivable
    new JournalEntryItem(  "Sales",     ….CREDIT, 900)
});
  • When we move an item from inventory to sell as a product, we move the product from an asset (inventory) to an expense (cost of goods sold). Thus, we increase from "cost of goods sold", and decrease "inventory".
  • The "cash" and "accounts receivable" accounts are asset accounts. Receiving cash and credit increases it. Thus, there are debit entry items against it.
  • The "sales" account is an income/revenue account. Making a sale increases it. Thus, there is a credit entry item against it.

More examples can be found here (at Wikipedia).

Special Journals

Special Journals are designed to facilitate the process of journalizing and posting transactions. They are used for the most frequent transactions in a business. For example, in merchandising businesses, companies acquire merchandise from vendors, and then in turn sell the merchandise to individuals or other businesses. Sales and purchases are the most common transactions for the merchandising businesses. A business such as a retail store will record the following transactions many times a day for sales on account and cash sales.

Automated systems would usually create interfaces that have a pre-determined set of journal entry items for the most frequent transactions.

Let's take the sales journal for example. An entry is made when creating invoices (or to record transactions that involve sales on credit). The journal entry items are as follows:

  • Debit on "A/R" account (increasing an asset-type account)
  • Credit on "Sales" account (increasing an income-type account)

The interface for the sales journal would look more like creating an invoice, rather than creating journal entry items. The description of the journal entry shall contain a reference to the number (or unique ID) of the created invoice.

Ledger Accounts

The astute reader would have seen that each entry item references an (ledger) account. From my previous post on DDD, we're referencing other aggregates by ID (and not by type).

The list of ledger accounts is called the "chart of accounts". Typically, an organization (or enterprise, or business) would setup a chart of accounts, and each account is classified under a certain type of account. The type shall determine how increases and decreases affect the balance of the account. The account is uniquely identified using an alpha-numeric string that follows some kind of convention.

So, how can we model the account?

@Entity
public class LedgerAccount {
  private String id;
  private String name;
  private String description;
  private String type;
  private List<LegderAccount> childAccounts;
  // private … balance; // can be calculated
  …
}

It's a pretty straight-forward entity. Generally, accounts are arranged in a hierarchy.

In automated systems, the journal entry items already reference the account. So, to get the balance of an account, it's just a matter of doing a simple query that joins the ledger account and its related journal entry items. The posting step is now optional.

Closing

This post has gotten quite lengthy. And we've only touched the journal entries. Hopefully, it's enough to get some accounting domain model started. If you've got questions/suggestions, please hit the comments.

Thursday, May 30, 2013

Domain-Driven Design: Referencing Aggregates and Using DTOs

After seeing and reviewing some existing systems, I've been thinking about how to improve the way I practice domain-driven design. In this entry, let me talk about two things that I think helps when implementing DDD:

  • Reference other aggregates by ID.
  • Use data transfer objects.

Reference Other Aggregates by ID

Let aggregates reference other aggregates by ID (identity), not the aggregate itself.

Vaughn Vernon has written about this.

It's quite often that I'd model aggregates and reference other entities/aggregates. But this makes the system more difficult to maintain, as an aggregate would need to know every other entity/aggregate. Take the order and product domain model as an example.

We have an order entity that has one-or-more order items. The order entity forms the aggregate root. Each order item would refer to a product, a quantity, and a total price.

Just to help paint a better picture, we would also have a repository for order (OrderRepository) and a repository for product (ProductRepository).

Usually, we would have the order item reference a product by type. Something like:

class Order {
  private Long id;
  private List<OrderItem> items;
  . . .
}

class OrderItem {
  private Product product;
  private int quantity;
  private Money unitPrice;
}

class Product {
  private Long id;
}

Instead of referencing product by type, we can reference it by ID, like this:

class Order {
  private Long id;
  private List<OrderItem> items;
  public Long id() { return this.id; }
  public List<OrderItem> items() { return Collections.unmodifiableList(this.items); }
  . . .
}

class OrderItem {
  private Long productId;
  private int quantity;
  private Money unitPrice;
  . . .
}

class Product {
  private Long id;
  . . .
}

NOTE: I'm using the Long type for simplicity here. Otherwise, a domain-related value object like ProductId could be used.

NOTE: Notice how getters are not used to expose read-only properties in the Order entity. This seems to be a pattern to help developers get off the JavaBean/getter-setter mindset, and stay with a domain object/entity mindset.

This allows a cleaner implementation, since the order aggregate would not be referencing the product. This also makes the ProductRepository more useful. Otherwise, products would have been retrieved using orders.

If you happen to be using JPA for persistence, you can use the @ManyToOne annotation and specify the targetEntity element:

@Entity
class Order {
  @Id
  private Long id;
  @OneToMany
  private List<OrderItem> items;
  . . .
}

@Entity
class OrderItem {
  @ManyToOne(targetEntity = Product.class)
  private Long productId;
  private int quantity;
  private Money unitPrice;
  . . .
}

@Entity
class Product {
  @Id
  private Long id;
  . . .
}

NOTE: Notice that a uni-directional relation between order and order items is used (not a bi-directional relation). This helps make the implementation simpler, as the order item does not reference its parent order.

The above results to the following DDL.

create table "order" (. . .);

create table order_item (
  . . .
  product_id bigint,
  . . .
);

create table product (
  id bigint generated by default as identity (start with 1),
  . . .
);

. . .
alter table order_item
    add constraint FKxxxxxxxxxxx2
    foreign key (order_id)
    references order;
. . .
alter table order_item
    add constraint FKxxxxxxxxxxx7
    foreign key (product_id)
    references product;
. . .

Given the above simple adjustment, we now have an order aggregate that does not directly reference the product aggregate. This creates a cleaner separation and a more modular domain model. It might even be possible to have an order that can reference a different type of product (as long as the ID type is compatible). This might allow a more re-usable order domain model.

Use Data Transfer Objects

Use simple structures (DTOs) to transfer data from the domain model to an interface and vice-versa.

I often see the domain model entities with all of its fields being modifiable via getters and setters. Also, they have zero-arguments constructors. This makes it difficult to apply invariants or business rules (as the entity can be in an invalid state). And the usual excuse I get for this is because they need to create a UI that allows the fields/properties to be modifiable.

For me, I'd rather have an entity that is always valid.

To preserve the business rules or invariants of the domain model, we cannot afford to have all of the entity fields being modifiable. This is where DTOs are needed.

package order.domain.model;

@Entity
class Order {
  . . .
  public int addItem(Long productId, int quantity, Money unitPrice) {
    . . .
  }
}

@Entity
class OrderItem {
}

. . .

package order.interfaces.dto;

class OrderDTO {
  private List<OrderItemDTO> items;
  public List<OrderItemDTO> getItems() {...}
  public void setItems(List<OrderItemDTO> ...) {...}
}

class OrderItemDTO {
  private Long productId;
  private int quantity;
  // getters and setters
}

The UI shall use the DTOs when displaying and receiving inputs. Once the data is captured in DTOs, assemblers are used to apply the changes to domain objects. This pattern can be seen in the dddsample project.

package order.interfaces.assembler;

class OrderAssembler {
  . . .
  public OrderDTO toDTO(Order order) {
    OrderDTO dto = new OrderDTO();
    . . .
    dto.setOrderDate(order.orderDate());
    dto.setEntryDate(order.entryDate());
    dto.setCustomerId(order.customerId());
    . . .
    return dto;
  }
  . . .
  public Order fromDTO(OrderDTO dto) {
    Order order;
    if (dto.getId() != null) {
      order = orderRepository.find(dto.getId());
    } else {
      order = new Order(..., dto.getCustomerId());
    }
    . . .
    Long productIds[] = dto.getProductIds();
    // Can use IN operator to get products with given IDs
    Map<Long, Product> products = productRepository.find(productIds);
    for (OrderItemDTO itemDTO : dto.getItems()) {
      Product product = products.get(itemDTO.getProductId());
      order.addItem(
          item.getProductId(),
          item.getQuantity(),
          product.getPrice());
    }
    return order;
  }
  . . .
}

This has helped me understand DDD implementations better. I hope it helps others too.

Monday, May 6, 2013

JSTL <c:url> and jsessionid Parameter

Here's a brief entry about the jsessionid parameter that appears whenever you use <c:url/> tags in your JSPs. I've seen several questions on how to remove it, and how to disable <c:url/> tags from generating it. After some research, and some quiet time to think about it, the solution is quite simple, and has something to do with JSPs having session defaulting to true.

The solution is to make sessions optional for pages that don't require them. Simply add a JSP directive <% @page session="false" %>.

JSPs, By Default, Create Sessions

Yes, JSPs create sessions, unless you specify otherwise. By default, JSP files get a HttpSession using request.getSession(true) method. So, by default, JSP files create a new session if none existed.

But what does this have to do with <c:url/> generating/adding a jsessionid parameter to the resulting URL?

The <c:url/> tag checks if the request supports cookies. In cases where the request is the first request (with no cookies sent, at least, none yet), the server could not be sure if the request supports cookies. In these cases, the <c:url/> tag implementation adds the jsessionid parameter when the request does not support cookies. This is called URL session tracking.

When will cookies not be supported?

There are a couple of possibilities. One would be when the browser has it disabled. The other would be when a search bot is crawling your web site.

So, it's not the tag's fault. It's doing what it is supposed to do. It also escapes characters to form a valid URL.

Others might think that simply not using the <c:url/> tag would solve the problem. But I think that creates more problems, as your URLs may not have been escaped properly.

Still others have conjured up filters that would remove the session ID from the URL. Please don't. Making sessions optional may be a better option.

JSPs and Template Frameworks like SiteMesh and Tiles

If you're using template frameworks like SiteMesh and Tiles, you're likely to be using JSPs as decorators or templates (for headers, navigation bars, footers, and others). Note that these JSPs may also create a session, unless you explicitly specify it using the page directive. So, be careful. It might be a good practice to keep these template pages with session creation set to false.

URLs and Crawlers

The problem of inadvertently creating session is more apparent when developing web sites that are crawled by bots (like Googlebot). If you happen to see URLs crawled by the search bot having jsessionid parameters, then you should be looking at the pages that should not have created sessions.

Not only are these session parameters ugly, they simply ruin your web site's search engine results page. Who would want to visit your site with a pre-existing jsessionid?

Conclusion

A good practice would be to keep your landing page (usually an index.jsp, or whatever your welcome page is in your web.xml) with a page directive to turn-off session creation. Another page that should not create sessions would be your login page. The session is only required after the user has logged in (not before).

If a user visits your page with an existing session, it will still work. Remember, we're just making session creation optional. We're not making it invalid.

I hope this brief entry can help several Java developers and save some of our precious time.