Ohjelmistoliiketoiminta. Ohjelmistokehitys. Ohjelmistotuotanto. Näissä aiheissa liikkuu Codenton blogi.

Lue Codenton asiantuntijoiden kommentteja ajankohtaisiin aiheisiin.

Skaalautuviin järjestelmiin kohdistuu muitakin vaatimuksia – skaalautuvuudesta ei hirveästi ole hyötyä ilman hyväksyttävää suorituskykyä ja lisäksi kokonaisuuden pitäisi vielä olla vikasietoinen ja ylläpidettävä. Toisin kuin toiminnalliset vaatimukset, skaalautuvuuden tapaiset ei-toiminnalliset vaatimukset ovat usein käänteisesti riippuvaisia toisistaan. Yhden vaatimuksen naiivi ratkaisu heikentää tai hankaloittaa toisen vaatimuksen saavuttamista.

Palvelimellasi saattaa olla paha olo.

Osittain tästä syystä skaalautuvien järjestelmien rakentaminen on vähän kuin tukkisi vuotavaa patoa sormilla – vuotoja poksahtelee aina vain lisää. Tämä on jo nähty edellisissä tämän sarjan kirjoituksissa:

  1. Yhdessä koneessa toimineen palvelun osajärjestelmät sijoitettiin eri koneisiin.
  2. Webpalvelimesta muodostuu pullonkaula, joka korjataan monistamalla se ja ottamalla LB ja tahmeat istunnot käyttöön.
  3. Tahmeissa istunnoissa on taas ongelmia vikaantumisten ja kuorman tasauksen kanssa, jota korjataan jaetuilla istunnoilla.
  4. Tietokannasta muodostuu pullonkaula, jota korjataan webpalvelimen hajautetulla tai jaetulla välimuistilla.

Epäkonsistentti näkymä

Käsittelin välimuisteja jo aiemmin jolloin rajoittauduttiin yksittäisessä palvelimessa paikallisesti käytettyyn välimuistiin. Paikallinen välimuisti toimii hyvin tilanteissa, joissa suurin osa välimuistissa olevasta tiedosta on vain ja ainoastaan kyseisessä välimuistissa.

Jos käyttäjien kuorma tasataan palvelimien kesken dynaamisesti ja yritetään käyttää vain paikallisia välimuisteja tulee hyvin nopeasti vastaan epäkonsistentin näkymän ongelma. Tällöin  käyttäjä näkee epäkonsistenttia tietoa, koska sitä ei ole päivitetty ajan tasalle kaikkien palvelimien välimuisteihin.

Epäkonsistentti tila voi muodostua välimuisteihin esimerkiksi seuraavasti: 1) Alussa palvelimien välimuistissa on sama tieto. 2) Käyttäjä tekee jotain, joka päivittää palvelimen FE1 paikallista välimuistia. 3) Käyttäjää palvellaan palvelimesta FE2, joka välimuistissa on vanhentunut tieto.

Käyttäjälle tilanne voi olla hämäävä jos hänen toimenpiteillään ei ole näennäistä vaikutusta palvelun tilaan. Palvelun kannalta tilanteessa ei kuitenkaan välttämättä ole mitään vaarallista – vanha välimuistitieto päivittyy ajan kanssa, ja tietokannassa oleva pysyvä tila on myös oikein. Voidaan kuitenkin helposti – vahingossa – rakentaa ratkaisu, joka väärään välimuistin tilaan luottaessaan tekeekin jotain peruuttamatonta, joten epäkonsistentin tilan ongelma koskettaa paljon muutakin kuin sekaantuneita käyttäjiä.

Hajautettu, jaettu välimuisti

Periaatteessa jaettu välimuisti voitaisiin toteuttaa siten, että jokaisessa palvelimessa olisi paikallinen välimuisti, jota pidettäisiin yhteisesti ajan tasalla. Kun yksi palvelin suorittaa päivityksen, se lähettää päivitystiedot myös muille palvelimille jotka päivittävät paikallisen välimuistinsa. Käytännössä näin ei koskaan tehdä, koska se ei skaalaudu.

Toinen tapa on siirtää ongelma “muualle” eli käytännössä levyjärjestelmälle. Jos käytössä on luotettava ja riittävän tehokas jaettu verkkolevy (NAS-ratkaisu) niin mikään ei estä jakamasta levypohjaista välimuistia NFS:llä kaikille koneille. Tämä ei silti ole myöskään yleinen ratkaisu.

Esimerkki kolmeen palvelimeen hajautetusta jaetusta välimuistista. Tässä esimerkissä hajautusalgoritmina on chr(substr(sha1(avain), -1, 1) mod 3, joten uusi arvo "karhukopla" päätyisi cache1:een (indeksi 0).

Eniten käytetty ratkaisu on jakaa kuhunkin välimuistipalvelimeen vain osa kaikista arvoista – tavoitteena tietysti mahdollisimman tasainen jakauma. Jos jokaisesta webipalvelimesta varataan osa kapasiteettia jaetulle välimuistille, skaalautuu välimuistin kapasiteetti palvelinten lukumäärän mukaan. Koska nykyään sekä muisti, että paikallinen verkkokapasiteetti ovat halpaa voidaankin melko “halvalla” rakentaa koko palvelun tarpeita vastaava tarpeeksi iso jaettu muistinvarainen välimuisti. Verkon yli toisen koneen muistista tiedon hakeminen on nopeampaa kuin paikalliselta levyltä!

Oleellista on kuitenkin se, että yhdelle hakuavaimelle tallennettua tietoa haetaan koko klusterissa vain yhdestä paikasta kullakin ajan hetkellä. Kaikki välimuistia käyttävät palvelimet saavat siis saman arvon koska se on niiden näkökulmasta saatavilla vain yhdestä paikasta.

Haasteita

Välimuistien käyttö voi olla ongelmatonta ja kehittäjälle helppoa. Näin on esimerkiksi Hibernaten ja vastaavien ORM:ien kanssa jotka tukevat hajautettuja välimuisteja. Välimuistiin tallennetaan vain oliot – itse relaatiot määritellään edelleen kannasta, tosin niiden koko on paljon pienempi. Kyselyt ja niiden tulokset voidaan sijoittaa myös välimuistiin, joskin sen tehokas hyödyntäminen vaatii jo enemmän työtä kehittäjältä.

Välimuistin käyttö on sovellukselle läpinäkyvää vain jos dataa muokataan yhdessä paikassa. Jos samaa tietoa päivitetään taustalla olevassa tietokannassa useaa eri kautta, pitää tiedon päivittäjien osata invalidoida muiden käyttäjien väärät tiedot. Esimerkiksi viestien määrä palvelussa voi pienentyä käyttäjän toimesta (poistaa viestejä) ja lisääntyä järjestelmän kautta (vastaanottaa viestejä.)

Välimuistit kategorisesti eivät myöskään toteuta transaktioita, joten niistä on turha odottaa ACID-semantiikkaa. Jos teet put/get/get/get sarjan samalle avaimelle, voit saada jokaisella get:llä eri arvon – eikä mikään niistä ole välttämättä se mitä put:lla laitoit. Paljon on siis kiinni siitä, miten ohjelmoija välimuistia käyttää joko suoraan välimuisti-API:n kautta tai epäsuorasti ORM:n tai muun middlewaren kautta.

Jaettu välimuisti ei myöskään aina ole oikea vaihtoehto. Jos datan käyttö on pääasiassa lokalisoitunutta, mutta mukana on silti myös globaalia dataa voi ratkaisuna olla sekoittaa paikallisia ja jaettuja välimuisteja.

Nyrkkisääntö on kuitenkin, ettei suorituskykyistä ja skaalautuvaa verkkopalvelua saa tehtyä ilman välimuistien käyttöä. (Välimuistin sijainnista ja mallista voidaan sitten keskustella paljonkin.)

Välimuistien variantteja

Välimuisteista on paljon erilaisia variantteja seuraavien ominaisuuksien suhteen:

  • Miten ne reagoivat välimuistipalvelimien hallittuun (ylläpidolliseen) lisäämiseen ja poistoon? Jotkut vaativat koko välimuistin tyhjentämistä.
  • Miten ne reagoivat palvelinten kaatumiseen? Jotkin kestävät yhden tai useamman palvelimen kaatumisen hukkaamatta välimuistin arvoja. (Tällöin lähestytään jo hajautettua tietovarastoa…)
  • Ovatko ne muistipohjaisia, levypohjaisia vai molempia? Mitä pidetään muistissa ja mitä levyllä?
  • Käytetäänkö levyä tilapäistilan laajennuksena, vai pysyväistalletukseen? Välimuistin sisältö saatetaan tallettaa pysyvästi, jotta esimerkiksi uudelleenkäynnistyksessä välimuisti saadaan täytettyä nopeasti aiemmilla arvoilla.
  • Mitkä hakuavaimet ylipäänsä on sallittu? Onko mahdollista käyttää binääritietoa (myös NUL-merkki) avaimena?
  • Miten isoja arvoja voidaan tallettaa? Voiko tallettaa vaikkapa isoja kuvatiedostoja?
  • Onko niissä lisäominaisuuksia, kuten atomisia “test-and-set” tai “atomic-increment” operaatioita?
  • Millä perusteella välimuisti valitsee poistettavat (evicted) arvot, jos sen maksimikapasiteetti saavutetaan?

Tunnettuja jaettuja välimuisteja ovat Memcached, Oracle Coherence, Terracotta EHCache ja Windows Azuren AppFabric. Lähempänä hajautettuja tietovarastoja, mutta myös välimuistina käytettäviä ovat redis ja Cassandra.

Seuraavassa osassa käsittelen “perinteisten” tietokantojen skaalaamista.

Linkkejä:

Lueskelin taannoin Jeff Atwoodin blogikirjoitusta siitä, miksi monet ohjelmoijan pestiä hakevat työnhakijat eivät oikeasti osaa ohjelmoida.

Olemme Codentossa aina käyttäneet (relevanteissa) työhaastatteluissa yksinkertaisia ohjelmointitehtäviä. Niistä kertyneen kokemuksen pohjalla minunkin pitää todeta, etteivät yllättävän monet tosiaankaan osaa ohjelmoida, vaan joko takeltelevat tai suoraan epäonnistuvat yksinkertaisissakin tehtävissä. Kuten esimerkiksi, “miten printtaat merkkijonon käänteisessä järjestyksessä käyttämällä vain primitiivirakenteita”:

sub print_reverse ($) {
  my @chars = split '', $_[0];
  for (my $i = @chars - 1; $i >= 0; $i--) {
    print $chars[$i];
  }
}

Kyllä, ihan totta, jotkut eivät onnistu tässä ollenkaan, eivät vaikka saavat valita ihan minkä ohjelmointikielen tahansa, liberaalisti aikaa sekä vihjeitä ja vinkkejä haastattelijoilta.

Aluksi otimme ohjelmointitehtävät mukaan voidaksemme seurata miten haastateltava lähestyisi esitettyä ongelmaa, tarkentaisiko tarvittaessa, mikä on kielipreferenssi jne. Nykyään  ohjelmointitehtävän tärkein merkitys on kuitenkin yksinkertaisesti tiputtaa pois ne jotka joko a) va… kaunistelevat totuutta CV:ssä tai b) ovat käytännön esimerkki Dunning-Krugerin efektistä.

Nykyään ohjelmointitehtävä on yleensä neljännellä portaalla työhaastatteluprosessissamme: CV:n läpikäynti → kahvi/lounas/puhelinkeskustelu → yleishaastattelu → 1. tekninen haastattelu → 2. tekninen haastattelu. Jo nyt, ja tulevaisuudessa entistä pienempi osa meille töihin hakevista on entuudestaan tuttuja, joten haastatteluihin etenevistä on odotettavissa entistä enemmän hylkäyksiä. Jos mitään ei muutettaisi.

Siispä siirrämme ohjelmointitehtävän – ohjelmointikyvyn ollessa relevantti – kokeiluna jo heti CV:n tarkistuksen jälkeen ja tehtäväksi verkossa. Atwoodin kirjoituksen kommenteissa on vinkkejä erilaisista jaetuista editoreista, kuten Etherpad ja Google Docs. Niiden paremmuudesta haastattelukäyttöön emme osaa vielä tietenkään sanoa mitään. Jos jollakulla on omia kokemuksia jaetuista editoreista nimenomaan ohjelmointitehtävissä, niin kirjoittakaa ihmeessä kommentteihin!

Se mitä tästä konkreettisesti toivomme on tietysti tarpeettomiin haastatteluihin käytetyn ajan väheneminen. Aika on rahaa – konsulttibisneksessäkin.

Metodologioiden huumassa unohtuu välillä korkeamman tason ajattelu ohjelmistokehityksestä. Ohjelmiston kirjoittamisen kustannusten (suorien ja epäsuorien) vähentämisen ylivoimaisesti tehokkain tapa on välttää ohjelmiston kirjoittaminen kokonaan.

Otetaan esimerkki: aikanaan Codentossa huomattiin joidenkin työntekijöiden tekevän jatkuvasti ylitöitä. Tätä haluttiin kontrolloida jollakin tavalla, jos ei vähentämällä päivittäisiä tunteja, laittamalla työntekijät kertymän sitä edellyttäessä pitämään vapaapäiviä.

Ohjelmistoyrityksenä Codentolla oli tietty suuri vaara joutua kehittämään oma työajanseurantasovellus, mikä olisi järjetöntä. Oikea tapahan on ostaa valmis sovellus, koska sama ongelma on lähes kaikilla pienyrityksillä, ja hyvä ratkaisu varmasti löytyy markkinoilta.

Vai onko?

Se mitä tosiasiassa tapahtui, oli, että puolen tunnin miettimisen jälkeen toimiston ulko-oven viereen asennettiin whiteboard, joka jaettiin työntekijäkohtaisiin sarakkeisiin sekä kertymä- ja vajausriveihin. Magneettisesta levystä leikattiin numeroita, jotka vastaavat kertymä- ja vajausruuduissa vastaavan tuntimäärän kertymää ja vajausta.

Taulu on käytössä tänäkin päivänä. Yhdellä silmäyksellä näkee, että toimitusjohtaja (jota työaikalaki ei koske) on taas tehnyt järkyttävästi ylitöitä. Muilla plussaa ja miinusta on vähän kohtuullisemmissa määrin. Tiistaina tauluun piti piirtää uusi sarake, kun yrityksessä aloitti uusi työntekijä. Vanhoja sarakkeita kavennettiin vähän, että uusi mahtui. Aikaa meni ehkä minuutti, jonka aikana uusi työntekijä perehdytettiin työajanseurantajärjestelmään.

Ohjelmistojen tarvetta kannattaa aina miettiä toisenkin kerran. Se, että joku tarve on joskus tyydytetty ohjelmistolla, ei ole todiste siitä, että se olisi ollut edes silloin järkevä ratkaisu, puhumattakaan siitä, että se olisi sitä nyt.

En muista onko Codento koskaan päässyt suosittelemaan asiakkaalle softan täysin kirjoittamatta jättämistä, mutta ainakin alkuperäisen vision leikkaaminen kymmenesosaansa on tehty. Voittajia olivat luultavasti kaikki, vaikka laskutusta ei tullutkaan yhtä paljon.

Ohjelmistokehityksessä on joskus tarve sisällyttää toisen projektin lähdekoodi oman projektin versionhallintaan moduulina tavalla jossa muutokset moduuliin voivat liikkua hallitusti molempiin suuntiin oman ja toisen projektin välillä: omassa projektissa voi tehdä muutoksia toisen projektin lähdekoodiin jotka myöhemmin voidaan hallitusti viedä takaisin alkuperäiseen toiseen projektiin, sekä toisen projektin uusia muutoksia voidaan hallitusti tuoda omaan projektiin.

Tämä onnistuu esimerkiksi Git:in alipuuyhdistysstrategialla (engl. subtree merge strategy). Alla sarja komentoja ajettava oman projektin työhakemistossa jolla saa $subtree_url-osoitteessa olevan projektin $subtree_dir-nimiseen alihakemistoon omassa projektissa:

git remote add -f $subtree_repo $subtree_url
git merge -s ours --no-commit $subtree_repo/master
git read-tree --prefix=$subtree_dir/ -u $subtree_repo/master
git commit -m "Merge $subtree_repo as subdirectory."

Tämän jälkeen alihakemistoa voi muokata vapaasti paikallisten tarpeiden mukaan. Muutokset toisesta projektista saa aina tarvittaessa tuotua alihakemistoon seuraavalla komennolla:

git pull -s subtree $subtree_repo master

Mahdolliset paikalliset muutokset yhdistetään tällöin hallitusti toisen projektin muutoksiin. Paikalliset muutokset voidaan vastaavalla tavalla viedä toiseen projektiin käyttämällä samaa alipuuyhdistysstrategiaa toisen projektin puolella koska alipuuyhdistysstrategia tunnistaa itse kumpi puoli on alipuu.

Hyvä puoli alipuuyhdistysstrategiassa on että se ei vaadi lisätoimia oman projektin versionhallintakäyttäjiltä tuodun moduulin suhteen, koska se on sisällytetty omaan projektiin tasavertaisesti oman koodin kanssa. Vertaa Git:in alimoduuleihin (engl. submodules) joka on toinen tapa tuoda ulkopuolisen projektin omaan projektiin, mutta vaatii lisätoimia versionhallinan käyttäjiltä (alimoduulien alustaminen).

Alipuuyhdistysstrategiasta kiinnostuneille Junio Hamanon selitys Git-postituslistalla on hyvä johdanto aiheeseen.

Humppaan itsekseni

Kirjoittanut Otso Kivekäs, 30.7.2010 - 15:58 - 2 vastausta

Softan teko on yleensä ryhmätyötä. Lähes kaikki työn puolesta koodaus tehdään ryhmissä, yleensä 3-10 hengellä, mutta joskus kaksistaan ja toisinaan tolkuttoman suurella porukalla. Harrastekoodauksestakin suuri osa kanavoituu vapaan koodin projekteihin, jotka ovat myös ryhmätyötä, vaikkakin usein kovin erilaista.

Ei siis ole sattumaa, että myös ohjelmistotuotannon prosessimallit on suunniteltu ryhmätyöhön. Itse asiassa niiden ensisijainen tarkoitus on mahdollistaa ryhmätyö. Scrum puhuu suoraan ideaalisti 7 hengestä; XP:n parikoodaus tuskin onnistuu alle 2 hengellä, ja vesiputousmallin alkuperäinen lupaus oli juuri suurten ja todella suurten projektien systemaattinen läpiveto, kun menetelmä skaalautuu ylöspäin. Jonkinlaisena filosofisena taustaoletuksena tässä voi nähdä, että koodaus nyt hoituu yksinkin, mutta kun on tiimi, tarvitaan Prosessi.

No hyvä, kooderi ilman ryhmää on kuin lammas ilman laumaa. Mutta lähes kaikki mielenkiintoinen maailmassa on lähtenyt siitä, että asioita käytetään johonkin mihin niitä ei ole tarkoitettu. miksei siis tässäkin. Eli kuinka taipuu prosessimalli yhdelle hengelle, ja onko siitä iloa?

Keskustelimme hiukan aiheesta toimistolla ja skypessä, ja teimme seuraavia huomioita:

  • Prosessimalleista ei ehkä usein ole iloa sellaisenaan, mutta kokemus niistä on hyödyllistä, koska niiden tavoittelemat asiat (edistymisen seuranta, varmistettu ymmärrys tavoitteista, tavoitteiden päivitys, jne) ovat kuitenkin tarpeen, vaikka ne tehtäisiinkin ad hoc.
  • Monet Scrumin työkalut voivat olla hyödyllisiä, erityisesti backlog
  • Prosessien ylläpito vaatii yksin työskennellessä suurempaa kurinalaisuutta, koska ei ole sosiaalista painetta (ja ehkä koska ne tuntuvat turhilta?)

Arvon ohjelmistotuotannon ammattilaiset ja harrastajat (lue: lukijat), onko teillä kokemuksia prosessimallien käytöstä yhden hengen projekteissa, sellaisenaan tai muokattuna? Millaisia? Mikä toimii ja mikä ei?

Ohjelmistojen kehitystoiminnassa virtuaalikoneiden käytön hyödyt ovat jo laajasti tunnettuja. Kyseessä on kuitenkin usein kehittäjän omassa työpöytäkoneessa ajettava virtualisointiratkaisu (kuin esim. VMware Workstation tai VirtualBox). Nykyään useissa yrityksissä on myös omat keskitetyt virtualisointiympäristöt (esim. VMware vSphere tai avoimeen lähdekoodiin perustuva Eucalyptus), eli eräänlaiset yksityiset pilvet, joissa voi ajaa virtuaalikoneita.

Mitä syitä kehittäjälle on suosia yksityistä pilveä, jos sellaista on tarjolla?

  • Yksityisessä pilvessä on todennäköisesti tehokkaammat laskentaresurssit kuin yksittäisen käyttäjän työpöytäkoneessa: muistimäärä, tallennustila ja laskentakyky on todennäköisesti suurempi yksityisen pilven palvelimissa.
  • Yksityinen pilvi vähentää työpöytäkoneen kuormittumista: kun työpöytäkoneella alkaa olla virtuaalikoneita enemmän kuin pari, se voi tehdä isäntäkäyttöjärjestelmästä niin hitaan, että kehittäjän tuottavuus pienenee kun joutuu odottamaan yksinkertaisiakin operaatioita. Pahimmassa tapauksessa työpöytäkone onnistuu jumittumaan kokonaan, jos vahingossa käynnistää liian monta virtuaalikonetta samanaikaisesti.
  • Yksityisessä pilvessa voi ajaa moninkertaisesti enemmän virtuaalikoneita rinnakkaisesti kuin työpöytäkoneella, jossa kehittäjä on rajoittunut pariin kerrallaan (usein johtuen rajoitetusta muistimäärästä). Yhtäaikainen ajaminen säästää vaivaa ja tehostaa työtä kun ei tarvitse sammuttaa muita koneita käynnistääkseen uuden.
  • Virtuaalikoneet yksityisessä pilvessä jatkavat ajamista myös kun työpöytäkone ei ole käynnissä. Eli ne eivät ole ollenkaan riippuvaisia kehittäjän työpöytäkoneesta. Tämä johtaa myös helpompaan virtuaalikoneiden jakamiseen kehittäjien välissä.

Hyvältä kuulostaa. Onko huonoja puolia?

  • Koska yksityinen pilvi on verkossa, se vaatii verkkoyhteyden kehittäjän työpöytäkoneelta. Pääsy on vaikea kun verkkoyhteys ei ole saatavilla/ei toimi/takkuilee. Lisäksi mahdollisesti ei ole pääsyä yrityksen ulkopuolelta. Vertauksena työpöytäkoneella ajettava virtualisointiratkaisu toimii aina kun työpöytäkoneessa on virtaa.
  • Yksityisen pilven rauta- ja ohjelmistolisenssikustannukset tuovat todennäköisesti huomattavasti suuremman kertamenon, kuin työpöytäympäristöön perustuva virtualisointiratkaisu joka voi maksaa alle sata euroa per käyttäjä.

Mutta jos olet yrityksessä jossa yksityinen pilvi on jo hankittu, ja käytät jo virtualisointia työpöytäkoneellasi: ota ihmeessa yksityisen pilven hyödyt irti myös kehitystyössä.

CCP-virkistyspäivä

Kirjoittanut Otso Kivekäs, 30.6.2010 - 14:18 - 1 vastaus

Viime viikon tiistaina 22.6. vietimme Codenton + CCP:iden ensimmäistä virkistyspäivää. Kaikenlaista häppeninkiä on tullut järjestettyä ennenkin, mutta ei vielä yhtäkään virkistyspäivän nimellä.

Alkuun keskustelimme vähän menneistä ja tulevista projekteista toimistolla. Siinä ei vielä kukaan virkistynyt ihan kauheasti.

Varsinainen virkistymisohjelma olikin sitten kiipeilyä Salmisaaren uudessa kiipeilyarenassa (siellä hiilikasan paikalla). Emme testanneet 30 metrin seinää, jossa pitäisi jo osatakin jotain, vaan tyydyimme ihan 10-metrisiin.

Saimme kaikki kenkää.

Osa meistä hyppi siitä hyvästä seinille.

Onneksi pyöräilyfasiliteetit sentään vastasivat tarpeitamme, joten pääsimme poistumaan hyvässä järjestyksessä.

Tämän jälkeen virkistäytymistä jatkettiin ravintola Persiljassa Lauttasaaressa. Listan pääruuat olivat monet hyviä, pitsat lähinnä peruslaatua.

Raportin viivästymisestä kiitämme Steveä, joka suuressa viisaudessaan päätti ettemme tarvinneet kuvia aiemmin.

Kuvat: Markus Stenberg ja Apple inc., 2010, paitsi viimeinen mun nokiakameralla

PS. Lukeeko blogia kukaan heinäkuussa vai jäädäänkö suosiolla tauolle?

Tutkin huvikseni Javan syntaksin muuttamista niin, että luokkien parametrit (Map<String, Integer>) kirjoitetaan hakasulkeisiin (Map[String, Integer]), niin kuin useimmissa kielissä, jotka eivät ole Java tai C++. Osoittautui ettei LALR(1)-parsereiden tapauksessa muutoksella ole suurta merkitystä parserin kokoon eikä minkäänlaista oikeellisuuden saavutettavuuteen. Puhtaan esteettisesti muutos on jopa voitto, koska sisäkkäisten parametrien yhtaikaisen sulkemisen (Set<Set<Integer>>) yhteydessä lekserin ei tarvitse kikkailla ymmärtääkseen, että kyseessä on kaksi perättäistä >-tokenia eikä yksi >>.

Molemmilla tavoilla jäsennyksen perusongelma on, että samasta jäsennystilasta voi alkaa muuttujaesittely (Set[String] mySet;) tai  taulukkoelementin asetus (set[index] = myValue;). LALR(1)-parserissa ei voi tehdä yhtään reduktiota, ennen kuin on selvillä, minkä jäsennyssäännön mukaan reduktio tulisi tehdä. Ylläolevassa esimerkissä päästään niinkin pitkälle kuin mySet/= ennen kuin tiedetään kummassa tapauksessa ollaan.

Ratkaisu olisi huomattavasti siistimpi, jos LALR-jäsentimen generointia varten kehittäisi vain aavistuksen verran ilmaisuvoimaisemman syötemuodon, joka mahdollistaisi säännöt muotoa A : B C D \ E F, eli lauseke A on lausekkeet B, C ja D peräjälkeen, paitsi jos se on myös lausekkeet E ja F peräjälkeen. Nykyiselläänhän ainakaan Bison ei osaa tätä paitsi-osuutta. Teoriassa tämä olisi toteutettavissa, mutta käytännössä jo Bisonin tasoisen jäsenningeneraattorin implementointi hipoo kontekstiriippumattomien kielien teoriani käytännön soveltamisen äärirajoja, joten en ole varma kannattaako minun edes yrittää. Tämä on kuitenkin tapaus, jossa tarvitaan vain yksi tarpeeksi fiksu tai jääräpäinen ratkaisija, ja lopputuloksesta on iloa monelle.

Jäsentimen ilmaisun yksinkertaisuus (kuitenkin niin, että moniselittelisyyttä ei pääse vuotamaan jostain raosta sisään) on tärkeää siksi, että se mahdollistaa jäsentimien kirjoittamisen myös niille, jotka eivät ole ottaneet teoreettista tietojenkäsittelytiedettä elämäntehtäväkseen. Nykyinen ohjelmistoteollisuus tuntuu kammoksuvan laajennettavia syntakseja — lähinnä koska työkalut niiden toteuttamiseen ovat tällä hetkellä suoraan sanottuna onnettomia. Pidän kuitenkin syntaksin laajennettavuutta yleiskäyttöisessä ohjelmointikielessä toivottavana.

Joskus kauan sitten ohjelmointikielissä ei ollut suoraa syntaktista tukea regexpeille, xml:lle eikä xpathille. Nythän olemme päässeet pois pimeältä keskiajalta, mutta ajatusleikkinä voimme siirtää itsemme sinne takaisin. Tällaisessa tilanteessa, jos ohjelmoija keksii: “hei, tässä voisi käyttää regexpejä” (“now you have two problems”), ja kieli mahdollistaa syntaksin laajentamisen, hän voi miettiä kieleen sopivan syntaksilaajennuksen, jolla regexpien suora esittäminen onnistuu, toteuttaa sen, ja enabloida sen joko siinä modulissa, jossa regexpejä käytetään, tai koko projektissaan, jos niitä on kaikki paikat täynnä.

Tässä on muutama kohta, joissa voidaan mennä pahasti metsään.

Ensinnäkään ei kannata kuvitella, että laajennus tulee automaattisesti käyttöön kaikessa ko. kielen koodissa, jota tiimi ikinä kirjoittaa. Pikemminkin on syytä lähteä uusien laajennusten kanssa liikkeelle pienesti, ja enabloida ne vain siellä missä niitä oikeasti kaivattiin. Kun käytäntö osoittaa, että laajennus on tehty kunnolla, eikä sotke syntaksia muiden asioiden osalta, ja että laajennus on hyödyllinen yleisesti, se tulee yleisempään käyttöön lähes itsestään. Vaihtoehtoisesti, jos ratkaisu osoittautuu kelvottomaksi — ja tapoja on monia, kaikki niistä eivät etukäteen selkeitä — se voidaan haudata hiljaisuudessa, vaikka se jäisikin elämään elävän kuolleen elämää siinä yhdessä projektissa yhdessä tiedostossa, missä se alun perin näki päivänvalon. Eli siis laajennuksen voimassaoloa pitää voida säädellä pitkin projektia. Ei kaikki-tai-ei-mitään-ratkaisuja.

Toiseksi laajennus pitää voida olla kirjoitettavissa normaalilla ohjelmointiponnistelulla. Tässä LALR(1):n kaltainen formalismi auttaa. Ja tämän takia haluaisin nähdä LALR-syötekielien jatkokehitystä, koska pienillä muutoksilla voi oikeassa paikassa olla suuri merkitys.

Kolmanneksi pitää muistaa mitä Fred Brooks sanoi hopealuodeista: niitä ei ole. Syntaksin laajentaminen on ratkaisu harvoin. Se on sitä kuitenkin joskus.

Neljänneksi olisi hyvä, että tietokone pitää huolen siitä, etteivät yhtaikaa käytössä olevat laajennukset tallo toistensa varpaille. Tässäkin LALR(1):n kaltainen formalismi auttaa. Jos kaikki laajennukset on ilmaistu samanlaisina sääntöinä, on koneen helppo laskea mistä tahansa sääntöjoukosta, aiheuttaako niiden yhtaikainen voimassaolo konflikteja.

Vaikka emme enää ole siellä keskiajalla, ja kielemme tukevat regexpejä, on hybristä ajatella, että kielemme ovat täydellisiä, ja mitään laajennustarpeita ei tulevaisuudessa enää ilmene.

Kesäkuun aamiaistilaisuus

Kirjoittanut Santeri Paavolainen, 11.6.2010 - 11:41

Oletko kuullut Codenton aamiaistilaisuuksista? Olettaisin että olet, sen verran yritämme niistä ääntä pitää! Pidimme tällä viikolla kaksi aamiaistilaisuutta, keskiviikkona Turussa ja torstaina Helsingissä.

Helsingissä meillä oli varsinainen supertähti, Amazon Web Services:n Attila Narin puhumassa täydelle salille. Koska Attilan esitystä ei tule katsottavaksi nettiin, yritän tässä kirjoituksessa referoida Attilan esitystä. Huomatkaa, että tulkintavirheet ovat silloin omiani eivätkä edusta Amazonin virallista kantaa!

AWS:ltä on juuri tullut whitepaper Building Fault-Tolerant Applications on AWS (Jeff Barr, Attila Narin), joten ei liene yllätys että Attila käsitteli yleisen AWS:n esittelyn lisäksi nimenomaan vikasietoisia AWS-ratkaisuja.

Ne, jotka tuntevat Amazonin kirjakauppana kannattaa avartaa mieltään: Amazon myy kolmelle eri ryhmälle: kuluttajille, kauppiaille ja kehittäjille. Yhteistä näille kaikille on “high volume, low margin” malli – olivat kyseessä sitten kirjat tai CPU-tunnit.

Ei liene yllättävää, että Amazon toteuttaa samaa mallia myös itse ostajana. AWS:n ratkaisut nojaavat pitkälle massatuotteisiin – infran puolella siis peruspalvelimiin, perusverkkoratkaisuihin jne. Kalliita suurteholaskennan erityisratkaisuja ei AWS:n konesaleista löydy. Amazonin tavoite on toteuttaa järjestelmänsä halvalla raudalla, mutta luotettavasti. Paukut pistetään suunnitteluun ja toteutukseen – ratkaisemaan konkreettisia ongelmia – perinteisen amerikkalaisesti siis tarkoituksena on ratkaista yrityksen rahantuottokoneen ongelmia, ei tehdä itsetarkoituksellista mitään hienoa.

Attila Narin, Solutions Architect for Amazon Web Services

Attilan neuvot skaalautuvien järjestelmien rakentamiseksi ovat monista lähteistä tuttuja, mutta ne on silti syytä kerrata:

  • Tee löyhästi kytkeytyneitä ratkaisuja (loose coupling), käyttäen esimerkiksi asynkronisia viestijonoja.
  • Oleta että kaikki voi vikaantua koska tahansa – jolloin minkään vikaantuminen ei vaikuta lopulta itse palveluun.
  • Tee järjestelmästä elastinen – vältä oletuksia palvelun komponenttien rakenteesta tai määrästä. Elastinen alusta ei takaa elastista palvelua – vaan palvelu on itsessään tehtävä elastiseksi.

Aiemmin mainitusta whitepaperista löytyy neuvoja vikasietoisten palveluiden rakentamisesta, joten ei niistä tässä. Attila antoi esimerkin palveluiden tuotantoonviennistä.

Eli miten tehdä versiopäivitys lennossa ilman palvelukatkoja?

  1. Vanha järjestelmä on toiminnassa, ja se on julkisesti elastic ip:n takana osoitteessa palvelu.esimerkki.com.
  2. Luodaan uusi järjestelmä vanhan rinnalle siten, että sen normaali dynaaminen EC2-IP on nimetty staging.esimerkki.com.
  3. Staging-ympäristöä voidaan testata ja kokeilla betakäyttäjillä uuden rinnalla.
  4. Kun siirto halutaan tehdä, ulkoinen osoite siirretään staging-palvelimelle. Tämä tapahtuu yhdellä käskyllä, jossa elastic ip siirretään palvelimesta toiselle.
  5. Vanha järjestelmä voidaan jättää päälle varmuuden vuoksi joksikin aikaa, mutta lopulta sekin sammutetaan.

Perinteisesti tälläiseen vaihtoon pitää joko partitioida olemassaoleva palvelu, tai pitää varalla toista identtistä palvelinta – tai palvelinklusteria. AWS:ssä päällekkäisiä kustannuksia tulee vain siltä ajalta, kun molemmat järjestelmät ovat rinnakkain käytössä.

Miten sitten mennä pilveen?

“Most important lesson.. start with something small, pick a small number of pilot projects that you start with. Add more complexity [as you get familiar with AWS.]“

“Once you have even one application running more will follow. The first ones usually turn into reference architectures.”

Hyväksi havaittuja neuvoja siis – aloita pienestä, hae kokemusta, kokemusten karttuessa pystyt näkemään miten saat pilvestä suurimman hyödyn omalle liiketoiminnallesi. Teknisellä tasolla käy monesti myös niin, että ensimmäiset toteutukset yrityksen sisällä muodostavat teknologia- ja toimintamallin seuraaville projekteille.

Lopuksi itsestäänselvä puffi Attilalta:

“Amazon relies on its solution providers like Codento to offer professional services.”

Suunnitteletko uutta sovellusta pilveen, tai olemassaolevan siirtoa? Ota yhteyttä AWS:n Suomen Solution Provideriin, eli meihin.

PS. Turun ja Helsingin muut esitykset tulevat parin viikon aikana saataville Codenton nettisivuille, eli odotettavissa on sekä allekirjoittanutta itseään että Joonas Lehtistä (ITMillVaadin) audiovisuaalisesti nautittavana formaattina.

Tietoyhteiskunnan kehittämiskeskus järjesti eBusiness Forum -seminaarin Tallinnassa 26.-27.5. Seminaarin pääpaino oli yritysten välisessä sanomavaihdossa, ja sitä on järjestetty jo parikymmentä vuotta. Ihan rehellisesti sanoen, EDIFACT, INTMOD ja INVOIC91.1 eivät varsinaisesti ole osaamiseni kovaa ydintä, joten en sano niistä enempää. Tänä vuonna ohjelmaa oli kuitenkin laajennettu myös yleisempii ohjelmistokehitsyaiheisiin, etenkin pilvipalveluihin ja ketterään kehitykseen.

Allekirjoittanut oli paikalla puhumassa pilvipalveluista: mitä ne ovat, kuka niitä myy, ja miten niitä käytetään. Aika pitkälti samoja aiheita joita olemme pyöritelleet aamiaistilaisuuksissamme, kalvot löytyvät Tieken sivuilta. Myös Connexorin Pasi Tapanainen kertoi kuinka he ottivat Pilviratkaisut käyttöön muuan osaavan konsultinputkan avustuksella (ette ikinä arvaa kenen).

Codentolaisista paikalla oli myös CCP-partnerimme, Scrum-kuningas Lare Lekman. Laren esitys käsitteli scrumin jalkauttamista organisaatioon ja lisäksi teollista vallankumousta, T-fordeja, Charles Darwinia, tämän kaimaa Chaplinia ja lyijykynien teroittamista. Ketterään esitykseen mahtuu paljon. NSN:n Ran Nyman esitteli Scrumia yleisesti, ja Hanselin Outi Jousi kertoi miten sitä voi käyttää julkisissa kilpailutetuissa hankkeissa, aihe jonka soisi saavan paljon lisää huomiota.

<kuvitelkaa tähän video Laresta osoittamassa ketteryyttään perinteisessä virolaisessa hevosenlänkilimbossa>