Jun 13, 2005

Expense Calculator - Session 6

Till session 5, we implemented all 6 requirements. Time to take a look at the code keeping in mind the observations of the last session.

First up I add more test coverage for other scenarios. Everythign works fine.

But i had pointed out about making parellel class heirarchies of expense sheet and expense statement. I try doing it but when i realize the Factory Method signatures would be different I revert back to old desing. I prefer factory method only when method signatures are same and if different then its not 'so difficult' to make a guess about redundnant parameters. In my case the method signature of factory method becomes too long and confusing.

Further I have kept Expense related classes package private. They wont be published to the outer world. So ensuring the right usage of two printStatement methods is possible. Thus no Introduce Polymorphic creation with factory method is used. :-). A case where refactoring doesnt make sense.

Next I see my ExpenseSheet Test case and the test methods which test statement generation.The questoin that begs to be asked here is what should I create a Party as: Payer or Receiver. This question popped up only after adding more test scenarios. It becomes evident that Payer or Receiver is not 'really' a Party Type, but a role played a Party. So Party bhavdeep may be a payer in one transaction and receiver in another. Another advantage of using good test coverage. I refactor to form a Role heirarchy which is used by Party. I update my test cases. Now they look more sensible. My test methods have a common feel: Create parties, set up their roles, add transaction and test 'whatever aspect' you want to.

Also I see that when I create a transaction I must process it. That is I need not call process. I make that method private , update my test cases and I call process in transaction constructor!Also in my test cases I did away with facade, dao classes. I will add these classes and packages only when required. In my test case I supply the Party with the list of transactions that it needs.

Finally my Domain and Test Class Diagrams look like this:

Domain:

Posted by Hello


Test:

Posted by Hello


Lessons Learnt:

  • I need to practice Refactorings a lot. I am still not natural at it.
  • After that is done, come and add automated functional test cases for this project. I will use FIT
  • Then attached UI and persistence and publish this desktop app.
  • Then Claps. :-)

Jun 11, 2005

Expense Calculator - Session 5

Now having implemented 4 requirements I come on to the next one:

Requirement 5: Generate an expense statement for a payer for a date range.

Say for bhavdeep for 1 Apr to 30 Apr 2005 genrate an expense statement should look like this:

Bhavdeep
1 Apr 2005 to 30 Apr 2005

Bhavdeep receive from Surender 13 USD
Bhavdeep receive from Deepak 5 USD

2 Apr 2005 Albertsons Deepak 12 USD
7 Apr 2005CostCo Surender 5 USD
16 Apr 2005 Burger King Deepak -7USD
28 Apr 2005 Panda Express Surender 8 USD

Thus we see a header with name, date range for statement, summary, and details.

I write a unit test, it fails, then i go on to implement it and it passes. Same old style by now.
But while implementing I am not able to come up with the right interface. I maintain a party message : getExpenseSheet(list transactions) and on expense sheet i supply party and date range as attributes to genrate statement. Is this the right way?Somehow I think not. I would like a party interface to which i can ask..getStatemetn(DateRange range). But then for that Pary would need to somehow get to the db and get list of transactions. So pary now talks to DB interafaces (not that i have any by now). But it would right. I dont like this coupling.

I stop. I rethink.I see what the user of this domain package would be comfortable with. UI and domain intermediate layer would speak to domain layer. Now this layer would also access facades that can let it speak to db layer. So I think..Party or for that matter any domain object should just have responsibilities. It must not know about the external world of db, ui et al.

So I come up with facades package. Primarily TransactionFacade that accepts a TransactionDao and gets me the list of transactiosn for date range. in my junit test case which i now re-write i use stubtransctiondao (not mock) and it returns me some canned transaction data. Good enough.

Now my test flow looks like this:
facade gets me list of trasnactions.
i ask party to get expensestatmetn for this set of trasnactions.

Simple this is . way better than my ugly looking test. also Party doesnt know where it got thsi set from (and rightly so). Now i look at expense sheet which does the bulk of printing. and its go t ugly. I see all this printing business requires a set of summary lines. I rightly move this code into an Extraced ExpenseStatement class. Now code looks cleaner.

Now i move on to my next requirement : Expense statement for a transaction.

Hmm.simple it looks. But when i see the structure of transaction expense statement i see it would have no details. Just trx name, date, payer, receivers and summary lines.

Now i look at expense statemnt class. I see a herirachy. one for party and other for transaction. I first refactor expensestatement into expensestatemetna and its child partystatement class.
Then i add the transcationstatement functionality.

Also my party interface looks like this: getExpenseStatemetn(DateRange, List trasnactons). You may ask why both?

First it lets me keep Party independent of calls to another layer such as persistence layer. Next daterange is required when printing the statement. AS of now this is good enough. Aslo that way i dont expose classes such as ExpenseStatement, ExpesneLine to the world outside domain package because they must not know about it. Lesser you expose better for your neighbors !!!!

Finally my class diagram looks like this:

A few observations on this class diagram:

  1. Party Expense Statement and Transaction Expense Statement are bit more coupled. Time to look up the GoF catalog probably :-). But for now lets wait.
  2. I can also probably have expensesheet heirarchy but that may lead to parellel class heirarchies. I need to evaluate.
  3. I need to do check my test coverage and make it more solid. Thats surely my next task.
  4. Also as of now I have the facility to handle transactions where payer has a share in expenses and doesnt have a share. When I think about those situations where part of expesnes are shared and part are not I realize the same classes do the trick. Basically I need to come up with a stable transction definition:
Transaction : is where there is only payer and there is only one amt. So a trx where total amt is 60$ but 40$ are shared equally but remaining 20$ are not is actually made up of 2 transactions: (assuming one payer of course): 40$ trx and 20$ trx. That gives me relief. At times simple thoughts do the trick .

My domain vocab looks like this;

Party: participates in transaction as payer or receiver
Transaction: has one party (payer), one amt and one or more receivers.
Distribution: Transaction amt is shared equally including payer (Equitable with Payer) or shared equally without the payer (Equitable without Payer)

So the above and money, daterange classes are what my domain package exposes to the outer world and thats fine enough. Always give a great thought to what you must keep public, private, friendly et al. Its important. Start by being stingy and then become moderate if reqd. Because other way is almost impossible always especially when your clients start going out of your control boundaries.

Posted by Hello

Jun 6, 2005

Expense Calculator - Session 4

In session 1, we implemented requirements 1 and 2. And sessions 2, 3 we spent time simplifying the design. At this stage we are now good enough to move on to implementing the next requirement.

Requirement 3: Generate an expense sheet for a payer for a list of transactions for a date range.

Steps:
Wriet junit test case. While writing the test case I realize I have not added a date to transactoins. :-). So wear refactoirng hat and add date attribute to transaction.

Next is handling date range. For me I have a Transaction class with date attribute. I guess that eventually the interface will boil down to a list of transactions. My query should fetch me the valid transactions. So i see something like party.getexpesesheet(transactions) as the interface.

I complete test case, it fails. then i implement it and it passes.

I have done the test for a payer. I do it for a receiver. IT also passes (claps) at first attempt.

I am keeping my unit tests very simple. My automated functional tests which will load a real long list of transactions and generate expense sheet will really test this functionally out. But at class levels thses tests suffice. Thats what I think now but this can change later on ;-)

Now I have added one more junit test case. I have 2 test cases. I scan the two and refactor them to form a heirarchy. This session really went smooth and fast. So thats what our rythm should be: write test case, fail, pass, refactor to simplify design, next req, test case, fail pass, refactor and so on.

At the end I just try to review my classes. And I see something. EquitableDistribution and NonEQuitableDistribution. The latter (or both) class names are misleading. Why? I said earlier non equitable = where payer doesnt have a share in expenses. So the prefix non applies to 'payer doesnt'. But read nonequitable and it means not divided equally. Misleading ha. I come up with right names. EquitableWithParty and EquitableWithoutParty. I do the rename refactoring.:-). I also see something coming up: PartlyEquitableWithParty ... ;-) probably. But when it comes I will handle it.

Next I move on to implement requirement 4: Generate an expense sheet for a receiver. This is pretty straight forward.

A rythm has surely developed :-)

The updated class diagram for domain and test sources look like this:

Domain class diagram:

Posted by Hello


Test class diagram:

Posted by Hello

Jun 5, 2005

Expense Calculator - Session 3

The tools I am using are:
  • Intellij Idea 4.5.3
  • CVS for source control *its a local repository on my laptop
  • Argo UML for class diagrams. I just used visual paradigm for session 1 but argo is what i m more comfortable with.

Till now the implementation looks good enough and more importantly simple. Now when I look at the expense sheet generated for the transaction it looks somehting like this for req 1: (see session 1)

bhavdeep 10 usd, deepak -5 usd, surender -5usd. Are these expense lines correct.yes but are they going to help me in my next req: that is generating an expense sheet for a party. say for bhavdeep across n transactions.

just trying to add transaction expense sheets for reqs 1 and 2 I see a glaring hole: expense line doesnt say whome the money comes from or goes to. to implement that i see bhavdeep 10usd and deepak, surender -5usd are credit and debit lines respectively. Hmm..i see an expense line heirarchy. So i add these classes. *design hat.

But while implementing i see that for credit lines there are multiple receivers who pay the amt. so for bhavdeep 10 usd, deepak and surender pay 5 usd each. essentially this is complicating matters. i think composite might come to rescue. but i always am wary of straight away jumping to patterns. they are complex beasts and u have to pay a price for using them. i try using compoiste and i see the design getting only complex. so i wait and do a relook.

I relook at the expense sheet basically credit line. and after some scratching it strikes me:
credit line 10usd is nothing but 2 credit lines of 5 usd. so my redone expense sheet now looks:
bhavdeep 5 usd from deepak, bhavdeep 5 usd from surender, deepak 5usd to bhavdeep, surender 5 usd to bhavdeep. this clears up things. first every credit line has a debit line and vice versa. bidirectional association. also as of now my thinking is helped by having all 4 though in realiyt only 2 exist..both debit lines or credit lines. but then i can always wear my refactoring hat and remove them if reqd.

i wear my refactoring hat/desing hat alternately and bring code into shape which looks now has simplifed transaction , payer classes and added an expense line heirarchy.

Session 4

the class diagram looks like this: compare with session 2 class diagram

Posted by Hello

Jun 4, 2005

Expense Calculator - Session 2

At the end of session 1, I had mentioned that Transaction class is a place where we can use State pattern. The two scenarios we saw deal with an equitable (payer shares the expenses) and non-equitable (payer doesnt share the expenses).

Analyze further and you can see that this characteristic about transactions is characterisitc of Party Heirarchy. Even party heirarchy is a bit confusing. Now if I create Distribution heirarchy and attach it to Transaction , then isParticipant method becomes redundant on Party heirarchy.

That in turn lets me do away with ParticipantPayer and NonParticipantPayer. Because that is now controlled by Distribution heirarchy. So I end up with Party and Receiver. Then I trun Party Heirarchy into Payer and Receiver which makes it a lot simpler.

Session 3

See the class diagram below and compare it with the class diagram on session 1. This shows that its 'difficult' to come up with simple solutions but with agile techniques you can ;-)

Posted by Hello

Expense Calculator - Session 1

My first session.

The following was achieved:
  1. Set up of intellij idea
  2. Requriements 1 and 2
Requirement 1: We bhavdeep, deepak, surender go to albertsons. Buy worth 15$ (we r stingy). bhavdeep pays. the expense amt is shared equally among 3.

Steps: Write junit test case, it fails. Write code so test passes.

Classes: Transaction, ExpenseSheet, ExpenseLine, Money, Party.

Observations:
  • process method in Transaction generates Expense sheet. Has if statements to find out if Party is payer / receiver and then calculate. Smell of Party heirarchy
  • other classes have relatively no behavior.
  • decision: for this requirement its good enuf but when moving to other requirements i will have to wear my refacotring hat before implemetnation
Requirement 2: Same as requirement 1. Except bhavdeep has no share in the expenses. He only paid for it. divided equally between deepak and surender.

Steps: Write junit test method, it fails, then write code to make it pass

Classes: Transaction, ExpenseSheet, ExpenseLine, Money, Party, NonParticipantPayer->Party, Receiver->Party

Observations:
  • Refactored Transaction , Party classes to distribute behavior of ExpenseSheet generation
  • Heirarchy of Party created. Expense lines generation delegated to Party without conditional processing (claps)
  • Transactions for above 2 requirements are equitable and non equitable. But they can change at run time. So I need to use State pattern. Havent done the refactoring. But its necessary though as of now only getEqualParts method has conditional processing. Thus this forms my next refactoring before I move on for the next requirement implementation
  • Add more behavior into money class. Something like 5USd 3 times is 15USD should be done by money class. will make Party expense cacls simpler
Session 2

Current Class Diagram is [Click on the picture to see enlarged]:Posted by Hello

Expense Calculator Started

I have started working on a new self application . I call it Expense Calculator. My intention
is to practice agile techniques: refactoring, unit testing, functional testing, automated builds to be precise.

About the app to be written:
Whenever a few ppl stay togehter there are bound to be shared expenses. This calculator will let you enter your expenses and generate expense sheets detaling the expenses and amount you must pay / receive from others.

About the experiences while writing the app:
I will put my experiences of writing the application in different posts and name them in this format: Expense Calculator Session X. Mainly I will put up a the targets I meet in each session and how the application evolves. Will elucidate them with class diagrams.

I hope this helps not only me but others. At significant intervals, I will also release the code developed.

See : Expense Calculator - Session 1