From a question in ParallelInheritanceHierarchies.
An Advancer is a MethodObject. I first created an Advancer to hold all of the temps used in the otherwise unrefactorable advance method in WyCash. A Portfolio of Positions could advance to a new date by processing all related transactions. The method was used a lot in WyCash because portfolio reports could be opened as of any date. Normally a method object does not live beyond the invocation of the method it assists. This was not the case with Advancer.
We found that Advancers were pretty much the equal of Portfolios. This is striking because we were writing a portfolio management system. Our system was about portfolios. Everyone knew what a portfolio was but no-one had ever heard of an Advancer. The word isn't drawn from the domain. When we sought the proper name for Advancer, the best our domain experts could come up with was DateRange, which it wasn't.
We came to think of computations in terms of the Advancers we would need. We knew there would be Portfolios of course, but we were thinking of the Advancers. The mere existence of Advancers shaped the way we thought. We got more done. We did it faster. We wrote less code. We had fewer bugs.
I often use Advancers as an example of EmergentDesign. We never would have designed them up front because neither we or our domain experts had ever heard of them. They did know that they wanted reports as of any date and had been disappointed by other systems' inability to provide such. Also they wanted to enter transactions in any order and expected the reports to reflect all entered data in a sensible way. We simply set out to provide this and ended up with a convoluted advance method in the process. Without refactoring it would have become just another tarpit like those that loom inside so many large programs. Instead we found an object with intellectual leverage. One that sped our thinking rather than slowing it.
We enjoyed the benefits of Advancers for many months before we discovered their real calling. We had been having persistent problems with a few tax reports. The numbers the government wanted were described in terms of positions within portfolios so we naturally looked to these objects to host the calculations. Unfortunately, the values we then had at hand were close but not exactly the values we needed. Everything seemed to be just one more object away, and repeated application of the LawOfDemeter only made things worse. Finally, out of frustration, we began to look around for other objects that might help, and there was Advancer. The Advancer had left over in its instance variables (the temps of the old advance method) exactly the information we needed. Not only did the calculations code up cleanly, they did so without Demeter. Our months of tax bugs were over.
Years later, I came to realize why we had had so much trouble with the tax calculations. First of all, we hadn't yet discovered Advancers when we started on them. But, more importantly, we were quick to accept the difficulty of their implementation. We were serving traders and traders asked for calculations that were easy. The government, we reasoned, were stupid by comparison and asked for things that were pointlessly hard to compute. We cursed the government and forged ahead. Only when I allowed myself a moment of philosophical reflection did I realize that traders cared most about what monies they had (positions) while the government cared most about how they came to have it (advancers). -- WardCunningham
I still don't quite grasp this, especially given that a transaction is a different object. Could you give some examples? For example, is a daily interest calculation an Advancer? How about a transfer between two accounts? Or a price change in a stock?
Yes, all of these are complications that add wrinkles to an advancer. My goal here is not so much to explain the advancer as to explain the experience of having discovered the advancer. A little confusion is good for the argument. If I explained the advancer in its total simplicity then one couldn't help but ask why I didn't just make them in the beginning. It is also possible that I remember the story better than the code. Writing it up plainly might require reinventing it since I no longer have the source. -- WardCunningham
I think I might understand WhatIsAnAdvancer, so let me phrase in different terms, and Ward can tell me if I've got it or not ...
You have a Portfolio object, and it has a large number of Positions. Positions can be added to the Portfolio regardless of date/time ordering. Resolving the effects that Positions can have on a Portfolio can be somewhat complex. Clients of the Portfolio object need to find out the value of a Portfolio at any given date in the past.
In the beginning, Ward & Co. tried to do this inside the Portfolio object, but it was a pretty complicated endeavor, and a lot of bugs resulted from the complexity. Eventually, they refactored all this code out to a separate object and called it an Advancer. All the Advancer does is take the Portfolio from one state to the next, processing one Position at a time.
Hm, now that I've written it out I'm not sure if I understand it, either. Feedback, Ward?
Yes, this is the general idea. Portfolios were already well factored into Clients, Positions, Instruments, Transactions, Calendars, Schedules, CashFlows, Calculators and more. But this was not enough factoring to prevent some cruft from collecting. That cruft belonged in an Advancer. It didn't look like cruft when moved there. Advancer emerged and served us well. -- Ward
We came up with the same ideas as an Advancer when writing - guess what - a portfolio management system! We just called them positions, though.
The part that has not really been explained here is that there is another part to the pattern: a TransactionTape. This is a time-ordered history of all the transactions (i.e. state changes) that have been applied to the system. The Advancer starts off with an empty position and the tape is rewound to the start date. Winding the tape forward and applying the state changes then gives you the state at any given date. Different advancers can be created with different dates; these are just caches of state. -- HubertMatthews
Yes, we had Positions too. One takes a position as of a date in a particular instrument by posting trades. A position is for one instrument what portfolio is for all instruments. A portfolio holds a collections of positions on a given date. My point above, and the surprise to me, was that a starting position and an ending position weren't enough information to properly report taxes. The trades (raw data) is enough information, but there is a fair amount of computing required to extract it. That is what advance did and Advancer now represents. There are other details but they are even more boring than these. -- WardCunningham
Have you thought about writing a book or articles about the lessons you learned whilst working on WyCash as I'm sure it's a topic that interests a lot of people.
I think an Advancer, as used here, is actually a CheckpointFactory?, a BalanceBin?, or just a live instance of a FinancialStatement?.
I really do need to write BalancesAreVectorsNotScalars? someday.