Child Care Benefit June 09, 2008 02:52 over 3 years ago
Jeg har lige modtaget en java kildefil fra en kollega med ca. 300 linjer. Jeg vil ikke vise den fordi den er alt for verbose eller lowlevel. Der er en main metode og et par metoder med noget dato fis. I teorien skulle klassen kunne beregne børneydelse og er en del af en større skattepakke der er baseret på Magnus og kan beregne både skat og budget.
Det var faktisk noget jeg skulle ha brugt min tid på men min kollega kunne bare ikke gøre for det. Opgaven er jo faktisk sjov når man kan de ret enkelte regler som udgør denne ydelse. Og Java klassen regner rent faktisk korrekt.
Det giver til gengæld mig en god mulighed for at abstrahere lidt over noget kode hvilket jeg synes er sjovt. Der hvor kæden hopper af for mig er mængden af kodelinjer brugt på simple konstruktioner. Fint nok, jeg bruger da koden i det forretningsmodul hvori denne funktionalitet skal være men kan ikke lade være at tænke over de implikationer det har på for eksempel drift, vedligehold, videreudvikling osv.
Hvad betyder det når få og ret enkelt regler bliver implementeret og fragmenteret ud i 300 linjer procedural kode? Ja til at starte med er det jo ikke enkelt mere. Jo jeg medgiver at alle os der arbejder professionelt med Java tendere til at gøre alting mere komplekst end det i virkeligheden er. Selv vores projektledere kan ikke genkende selv simple opgave efter vi har fundet en lille variation af et kendt teknisk problem som vi lige skal løse først, alle opgaver ender med at være Java problemer.
Et andet problem er læsbarhed. Kan jeg i det hele taget forstå koden. Kan koden klassificeres efter kravet om beautyful code (en anden post). Nej, allerede efter ca. 40 linjer gider jeg ikke læse mere. Giver det fremtidige problemer? Ja, for reaktionen er jo at jeg selv vil bygge en helt ny udgave når der kommer en mindre tilføjelse.
Et at de vigtigste objektorienterede principper er genbrug. Men meget få tænker i de baner når de udvikler software. Ofte er undskyldningen at der ikke er tid! Pis, hvis der er tid til dårligt design er der også tid til bedre design.
Hvordan organiseres logiskesammenhørerne sprog konstruktioner? Skal man fokusere på sproget eller på forretningen? Et andet objektorienteret princip omhandler adfærd og måske ville det være nyttigt at bruge de gamle dyder og give objektet mulighed for at løse sine egen opgaver ved at implementer disse egenskaber i klassen selv. Sproget betyder mindre hvis man implementerer efter objektorienteret paradigmer.
Hvis man vil lave god software mener jeg at man må forstå præmisserne om opgaven. En ting som undrede mig var at der i Java koden ikke er brugt datastrukturer til at repræsentere fx, perioder, årgange og kvartaler. Ca. 25% er brugt til simple traversering af dato. Det kan jeg gøre bedre. Faktisk vil jeg definere alle de ting som jeg med sikkerhed ved fra start og binde dem i strukturer.
Et andet sted hvor jeg virkelig kan gøre en forskel er omkring selve algoritmen som beregner de næste 12 måneders børneydelse. Java klassen har defineret 100 linjer til denne metode alene. Først findes de næste 4 kvartaler. Dernæst det ultimative stopkriteriet som er at børneydelsen udløber den dag man fylder 18. Sjovt er det at man begynder først på den 20 i næste kvartal efter fødsel. Til slut er det blot at plukke de respektive beløb.
module Childcontribution
class Calculate_benefits
def initialize(child)
@child = child
@petite_18_teen_birthday = Date.new(y=@child.year+18, m=@child.month, d=@child.day)
@today = Date.today
periods
quarters
ranges
end
def payment_next_12_month
@ydelse = Hash.new(0)
@quarters.each do |quarter|
y = calculate_age(quarter, @child)
if y == 18
if birthday_in_last(quarter)
@ydelse[quarter] = calculate_speacial_case(quarter)
else
@ydelse[quarter] = 0
end
else
@ydelse[quarter] = @ranges[y]
end
end
@ydelse.each_pair do |key, value|
puts "Ydelse pr. #{key} kr. #{value} "
end
amount = 0
@ydelse.values.collect {|value| amount += value }
amount
end
private
def birthday_in_last(quarter)
start = @periods[@periods.rindex(quarter)-1]
is_birthday_in_last = start < @petite_18_teen_birthday && quarter > @petite_18_teen_birthday
end
def calculate_speacial_case(quarter)
start_date = @periods[@periods.rindex(quarter)-1]
puts day_pay = @ranges[@ranges.size-1] / 90 # 2515 / 90
days = @petite_18_teen_birthday - start_date
day_pay * days
end
def calculate_age(quarter, birthday)
(quarter - birthday).to_i / 365
end
def ranges
@ranges = Hash.new(0)
(0..2).each { |n| @ranges[n] = 4039 } # 0-2- Årige
(3..6).each { |n| @ranges[n] = 3198 } # 3-6- Årige
(7..17).each { |n| @ranges[n] = 2516 } # 7-17 Årige
end
def periods
@periods = Array.new()
for y in [2007, 2008, 2009, 2010]
for m in [1, 4, 7, 10]
@periods << Date.new(y=y,m=m,d=20)
end
end
end
def quarters
@quarters = Array.new(0) # Hash.new(0)
for i in 0...@periods.length
if @periods[i] > @today
for n in i...i+=4
@quarters << @periods[n]
end
break
end
end
end
end
end
child = Date.new(y=1991,m=1,d=1)
calc = Childcontribution::Calculate_benefits.new(child)
puts "Next 12 month #{calc.payment_next_12_month}"
By Frank Vilhelmsen - 3 tags: blog java ruby - Add comment