oke,
im haskell I see how things are working but pharo is not smalltalk.
So how do you see this in smalltalk.
Roelof
Op 23-12-2020 om 01:29 schreef Richard O'Keefe:
im haskell I see how things are working but pharo is not smalltalk.
So how do you see this in smalltalk.
Roelof
Op 23-12-2020 om 01:29 schreef Richard O'Keefe:
Yes, there is a better way to do it.I found this particular problem at the Programming Praxisweb site, which took it from http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata
This is a superb example of how an informal specificationand a set of test cases can diverge.
The specification says to score a bowling game accordingto a particular set of rules. Here is exactly the algorithmcalled for, written in the functional programming languageHaskell:
score (10:b:c:xs) = b+10+c+(if null xs then 0 else score (b:c:xs))
score (a:b:c:xs) | a+b = 10 = 10+c+(if null xs then 0 else score (c:xs))
score (a:b:xs) = a+b+(if null xs then 0 else score xs)
That's *it*. Explanation, (10:b:c:xs) means "a sequence startingwith 10, followed by something (call it b), followed by something(call it c), followed by the rest of the sequence (call that xs).This is actually strictly statically typed as well.And it shows the while the data are *provided* from first tolast, the score is most easily *computed* from last to first.
Let's remind ourselves of Kent Beck's four rules of good code:1. Runs all the tests
2. Contains no duplication
3. Expresses all the important design intentions
4. Minimizes entities (e.g. classes and methods).
Hence the Extreme Programming slogan"You Ain't Gonna Need It."
Now we come to the divergence between the specification(which calls for #roll: and #score methods)and the tests (which call for a #scoreAfterRolling: methodand then in test 15 calls for #scoreRolling:after:).
There are two kind of test case for this exercise.+ check that the result is correct in a good case- check that the right error is raised given bad data.Now the second kind go far beyond the informalspecification and require not only that certain errorsbe detected but *when* they are detected.
And this is something you have to bear in mind whenwriting down your test cases: you have to prevent ideasyou may have about *how* the code might work creeping intoyour test cases and forcing the code to work that way.Most of my code, and most of the trouble I had writing thecode, was about these "does it report the right error atthe right time and oh yeah I made up these 'right' definitionswith no warrant in the customer's requirements" test cases.
I mean, seriously, NO methods in common between the specificationsand tests?
Returning to Kent Beck's maxims. How many classes do we need?The test code calls for ONE class, "Bowling".There are no tests for any Frame pr Roll classes,and no need for any.How many methods does it need?The test code checks #scoreAfterRolling and #scoreRolling:after:There are not tests for any others.
What state should the instances of the class hold?There is hintYou will need to store some game state.but that applies to the #roll:/#score interface,NOT to the interface that's actually tested.
Use as many classes and methods as you NEED,but remember that you need a lot fewer than you think,
On Mon, 21 Dec 2020 at 23:05, r.wobben--- via Pharo-users <pharo-users@lists.pharo.org> wrote:
Hello,
To come back at this one.
I made a class Bowling and a class Frame which contains two instance variables named firstThrow and secondThrow.
but I still wonder how do I know which one to fill in.
I can do ` (firstThrow nil?) ` but that feels not right.
Is there a more idiomatic solution for this ?
Roelof