minttu / ernu

Programming language
MIT License
2 stars 0 forks source link

Koodikatselmointi #6

Closed olavim closed 9 years ago

olavim commented 9 years ago

Koodi ladattu klo. 15:13, 26.12.2014


Yleensäottaen koodi näyttää mallikkaalta: osat on jaettu asiallisiin luokkiin ja pakkauksiin, eikä nimettömiä ja mitäänsanomattomia metodeja/muuttujia löydy. Useissa kohdissa kuitenkin toivoisi, että 50-100 riviä pitkät metodit olisi jaettu pienempiin metodeihin. Esimerkkinä tästä Tokenizer-luokasta löytynyt tokenize() metodi, jonka 90 rivin sisältä löytyy mm. loputon switch-lauseke. Switch-lauseketta itseään ei tietenkään välttämättä ole edullista yrittää pilkkoa, mutta sen voisi laittaa omaan metodiinsa (esim. handleChar(char c) tms.). Omasta mielestäni olisi myös hyvä idea, että minkään case avainsanan alla ei ole kovin montaa riviä koodia, vaan juurikin yksi metodikutsu ja break;. Toinen missä toivoisin eritoten koodin pilkkomista on CLI luokan parseArguments metodi, joka tuntuu tekevän aika montaa asiaa.

Yleensäottaenkin kaikki epäselvät koodinpätkät olisi hyvä pilkkoa pienempiin, selvempiin koodinpätkiin. Eräs rivin rumilus löytyy ApplyFunction luokan call metodista:

return (new CallNode(node, ((ArrayNode) args).getValues())).getValue(environment);

Tällainen olisi hyvä orjallisesti pilkkoa muutamaan riviin:

List<Node> values = ((ArrayNode) args).getValues();
CallNode node = new CallNode(node, values);
return node.getValue(environment);

En ole tietenkään 100% perillä ohjelman toiminnasta, mutta mielestäni CLI luokan parseArguments metodissa esiintyvät System.exit(1) kutsut voi hyvin vaihtaa pelkkiin returneihin, sillä ohjelma toimii kokoajan yhdessä threadissa, eikä shutdown hookkeja ole missään käytetty. Tämä tuskin vaikuttaa käytännössä mihinkään, mutta mielestäni returnit ovat tyylillisesti parempi vaihtoehto.


Token luokassa equals metodi on korvattu, muttei hashcode. Vaikkei välittömästi tarpeen, voi laajennettavuus kärsiä.


Parser luokan loputon konstruktori saattaisi olla mukavaa jakaa addInfixParsers() ja addPrefixParsers() tms. metodeihin.


Precedence luokan voisi muuttaa enum luokaksi: referenssi.


Kaikki ohjelman ongelmakohdat ovat yllä kuvailtujen tapaisia, eikä niitä ole kuitenkaan loputtomasti. Kuten alussa mainitsin, koodi on esimerkillisesti omissa luokissaan (ja niitähän riittää...), ja jokainen luokka ajaa omaa asiaansa. Ongelmat ovat tiivistetysti pääasiassa metodien sisällä: epäselviä koodinpätkiä, turhan paljon koodia niissä, yms.

Varmasti tulevien refaktorointien edessä nämä pointit kuitenkin. Hyvää työtä näin kaikenkaikkiaan :)

minttu commented 9 years ago

Switchejä voisin pilkkoa tosiaan. Mielestäni inline versio on huomattavasti helpompi lukea, mutta voin kenties pahimmat muuttaa.


Javasta ei saa annettua returncode != 0 ilman exceptioneita ja System.exittiä. Koska exceptioneita ei saisi hirveästi näyttää käyttäjälle tämä on paljon siistimpi tapa. Refaktoroin hieman toisaalta, jotta exceptioneiden nappaaminen on ulkoistettu toiselle metodille.


Ei ollenkaan tarpeen, mutta toteutin silti.


Miten se auttaisi tilannetta että heti konstruktorin jälkeen on kaksi pitkää funktiota jotka tekevät mitä konstruktorissa ennen tehtiin? Pidempi matka konstruktorin alusta oikean koodin alkamiseen jos muuttaa. Kenties tähän on jokin muu ratkaisu mutta ei mielestäni ehdottamasi.


Joudun tekemään matikkaa näillä numeroilla, ei kiitos. Koodi monimutkaistuisi kun pitäisi hyppiä enumin rajoitusten yli. En tarvitse typesafetyä näille ja koko luokan ainut tarkoitus on estää maagisten numeroiden kiertyminen.

olavim commented 9 years ago

Javasta ei saa annettua returncode != 0 ilman exceptioneita ja System.exittiä. Koska exceptioneita ei saisi hirveästi näyttää käyttäjälle tämä on paljon siistimpi tapa. Refaktoroin hieman toisaalta, jotta exceptioneiden nappaaminen on ulkoistettu toiselle metodille.

Aivan, jos komentoriviltä ohjelmaa ajetaan niin tämähän menee niinkuin pitää. En osannut sitä ottaa huomioon (tehnyt niin paljon graafisia softia viimeaikoina...)

Miten se auttaisi tilannetta että heti konstruktorin jälkeen on kaksi pitkää funktiota jotka tekevät mitä konstruktorissa ennen tehtiin? Pidempi matka konstruktorin alusta oikean koodin alkamiseen jos muuttaa. Kenties tähän on jokin muu ratkaisu mutta ei mielestäni ehdottamasi.

Toisaalta lyhyempi matka konstruktorin loppuun. Voisihan tuolle myös jonkinlaisen factoryn luoda... En mää oikeesti tiedä mitä itte ees tekisin ton kanssa; häirittee kun on 50 samannäköstä kutsua.

Vähän eri kantilta, mutta asiaan liittyvä asia tuli mieleen, että prefix- ja infixParserit saattaisi olla hyvä ottaa konstruktorin parametrina vastaan? Tässä tilanteessa prefix- ja infixParserit olisivat ehkä enemmänkin prefix- ja infixRule tms. Tää ratkasis asian tossa Parser luokassa, mutta siirtäis tietty vastuuta alaspäin. Just joku parserRulesetFactory ja sen metodit createDefaultInfixRuleset ja createDefaultPrefixRuleset voisi selkeyttää. Kunhan heittelen. Nää on enemmänki ton "laajennettavuuden" kannalta, ja voi tuntua hölmöiltä kun parsereilla on yleensä se yks tietty tapa toimia. Tällaiten voisi toki samaa koodia käyttää helpommin uudestaan johonkin kuvitteelliseen toiseen parseriin.