An Ad-Hoc Analysis and Fix - in workspace
Object Example
Our system has people (of class Person), who have BinSupplies, which have Bins, which have Parts. Parts can have TransactionParts. When TransactionParts come into the system, each one creates a Part, which is tied back to the TransactionPart. The Part is put in a Bin.
We discovered a Bin with two parts where there should have been one. This indicated that something was wrong. Soon we discovered that something had been done twice that should have been done once, and that there were an unknown number of people in the system who could have the problem. We needed to fix the database. We quickly found how to identify people who could have the problem, and now had to determine which Bins, if any, were affected, and we had to fix them.
We determined that the extra parts would have the identical TransactionPart as the original good one. Our mission (and we decided to accept it) was to identify all Bins exhibiting the problem.
We inspected our way into the Bin that we knew had the problem. Now we wanted to write some code that would show the problem. We decided that since the TransactionParts were identical, we would make an IdentityDictionary by TransactionPart, holding a collection of the parts that had that TransactionPart. If things were bad, some collection would have more than one element. Along the way we realized that we had to consider the Part amount as well, so we added a layer of Dictionary by amount.
We wrote this patch of code to classify the bin:
transDict := Collection identityDictionary. bin partsDo: [ :eachPart | | dateDict amountDict collection | dateDict := transDict at: eachPart transactionPart ifAbsentPut: [Collection dictionary]. amountDict := dateDict at: eachPart effectiveOn ifAbsentPut: [Collection dictionary]. collection := amountDict at: eachPart amount ifAbsentPut: [Collection orderedCollection]. collection add: eachPart].
Followed by this patch to see who had too many parts:
transDict values do: [ :eachDateDict | eachDateDict values do: [ :eachAmountDict | eachAmountDict values do: [ :eachCollection | eachCollection size > 2 ifTrue: [eachCollection do: [ :eachPart | Transcript show: eachPart printString; cr]. Transcript show: '----'; cr]]]
Now this is already pretty complicated. Its not easy to see how the Dictionaries nest, but we were on top of the situation and knew what we were doing (at the time).
OK! Now all we have to do is build this code into a loop over all bins, and build that into a loop over all the identified people. The result (stand back) looks like this:
"to be done in an inspector on the identified Persons" self do: [ :eachPerson | | binSupply printed | printed := false. binSupply := eachPerson binSupply. binSupply corporations do: [ :eachCorp | #(HSEntRawInput) do: [ :eachBinName | | bin transDict dateDict amountDict | bin := binSupply bin: eachBinName corporation: eachCorp. transDict := Collection identityDictionary. bin partsDo: [ :eachPart | | collection | dateDict := transDict at: eachPart transactionPart ifAbsentPut: [Collection dictionary]. amountDict := dateDict at: eachPart effectiveOn ifAbsentPut: [Collection dictionary]. collection := amountDict at: eachPart amount ifAbsentPut: [Collection orderedCollection]. collection add: eachPart]. transDict values do: [ :eachDateDict | eachDateDict values do: [ :eachAmountDict | eachAmountDict values do: [ :eachCollection | eachCollection size > 2 ifTrue: [eachCollection do: [ :eachPart | printed ifFalse: [printed := true. Transcript cr; show: eachPerson messageHeader; cr]. Transcript show: eachPart printString; cr]. Transcript show: '-----'; cr]]]]]]]
We took the above code and saved it as a class method on Person, so we could find it if at some future time we needed to do it all again. We went home for the night.
Note: I think the above is correctly formatted, but to be honest, I'm not sure, between HTML and the complexity of the code itself. In a way, that's the point!
Let's look at a better solution.
© 1997, 1998, Ronald E Jeffries
ronjeffries@acm.org
http://www.xprogramming.com