KataArgs

2 views
Skip to first unread message

emilybache

unread,
Jan 21, 2009, 5:46:30 AM1/21/09
to Got.rb
Hej på er,

Jag vet inte om ni kommer ha en Got.Ruby möte snart, men jag undrar om
ni har lust att tackla en ny Kata och även hjälpa mig lite grand?

Jag har nyligen lagt upp en ny kata på codingdojo.org, och även
skrivit en blog post om var det kom ifrån och mina åsikter om Bob
Martin's Java och Ruby lösningar på den.

Jag skulle uppskattar mycket om någon av er läste min blog post och
kan kolla upp att jag har förstått Bob's Ruby kod rätt. Jag är ju
ingen Ruby proffs, och möjligheten finns att jag har gjort bort mig
något fruktansvärt! Jag är även jätteintresserade ifall ni vill prova
katan och kan komma på en annorlunda lösning än det som Bob har gjort.

kata beskrivning - http://codingdojo.org/cgi-bin/wiki.pl?KataArgs
blog post - http://emilybache.blogspot.com/2009/01/kataargs-and-clean-code.html

Mvh
Emily Bache



Carl-Johan Kihlbom

unread,
Jan 21, 2009, 4:13:41 PM1/21/09
to go...@googlegroups.com

Hej Emily!

Låter som ett kul problem! Vi har kört kata de två senaste gångerna,
så nästa möte sitter vi nog bara och snackar. Därefter vore det kul
att sätta tänderna i farbror Bobs kod!

/ CJ

Ivan Navarrete

unread,
Jan 21, 2009, 10:47:47 PM1/21/09
to Got.rb
Hej Emily.

Jag tror att du har förstått ruby koden helt rätt. Själv försökte jag
mig på en lite annorlunda lösning ( http://github.com/crzivn/rubyargs
). Koden har ett par rader där det kanske inte är jättetydligt vad som
händer och dessutom känns lite halvbra, men å andra sidan tog jag bort
metaprogrammeringen vilket underlättar förståelsen något. Var inte
helt övertygad om att den behövdes här. Har inte läst boken du nämner
så vet inte om jag missar någon design-princip.

/Ivan

emilybache

unread,
Jan 28, 2009, 1:50:22 PM1/28/09
to Got.rb
Hej,

Tack för uppmuntran att jag har förstått Bobs kod :-)

Jag tittade lite på din lösning på http://github.com/crzivn/rubyargs.
Det är alltid modig att lägga ut kod man har skrivit, för då får man
feedback på den ;-)

Jag tycker om ganska mycket av vad du har gjort. Till exempel jag
tycker att din dictionary mapping är lika tydlig som Bobs
metaprogrammering, och enklare.

parser.expect('l' => :boolean, 'p' => :number, 'd' => :string, 'g'
=> :list)

Jag tycker också om att du dela upp ARGV strängen till options med en
regexp.

def parse(input)
# join option flags with their values (for easier regexp matching
later):
# ["-a", "123", "-b", "abc", "-c", "-d", "1", "2", "-3", "4"] =>
# ["-a 123", "-b abc", "-c", "-d 1 2 -3 4"]
input = input.join(' ')
options = []
while i = input.rindex(/-[^\d+]/) do
options << input.slice!(i..-1).strip
end

Jag också var inne på en sån lösning med string.split("-"), men
övergav den när jag upptäckt att jag inte enkelt kunde skilja mellan
en flag och en negativ integer. Jag borde verkligen har tänkte då
"regexp" men det är kanske skillnaden mellan en python programmerare
och en ruby programmerare :-) Jag är dock lite osäker om det verkligen
kommer att funka i alla möjliga lägen. Kunde man inte få en regexp
match på fel sak ibland?

Det finns aspekter av din design som jag tycker mindre om, dock.

case filter
when Symbol: value.send(filter)
when Proc: filter.call(value)
else value
end

det känns inte bra att ha en switch statement som behöver skilja
mellan en symbol och en function. Jag tycker man borde kunna fixa det
här utan.

Jag tycker också att du behöver tänka lite på vad som behövs för att
lägga till en ny typ. Just nu behöver man ändra i Args klassen, och
lägga till något mer i OPTIONS tror jag. Det gör din design mindre
tålig för förändring. Fördelen med Bobs är att man kan lägga till nya
typer utan att ändra i befintlig kod. Det är vad menas med "Open
Closed Principle" dina klasser ska vara "open for extension but closed
for modification".

Tack för att du tog tiden att göra katan och även dela med dig av din
kod!

Vi ska tackla denna katan på måndag på våran GothPy möte, så
förhoppningsvis kommer det lite python kod ut på github efter det, och
ni är välkomna att granska och kriticera det med!

Mvh
Emily

Simon Lundström

unread,
Jan 29, 2009, 2:50:16 AM1/29/09
to go...@googlegroups.com
Ett halv-rant-mail men med endel frågor. Jag har inte ens läst kodkatan,
så flamea mig bäst ni kan (om ni vill).

emilybache wrote:
> Hej,
>
> Tack för uppmuntran att jag har förstått Bobs kod :-)
>
> Jag tittade lite på din lösning på http://github.com/crzivn/rubyargs.
> Det är alltid modig att lägga ut kod man har skrivit, för då får man
> feedback på den ;-)
>
> Jag tycker om ganska mycket av vad du har gjort. Till exempel jag
> tycker att din dictionary mapping är lika tydlig som Bobs
> metaprogrammering, och enklare.
>
> parser.expect('l' => :boolean, 'p' => :number, 'd' => :string, 'g'
> => :list)
>
> Jag tycker också om att du dela upp ARGV strängen till options med en
> regexp.
>
> def parse(input)
> # join option flags with their values (for easier regexp matching
> later):
> # ["-a", "123", "-b", "abc", "-c", "-d", "1", "2", "-3", "4"] =>
> # ["-a 123", "-b abc", "-c", "-d 1 2 -3 4"]
> input = input.join(' ')
> options = []
> while i = input.rindex(/-[^\d+]/) do
> options << input.slice!(i..-1).strip
> end

När man gör kodkatas, är det förbjudet att använda (std)libs/gems?
getopts och optparse (plus att det finns fler) skulle ju annars lämpa
sig här.

> Jag också var inne på en sån lösning med string.split("-"), men
> övergav den när jag upptäckt att jag inte enkelt kunde skilja mellan
> en flag och en negativ integer. Jag borde verkligen har tänkte då
> "regexp" men det är kanske skillnaden mellan en python programmerare
> och en ruby programmerare :-) Jag är dock lite osäker om det verkligen
> kommer att funka i alla möjliga lägen. Kunde man inte få en regexp
> match på fel sak ibland?
>
> Det finns aspekter av din design som jag tycker mindre om, dock.
>
> case filter
> when Symbol: value.send(filter)
> when Proc: filter.call(value)
> else value
> end
>
> det känns inte bra att ha en switch statement som behöver skilja
> mellan en symbol och en function. Jag tycker man borde kunna fixa det
> här utan.

Kan du förklara varför det inte känns bra? Vad skulle du använt
istället, if-then-elseif-else?

> Jag tycker också att du behöver tänka lite på vad som behövs för att
> lägga till en ny typ. Just nu behöver man ändra i Args klassen, och
> lägga till något mer i OPTIONS tror jag. Det gör din design mindre
> tålig för förändring. Fördelen med Bobs är att man kan lägga till nya
> typer utan att ändra i befintlig kod. Det är vad menas med "Open
> Closed Principle" dina klasser ska vara "open for extension but closed
> for modification".

"Open Closed Principle" är intressant, aldrig hörttalas om tidigare.

> Tack för att du tog tiden att göra katan och även dela med dig av din
> kod!
>
> Vi ska tackla denna katan på måndag på våran GothPy möte, så
> förhoppningsvis kommer det lite python kod ut på github efter det, och
> ni är välkomna att granska och kriticera det med!
>
> Mvh
> Emily

MVH
- Simon

emilybache

unread,
Jan 29, 2009, 7:24:10 AM1/29/09
to Got.rb
Hej,

Det är inte alls förbjudet att använder standard biblioteken. Pöängen
med den här katan var från början att Bob Martin jobbade i Java (som
kanske inte ha lika bra bibliotek som Ruby) och ville ha något väldigt
enkelt bara, som hantera just det fallet han hade. Så med den här
katan tycker jag visst att man kunde wrappa standard biblioteken på
ett sätt som gör dom enkla att använda för just det här fallet. Jag
har inte sett någon gör det ännu för att lösa katan. Vill du prova?

Med case-statementet som jag inte gillar, jag borde varit mer
specifikt, tack för att du poangtera det. Det luktar för mig som om
man hade kunnat använder sig av polymorphism istället. (page 299 i
"clean code", "Prefer polymorphism to If/Else or Switch/Case") Då
kanske det hade varit lättare att lägga till nya typer i framtiden,
och uppfylla "open closed principle".

Mvh
Emily

Jörgen Lundberg

unread,
Jan 30, 2009, 3:21:57 AM1/30/09
to go...@googlegroups.com
2009/1/29 emilybache <emily...@gmail.com>:

> Med case-statementet som jag inte gillar, jag borde varit mer
> specifikt, tack för att du poangtera det. Det luktar för mig som om
> man hade kunnat använder sig av polymorphism istället. (page 299 i
> "clean code", "Prefer polymorphism to If/Else or Switch/Case")

Switch/Case är djävulens verktyg... :)

/Jörgen

Jonas Nicklas

unread,
Jan 30, 2009, 4:47:27 AM1/30/09
to go...@googlegroups.com
koden i fråga var väl detta:


case filter
  when Symbol: value.send(filter)
  when Proc: filter.call(value)
  else value
end

just i detta fall anser jag det vara okay att använda en case/switch sats. Polymorphism i detta fall hade krävt att lägga till metoder i Ruby's standardbibilioteksklasser (Symbol, Proc), detta tycker jag ska man undvika att göra om det inte är absolut nödvändigt.

Även mycket snyggare här att använda case...when istället för if/else. Man kan se det som att case..when använder sig av polymorphism (det är ju === metoden som anropas på filter).

En liten småkritik dock: att använda kolon efter `when` är deprecated och kommer inte fungera längre i Ruby 1.9. Det är mer framtidssäkert att skriva:


case filter
  when Symbol
    value.send(filter)
  when Proc
    filter.call(value)
  else
    value
end

/Jonas

2009/1/30 Jörgen Lundberg <jorgen....@gmail.com>

Simon Lundström

unread,
Jan 30, 2009, 10:45:52 AM1/30/09
to go...@googlegroups.com
emilybache wrote:
> Hej,
>
> Det är inte alls förbjudet att använder standard biblioteken. Pöängen
> med den här katan var från början att Bob Martin jobbade i Java (som
> kanske inte ha lika bra bibliotek som Ruby) och ville ha något väldigt
> enkelt bara, som hantera just det fallet han hade. Så med den här
> katan tycker jag visst att man kunde wrappa standard biblioteken på
> ett sätt som gör dom enkla att använda för just det här fallet. Jag
> har inte sett någon gör det ännu för att lösa katan. Vill du prova?

Mja, jag önskar jag hade tiden och kunskapen (och intresset ; ) Jag är
ju trots allt bara hobbyprogrammerare, sysadm till jobbet). Annat stjäl
min tid.

> Med case-statementet som jag inte gillar, jag borde varit mer
> specifikt, tack för att du poangtera det. Det luktar för mig som om
> man hade kunnat använder sig av polymorphism istället. (page 299 i
> "clean code", "Prefer polymorphism to If/Else or Switch/Case") Då
> kanske det hade varit lättare att lägga till nya typer i framtiden,
> och uppfylla "open closed principle".

Åhå, bad att få det förklarat för mig av en kompis som är utvecklare, nu
förstår jag vad du menade.


Trevlig helg!

MVH
- Simon

* *

unread,
Feb 2, 2009, 2:18:18 PM2/2/09
to go...@googlegroups.com
Hej Emily. Tack för all feedback.


2009/1/28 emilybache <emily...@gmail.com>

Det borde fungera så länge man inte använder siffror som flaggor eller bokstaver som tal ex. -ff, eller nåt liknande. Givetvis så skulle man skrivit mer testfall i en produktiosapp för att täcka alla möjliga fall.

 


Det finns aspekter av din design som jag tycker mindre om, dock.

case filter
                            when Symbol: value.send(filter)
                            when Proc: filter.call(value)
                            else value
                          end

det känns inte bra att ha en switch statement som behöver skilja
mellan en symbol och en function. Jag tycker man borde kunna fixa det
här utan.

Kanske borde förklara lite mer hur jag tänkte här. Om man vill så skulle man kunna bestämma att alltid ange :filter i OPTIONS arrayen som ett lambda{}. Då skulle man alltid kunna köra  filter.call(value)  om filtret är angivet, och slippa case satsen. Tyckte dock att det var smidigt att även kunna ange filter som en symbol när man vill anropa en redan existerande metod.
 


Jag tycker också att du behöver tänka lite på vad som behövs för att
lägga till en ny typ. Just nu behöver man ändra i Args klassen, och
lägga till något mer i OPTIONS tror jag. Det gör din design mindre
tålig för förändring. Fördelen med Bobs är att man kan lägga till nya
typer utan att ändra i befintlig kod. Det är vad menas med "Open
Closed Principle" dina klasser ska vara "open for extension but closed
for modification".

Det är sant, just nu måste man lägga till nya typer i OPTIONS. Vill man kunna utöka dom dynamiskt så skulle ett sätt kunna vara att lägga dom i en variabel @options och kanske utöka Args klassen med en metod  register_option(option)  som lägger till den nya till dom befintliga.
 


Tack för att du tog tiden att göra katan och även dela med dig av din
kod!

Vi ska tackla denna katan på måndag på våran GothPy möte, så
förhoppningsvis kommer det lite python kod ut på github efter det, och
ni är välkomna att granska och kriticera det med!

Det jag själv tyckte minst om med min kod och något som ingen nämnt ännu är nog att

found = @expected_options.find { ... }

har som sidoeffekt att den uppdaterar @values variabeln. Väldigt ofunktionellt och inte särskilt intuitivt. Kanske la jag för mycket vikt vid att få koden så kort som möjligt.

Sedan så använde jag spec filen för att avgöra när koden var klar. Tittar man på originalbeskrivningen så skulle det finnas vettiga felmeddelanden för varje argumenttyp. Vill man lägga till nya variabler och funktioner till argumenten så är det nog bättre att slå ihop argumentbeskrivningarna till riktiga klasser istället för att kluttra dem med fler komplicerade lambdas (och så slipper man case satsen som du inte gillade).

Ska bli kul att se vad ni kommer fram till på erat möte.

M v h

Ivan

Ivan Navarrete

unread,
Feb 2, 2009, 2:29:48 PM2/2/09
to Got.rb
Intressant, visste inte om detta. Vet inte om jag gillar det dock.
Kolon sparar en del skärmutrymme i de fall då man har små eller längre
fast homogena case satser, utan att för den delen förlora i läsbarhet.
Men det fanns säkert någon bra anledning till varför det togs bort.

/Ivan
Reply all
Reply to author
Forward
0 new messages