账户

收集相关的会计分录并提供汇总行为

2005年1月22日

这是我于2000年代中期撰写的《进一步的企业应用程序架构开发》的一部分。不幸的是,此后太多其他事情吸引了我的注意力,因此我没有时间进一步研究它们,在可预见的未来我也没有时间。因此,这些材料还处于草稿阶段,我不会进行任何更正或更新,直到我能找到时间再次处理它们。

账户已经存在很长时间了。无论是个人银行账户、项目成本账户还是公司科目表,它们都会出现在大多数涉及会计的问题中。

关于账户是什么,有各种不同的思考方式。一个好的方法是将它们视为条目容器(会计分录)。每当你创建条目时,你都会将其放入账户中。然而,账户不仅仅是一个容器,它还具有提供摘要信息的行为,例如余额。

你也可以将账户视为某个值的审计日志,你使用它来记录某个金额,你不仅想知道当前值,还想知道它在过去任何时间点的值,并且你想知道对该值进行的每次离散更改。

第三种思考账户的方式是将条目中描述条目类型的所有元素联系在一起。这样,它在条目与其描述符之间提供了一层间接性。使用它可以更轻松地将所有具有相似特征的条目汇总在一起。

图1:账户可以在条目与其描述符之间充当间接性层

当人们想到账户时,他们通常会想到货币账户。但是账户可以用于比金钱更多的东西。如果我的冰箱里有24瓶黑巴特啤酒,我可以将其视为一个账户。当我拿几瓶给辛迪和我一起喝罗根·乔什时,我可以将其视为提取两瓶。我不想为我的冰箱使用会计系统,但如果你有一个仓库网络,那么这种模型可能很有意义。

工作原理

账户模式有两个基本要素:保存条目集合和提供这些条目的汇总信息。

由于你通常会获得大量条目,因此你通常需要优化计算余额的方式。优化技术将取决于你从账户中需要什么样的信息。例如,如果你经常需要当前余额,你可以在一个字段中缓存当前值,并使用条目向后计算以获得更早的余额。

条目通常可以追溯到账户的开户时间。但是,如果条目过多,并且你不再需要有关它们的详细信息,你可以用一个汇总条目替换一组条目,该条目的值为已删除条目的余额。这将保持合并后日期的余额,但意味着你将无法获取切入汇总条目的信息。但是,此条目可以用作详细条目的代理。

你通常期望账户中的所有条目都使用相同的货币。因此,你通常会看到使用特定货币创建的账户。可以创建动态选择其货币的账户,当它们收到第一个条目时,但空账户的繁琐行为意味着这几乎不值得付出努力。

如果你允许账户保存不同货币的条目,则需要使用货币袋进行汇总计算。

你看到的典型汇总行为是获取某个日期或某个时间段的余额、提取和存款。

何时使用它

我倾向于在两种不同的情况下使用账户

第一个是存在某个值,我需要当前值、历史值,并且能够保留对该值的更改的历史记录。如果我只需要当前值,我可以只使用一个字段。如果我只需要当前值和历史值,我可以使用时间属性 - 虽然我不确定账户是否比时间属性更复杂。

第二种情况是,如果我已经在使用会计分录(15),但我希望将所有条目汇总到一组共同的描述中。这使得比较类似条目变得更容易。

你经常会发现自己想知道是使用账户还是单独使用会计分录。一些基于事件的模式,例如发布规则网络(52)和差异调整(59),如果你使用账户会更容易使用。另一个因素是领域专家如何看待领域。如果他们使用账户来思考世界,那么使用账户是有意义的,如果不是,则不要使用。

不难看出账户与版本控制系统概念之间的类比。实际上,你可以将账户视为将版本控制的概念应用于金钱。但是我认为这并不意味着你可以将账户用于非定量情况。虽然我认为你可以将代码版本控制视为对文本文件的余额、提取和存款,但对我来说,这有点过分了。

示例:简单示例(Java)

账户的基本行为实际上非常简单,包括收集条目(会计分录)和提供汇总信息。收集条目非常简单。

class Account ...
  private Collection entries = new HashSet();
  private Currency currency;
  void addEntry(Money amount, MfDate date){
    Assert.equals(currency, amount.currency());
    entries.add(new Entry(amount, date));
  } 

汇总信息并没有复杂多少。

class Account...
  Money balance(DateRange period) {
    Money result = new Money (0, currency);
    Iterator it = entries.iterator();
    while (it.hasNext()) {
      Entry each = (Entry) it.next();
      if (period.includes(each.date())) result = result.add(each.amount());
    }
    return result;
  }
  Money balance(MfDate date) {
    return balance(DateRange.upTo(date));
  }
  Money balance() {
    return balance(MfDate.today());
  }

通常,提供单独的行为来确定一段时间内添加到账户或从账户中删除的总额很有用。