SANKO-tapahtuma: Funktionaalinen ohjelmointi ja F#

This post is an exception from the English majority of my writings. I will be summarizing the Finnish .NET User Group’s event on F# and functional programming, and will do it in Finnish. In summary, a great event!

Neljäs SANKO-tapahtuma järjestettiin 9.6. ohjelmistoyhtiö Reaktorin tiloissa Helsingin keskustassa. Tuomas Hietanen ja Rami Karjalainen alustivat kertomalla kokemuksiaan funktionaalisesta ohjelmoinnista ja esittelemällä F#-kieltä. Kolmen tunnin tiukan esityksen jälkeen ilta jatkui ruokailulla ja saunomisella. Paikalla oli kokonaisuutena kolmisenkymmentä ihmistä.

imageTuomaksen ja Ramin esitykset voisi tiivistää seuraavasti: He näkivät funktionaalisuuden olennaisena positiivisena trendinä, ja kokivat F#:n erittäin vakavasti otettavana kielenä vähintäänkin liiketoimintalogiikan ja datan toteutukseen. He olivat pitkään tehneet yhdessä vakuutusalan hanketta, jossa F# oli keskeisessä roolissa.

Yleis√∂ss√§ oli vahvaa kiinnostusta aiheeseen, ja Tuomas saikin selitt√§√§ funktioteoriaa ja muita periaatteita varsin pitk√§llisesti. K√§ytt√∂kokemus F#:sta itsest√§√§n oli harvassa, mutta C#:lla funktionaalista ohjelmointia ‚Äď siis LINQ:n tehok√§ytt√∂√§ ‚Äď oli kyll√§ harrastanut monikin. Funktionaalisuutta harjoitellessa F# nousi C#:a suosituimmaksi mm. vahvemman tyyppi-inferenssin (tyyppien automaattinen p√§√§ttely, jolloin koodissa tarvitaan v√§hemm√§n turhaa tyyppien toistelua ja generics-kulmasulkeita) ja interaktiivisuuden takia. K√§ytiinp√§ esitysten lomassa my√∂s keskustelu, jossa pohdittiin testivetoisen kehitt√§misen (TDD) arvoa ja sit√§, onko itseasiassa interaktiiviseen REPL-ty√∂kaluun pohjautuva interaktiivinen kehitysmalli tehokkaampi.

Tuomaksen esitys: kalvot ja esimerkkisovellus

Ramin matskut: kalvot ja koodi

SANKO-toimintaan voit tutustua Facebookissa ja LinkedInissä. F#:lle on myös oma käyttäjäryhmänsä.

Kiitos kaikille osallistujille ja esiintyjille ‚Äď ja tietysti my√∂s Reaktorille sponsoroinnista. Ja hei, Reaktorin l√§sn√§olo .NET-kent√§ll√§ tarkoittaa siis sit√§, ett√§ Suomen parhaana ty√∂paikkana monesti palkittu softatalo on nyt auki my√∂s Microsoft-osaajille. Se on merkitt√§v√§ asia, enk√§ sano t√§t√§ vain siksi, ett√§ sain hyv√§√§ ruokaa. :-)

Be Sociable, Share!

June 26, 2011 ¬∑ Jouni Heikniemi ¬∑ 167 Comments
Tags: ,  ¬∑ Posted in: General

167 Responses

  1. Vakuutusmies - December 16, 2011

    Hmm, mielenkiintoista. Tiedän, että eräässä paikassa jossa Tuomas ja Rami tekivät yhteistyötä C#'a, mutta F#'sta en ole kuullut mitään. Samoin olen kuullut, että samaisessa paikassa nämä C#-osuudetkin olisi myöhemmin korvattu Javalla.

  2. Minäkin olen anonyymi - December 16, 2011

    Tuskin vanhoja koodeja niin vaan korvataan Javalla? Moni firma käyttänee yhä vanhaa Microsoft CMS:ää tai Moss:ia.

    Mutta itse asiassa olen kuullut, että tehoton Java-kehitys on ajanut monta firmaa ihan yt-neuvotteluihin asti.

  3. Vakuutusmies - December 18, 2011

    Aika hyvä vastaveto sinällään ;-)

    Erityisen tehottomaksi Java-kehitys tulee, kun joku saa päähänsä toteuttaa asioita Javalla funktionaaluuden mekanismein. Tästä olkoon esimerkkinä esimerkiksi löytämäni häntärekursiolla toteutettu listan muutos merkkijonoksi. Aika säälittävä veto; koodia ei ymmärrä, se on tehotonta (mm sen takia, että lista kopioitiin ensin linked list'iksi), useimmat JVM:t eivät edes tue häntärekursiota ja ko. toiminnallisuus menee Javalla ilman kikkailuja yhdellä rivillä.

    Oletteko muuten huomanneet sellaista trendiä, että kun vielä elokuussa F# oli TIOBE:n listalla sijalla 19, niin nyt joulukuussa se olikin listalla vasta sijalla 36? Ei taida olla toi funktionaalisuus oikein joulupukin mieleen.

  4. Vakuutusmies - December 21, 2011

    Katselin vähän Microsoft-puolen koodikantaa, ja hämmästyksekseni siellä toden totta on kuin onkin F#-koodia. En oikein ymmärrä miten tämä on mahdollista, sillä F#'n käyttö ei ole, ei ole koskaan ollutkaan, eikä hyvin todennäköisesti koskaan tule olemaankaan Tieto-Tapiolan linjausten mukaista. Toisaalta taas näiden koodien osuutta voidaan pitää lähestulkoon samana kuin jos vertaisi nuppineulan päätä maapallon kokoon. Näitä koodeja katsellessani on vaikea ymmärtää miksi ne on tehty F#:lla. Esimerkiksi propertyjen asettaminen F#:ssa, esim
    req.ContentType <- "application/json";
    sisältää enemmän merkkejä kuin sama asia C#:lla (req.ContentType = "application/json";). Muutenkin koko koodissa ei ollut yhtään mitään mikä olisi puoltanut F#:n käyttöä.

    No, joka tapauksessa voin kuitenkin luvata, että kyllä vain nämä vähätkin tekeleet siirtyvät historiaan kovinkin pian, joten toivon ettei ainakaan Tapiolaa käytetä F#-referenssinä, ei nyt eikä tulevaisuudessa.

    Noin yleensäkin olen kovasti epäileväinen, että onko näillä uusilla funktionaalisilla kielillä (F#, Scala, ..) Suomessa toteutettu mitään sählyvuoron varausjärjestelmää vakavampaa (riippumatta siis siitä, onko kyseessä pankki, pörssi, tms). Ja huom, C# ei ollut edellisessä listassa. Ja kun jotkut puhuvat funktionaalisuudesta uutena, käänteentekevänä ilmiönä, niin saanen olla hieman eri mieltä. Esimerkiksi LISP (jonka jotkut lukevat funktionaaliseksi ja jotkut eivät) on ollut olemassa jo jonkin aikaa, rli vuodesta 1958, ja siitä ei ole ikinä kuitenkaan tullut valtavirran kieltä. Se oli esim. TIOBE:n listan mukaan joulukuussa 1986 sijalla 2 ja nyt sijalla 13. Trendi on hitaasti, mutta varmasti laskeva. Siitäkin huolimatta LISP-kommuunilta kysyttäessä LISP:n totalitäärinen maailman valloitus on aivan nurkan takana, ollut jo ainakin viimeiset 40 vuotta.

    Koen sanojen ja aaltosulkeiden laskemisen lähinnä surkuhupaisaksi. Jos puhutaan mistään firman sisäisen sählyvuoron varausjärjestelmää vakavammasta sovelluksesta, olisi kovasti toivottavaa, että järjestelmä suunniteltaisiin. Suunnittelu taas oikein tehtynä pakottaa suunnittelemaan ja kuvaamaan asioita. Tähän se aika menee ja koodin "puhtaaksi" kirjoittaminen on lähinnä liukuhihnahommaa. Olen todistanut montaa tapausta, missä on ketterästi lähdetty ilman suunnittelua liikkeelle. Kaikissa näissä yhteinen tekijä on se, että asiat tehdään monta kertaa ja päällekkäisen työn tekeminen on pikemminkin sääntö kuin poikkeus.

    Ja viimeiseksi vielä sellainen juttu, että vaikka teksteistäni saattaisi luulla minun olevan suurikin .NET:in vihaaja, niin näin ei suinkaan ole. Ja mitä tulee ohjelmointikieliin, niin itse pidä esimerkiksi C#:n ominaisuuksista huomattavasti enemmän kuin Javasta. Siitä huolimatta teen lähes kaiken Javalla, eikä minun tarvitse puhkua siitä, että on olemassa muita, parempia ohjelmointikieliä. Java on riittävän hyvä ja sen osaajia on paljon (ollut jo monta vuotta #1), mutta sen ei tarvitse olla paras. Javaan on tulossa lambdat (samalla syntaksilla mitä on C#:ssa), mikä on hienoa, mutta toisaalta samalla vaikeutetaan kieltä ja osa osaajista putoaa taas pois. Ja niille tyypeille jotka juoksevat sen ultimaattuminen perässä koko ajan voi vinkata, että opettelisivat esimerkiksi nyt sitten vaikka sen C#:n/Javan kunnolla, erityisesti platformin valmiit palvelut sekä C#/Javan muistimallin, jonka osaajia tuntuu olevan kovin harvassa. Ja syynä tähän ei ole se, että C#/Javan muistimalli olisi niin mahdottoman vaikea, vaan ylimielisyys asiaa kohtaan. Eli toivonkin, että myös alan uusilla tulokkailla olisi sen verran kunnioitusta, että selvittäisivät edes perusasiat (esim. mikä ero on linked listalla ja arraylistalla, miksi myös muuttujan luku pitää synkronoida tai mikä on volatile) ennen kuin alkavat paukuttelemaan henkseleitään.

    ei-toiminnallista, eli rauhaisaa, Joulua kaikille,

    Paci "Vakuutusmies" Salminen
    Johtava IT-arkkitehti
    Tieto-Tapiola Oy

  5. Tuomas Hietanen - December 21, 2011

    Moi Pasi,

    Microsoftin .NET-ympäristössä on jo useamman vuoden ollut kolme virallista kieltä: VB/C#/F#.

    Käännettyinä nämä näyttävät kaikki dll:iltä. Jos haluaa tutkailla käännöksiä tarkemmin, niin Microsoftin .NET:ille on erilaisia työkaluja kuten Reflector/ILSpy. Ensimmäisellä voit vaikka halutessasi konvertoida koodin lähdekieleltä toiselle.

    F# on ollut tuossa tapauksessa luonnollinen valinta, ei siksi, että se on uusi ja funktionaalinen, vaan siksi, että sillä syntyy .NET-ympäristön helpoin, selkein ja ylläpidettävin koodi myös perus-olio-ohjelmoinnissa.

    Toden näköisesti ymmärrät täysin koodia alle 2 tunnin perehtymisellä. Silloin kun koodi on tehty, niin meillä oli tiimissä neljä kehittäjää, jotka osasivat kirjoittaa kyseistä .NET-kieltä, kaksi firman omaa ja kaksi konsulttia (minä, Jari, Jaakko, Rami), ja tämän lisäksi ylläpidettävyyden näkökulmasta muutkin olivat motivoituneita opettelemaan kyseisen kielen (esim. Juho).

    Itse olen osaltani pitänyt huolen siitä, että tehty koodi on tuotettu pieninä selkeinä irrallisina kokonaisuuksina, eli se on helppo korvata tarvittaessa. Lisäksi koodi on täysin sivuvaikutuksetonta, ja bugitonta (minkä puolesta puhuu sekin, että koodi ei ole vaatinut vuosiin päivityksiä).

    Rauhallista joulua myös sinne Tapiolan suunnalle!

    T: Tuomas

  6. Tuomas Hietanen - December 21, 2011

    Vielä kommentti tuohon maapallo-vs-nuppineula vertaukseen:

    En ole ollenkaan vakuuttunut, että softan pitäisi ikinä olla maapallon kokoinen. Mulle riittää ne pienet nuppineulat. Tässäkin tapauksessa nuppineulan toimivuus näkyy kuitenkin useammalle tuhannelle käyttäjälle päivässä. Parempi, että koodi on laadukasta, ja tekee vain sen mitä pitää, eikä hoida kaikkia maapallon asioita.

  7. F#-koodaaja - December 21, 2011

    Merkkejä on yhtä monta, sillä F#:ssa ei ole puolipistettä:

    req.ContentType <- "application/json"
    req.ContentType = "application/json";

    Ja itse asiassa F# 3.0:ssa on vielä tulossa auto-propertyt, jolla tälläinen turha propertyjen-asettelu-koodi poistuu kokonaan.

  8. Vakuutusmies - December 22, 2011

    Hyvä F#-koodaaja,

    Jos asia on näin, niin sitten voit vääntää tästä asiasta peistä varmaankin Tuomaksen kanssa, sillä tuo näyttämäni pätkä on suoraan siellä sorsakoodissa. Minähän en osaa ko. kieltä enkä ole sitä aikonut opetellakaan. Ja muista toki katsoa toki myös kommenttini niistä sanoista ja aaltosulkeista. Kirjainten laskeminen on niin turhaa hommaa kun vaan olla voi. En ihan osta sitä, että syntaksin osuus olisi yleensäkin jotenkin kovin merkityksellinen, etenkin jos tehdään mitään lottopallojen arvontaa merkityksellisempää. Esimerkiksi Javaan on tulossa helpostusta generics-tyyppien esittelyyn ja luontiin, ja ihan kiva niin, mutta ei ole koskaan tullut mieleen sanoa, että homma venähtää sen takia, että on niin paljon -merkkejä kirjoitettavana. Ja mihin niitä settereitä edes funktionaalisessa ohjelmoinnissa tarvitaan kun kaikki on vaan funktioita ja immutableja? Jos on olioita ikävä, niin niitähän on vaikka siellä C#:ssakin läjäpäin. Erona vaan on se, että C#-osaajia löytyy läjäpäin. On sitten todennäköisesti niitä ;-merkkejäkin vain niissä kohtaa kun pitää ;-)

    Ja sitten tuohon auto-property'yn. Mitenköhän F# osaa automaagisesti asettaa property'yn ContentType vaikkapa vakion application/json? Tai jossain tapauksissa ehkä arvoon application/xml. Ja koska auto-property siis ilmeisesti osaa myös auto-asetuksen, niin luonnollisesti minun ei tarvitse kertoa missä tapauksessa sinne laitetaan mikin arvo. Jos kyseessä on vakio, niin sehän ei sitten visiinkään ole ainakaan ihan uusi keksintö ohjelmointikielissä. Jos on tosiaan niin, että F# osaa automaattisesti hoitaa asetukset ilman ohjelmointia, niin sittenhän kaikki oikeat arvot löytävät paikkansa ilman, että minun pitää tehdä mitään. Nyt F# alkaakin kuulostaa todella houkuttelevalta ;-)

  9. Vakuutusmies - December 22, 2011

    Korjaus edelliseen, paljon -merkkejä välistä puuttuu pienempikuin ja suurempikuin merkit. Palvelinpää näköjään sensuroi ne pois.

  10. Trolli - December 22, 2011

    http://www.youtube.com/watch?v=ekLttYTeCR8

  11. Vakuutusmies - December 22, 2011

    Hei F#-gurut,

    Kertokaapa mikä hienous on auto implemented propertyllä. Mitä järkeä on siinä, että saan automaattisesti getterin ja setterin jotka eivät tee mitään? Eli mikä on suuri ero verrattuna siihen, että olisi vaan public attribuutti? Ainoa asia mitä itse pystyn päättelemään on se, että sallitaan pelkkä get.

  12. Vakuutusmies - December 22, 2011

    Jep jep, Make sanoi mulle pahasti ;-)

    Yritän tässä vähän samalla saada kriittistä keskustelua aikaiseksi, kun siellä SANKO-tapahtumassa hyvin todennäköisesti oli valtava yksimielisyys siitä, että tämä funktionaalisuus ja F# on hyvä, tai pikemminkin paras. Jos ei ollut, niin hyvä. Haluan hämmentää myös tätä asiaa sen takia, että kun esimerkiksi tietoviikossa kehutaan kuinka vaikkapa "Scala tarvitsee noin puolet javan rivimäärästä". Hoh hoijaa. Kenenhän Java-taitojen mukaan tämä on laskettu? Lieneekö ehkä vertailukohtana jo legendaksi muodostunut häntärekursiolla toteutettu listan merkkijonoksi muuttaminen? Noita lehtiä, esim Tietoviikkoa, lukevat myös jotkut tietotekniikkayhtiöiden johtajat, ja jotkut heistä saattavat kummastella kovasti mistä tässä "käänteentekevässä hopealuodissa" oikein on kysymys.

  13. Jouni Heikniemi - December 22, 2011

    Kiitos minun puolestani mielenkiintoisesta keskustelusta. Hyvin poikkeuksellista dialogia puolin ja toisin.

    Kesän SANKO-tilaisuudessa ei mitenkään mielestäni koettu F#:ia miksikään täydellisyyden huipentumaksi, joskin toki 30 kuulijalla on varmaan se 30 eri mielipidettä. Enemmänkin keskustelu kulki sillä akselilla, mitä F#:n tarjoamat edut (esim. vahva tyyppi-inferenssi ja joiltain osin kompaktimpi syntaksi) tuovat lisää C#:n tarjoamien vahvojen funktionaalisten välineiden päälle.

    Mielestäni _funktionaalinen ajattelu_ itsessään on hyvä työkalu kenen tahansa ohjelmoijan työkalupakkiin. Jos kielessä ja kirjastoissa on vahva tuki funktionaalisille rakenteille (esim. C#:n LINQ), aina parempi.

    Ehkä keskeisin Tuomakselle ja Ramille heitetty haaste kesäkuun tilaisuudessa oli demonstroida se, miten hyvä F# tekee maailman paremmaksi hyvään C#:iin verrattuna. Tästä demosta en itse vielä ainakaan vakuuttunut (= lue: vaikka C#:ni on hyvin funktionaalista, en ole tarttunut F#:iin).

    Toisaalta asetelma on sikäli perusteeton, että miksipä välttämättä F#:ia, joka itsessään on ihan arvokas ja täysivoimainen ohjelmointikieli, täytyisi verrata nimenomaan C#:iin? Kuten Tuomas perustellusti totesi, molemmat ovat täysiverisiä .NET-kieliä, eikä F#:lla tehty softa sinänsä C#:ia huonompi ole. Ekosysteemikysymykset ovat toki sitten eri asia Рkyllähän F#-osaamisen huonompi saatavuus kiistatta on tällä hetkellä ongelma.

  14. Vakuutusmies - December 22, 2011

    Asiallinen kommentti.

    Kuten jo mainitsinkin, itse pidän hyvänä asiana, että Javaankin rantautuu jonkin verran näitä piirteitä. Moni on toistakin mieltä asiasta, mutta itse suurena anonyymien luokkien ystävänä saan tällä pienennettyä nimenomaan sitä turhaa "noisea", joita anonyymin luokan tekeminen Javassa todellakin on.

    BTW, Vakuutusmies edustaa minua itseäni, ei "työminääni"

  15. Mika Kolari - December 22, 2011

    Vakuutusmies,

    En tiedä F#:sta, mutta C#:ssa propertyt voivat olla myös abstrakteja tai virtuaalisia, toisin kuin kentät. Lisäksi automaattisten propertyjen kirjoittaminen on niin nopeaa eivätkä ne tee koodista yhtään vaikeammin ymmärrettävää tai monimutkaisempaa, joten en näkisi mitään syytä olla käyttämättä niitä.

    Itseäni ihmetyttää miten funktionaalinen ohjelmointi istuu sellaiseen sovellukseen, jossa ylläpidetään tietoja. Eikö se sotisi tilaton/immutable -ajatusmaailmaa vastaan? Siis jos vaikka lomakkeelta saadaan useita tietoja ja useampi pitää validoida eikä muutoksia saa tallentaa, jos yksikin tieto on virheellinen.

  16. Vakuutusmies - December 22, 2011

    Alrighty,

    Jos teen automaattisen propertyn näin

    public string Name { get; set; }

    niin mikä ero siinä on tämän kanssa

    public String Name;

    Jos unohdetaan, että nyt ko. kikkareella on property eikä vaan public field, en näe tässä mitään kovin ihmeellistä. Kapseloinnin kannalta tällä ei ole mitään tekemistä, sillä eihän "automatiikka" kontrolloi get että set metodeja mitenkään. Kaikki stringit menevät sisään heittämällä. Ja itselläni ei ainakaan kovin usein ole tullut tilannetta jossa tarvitsisin abstrakteja accessoreita. En sano, että ne olisivat hyödyttömiä, mutta eipä ole tullut paljon käytettyä. On tullut ratkaistua asiat aina jotenkin toisin.

  17. Torvi (totuuden) - December 22, 2011

    Keskustelu onkin mennyt oleelliseen suuntaan funktionaalisen ohjelmoinnin näkökulmasta, kun keskustellaan propertyt vs. public fieldit. Ehdotan keskustelun laajentamista for vs while -looppeihin, jotta mennään varmasti oikeaan suuntaan. Huoh.

    F# on oliokielikin, joo… mutta ennen kaikkea sen "hyvyys" perustuu funktioparadigmaan. Suurin hy√∂ty olioihin saadaan siit√§, ett√§ F#:ssa immutable olion luominen on default toisin kuin C#/Java, jossa se on helvetillist√§ boilerplatea.

    Funktionaalisessa ohjelmoinnissa ei muutenkaan usein käytetä olioita (puhtaissa funktiokielissä ei niitä edes ole) vaan esim. tuple ja record ovat tietorakenteina käytössä. F#:ssa niiden käyttöä puoltaa structual equalityn saaminen kääntäjältä, jolloin Javassa ja C#:ssa yhtenevä equals/hashcode peeloilu jää pois.

  18. Mika Kolari - December 22, 2011

    Tuollaisessa tapauksessa ei ole eroja. Yleensä YAGNI on hyvä periaate, mutta propertyjen tapauksessa "over engineering" (mitä jos haluankin myöhemmin periä tämän luokan ja ylikirjoittaa propertyn tms.) ei maksa mitään.

    Propertyillä saa ikään kuin enemmän samalla vaivalla.

  19. Lauri Kotilainen - December 22, 2011

    Asian vierestä, mutta olkoon:

    Autopropertyjen pointti lienee se, ett√§ jos getteriin tai setteriin haluaa my√∂hemmin lis√§t√§ logiikkaa, sen voi tehd√§ rikkomatta bin√§√§rirajapintaa — senkun muuttaa autopropertyn tavalliseksi ja kirjoittaa accessorit auki. L√§hinn√§ kyse on siis API/ABI-n√§k√∂kulmasta, joka sin√§ns√§ koskee l√§hinn√§ niit√§, jotka shippaavat muiden k√§ytt√∂√∂n bin√§√§rej√§ l√§hdekoodien sijaan.

    Toki virtuaalinen getteri/setteri on myös yksi vinkkeli, mutta sellainen jota pitäisin vähän vähemmän tyypillisenä.

  20. Lauri Kotilainen - December 22, 2011

    Aiheeseen liittyvää keskustelua .NET-tiimiläiseltä ajalta ennen autopropertyja: http://blogs.msdn.com/b/ericgu/archive/2007/02/01/properties-vs-public-fields-redux.aspx

    "to put it another way, I rank the ability to version easily higher than the cost of the extra clutter in the class and increased size of the assembly that comes from the property.

    But, if the clients of a class are always compiled together with a class – or at least shipped together – then there is no versioning issue to consider. In that case, I think it's a bad idea to write the "trivial property" – all you've done is complicate your code without any benefit. If the public field you write needs to be a property, then just make the change and recompile."

  21. Tuomas Hietanen - December 22, 2011

    Jouni, kiitos hyvästä kommentista.

    Kuitenkin, "Ehkä keskeisin Tuomakselle ja Ramille heitetty haaste kesäkuun tilaisuudessa oli demonstroida se, miten hyvä F# tekee maailman paremmaksi hyvään C#:iin verrattuna."

    Jos kohteena on 30kpl noin 5-10 vuotta C#:lla tehnyttä Suomen-tasolla-alan-huippua, niin on turha olettaa tuollaista haastetta parin tunnin sessiolta.

    Pikemminkin, tärkeämpää rohkaista ihmisiä testaamaan heille uusia asioita, ja sitä kautta auttaa heitä löytämään itse sen oman paremman maailmansa.

    Oma parempi maailma kyllä sitten löytyy, jos on löytyäkseen.
    Se voi olla esim. bugittomuus, selkeä lähdekoodi, suurempi ilmaisuvoima, tai vaikka vain se, että huomaa, että pitkästä aikaa koodaaminen on taas kivaa.

  22. F#-koodaaja - December 22, 2011

    Propertyn ja luokkamuuttujan ero on, että
    voin rajoittaa käyttöoikeuksia, esim:

    public string Name { get; private set; }

    Pari esimerkkiä olio-ohjelmoinnista, mikäli blogi suo:

    —-
    // C#, klassinen:
    public class Tyyppi{
    private readonly string arvo;
    public object Arvo{
    private set {
    arvo=value;
    }
    public get {
    return arvo;
    }
    }
    public Tyyppi(object par){
    Arvo = par;
    }
    }

    —-

    // vastaava F# (2.0 ja 3.0):
    type Tyyppi(par) =
    member x.Arvo = par

    —-

    Käytännön C#: Auto-propertyillä, ja helppouden takia joustetaan immutableista:

    public class Tyyppi{
    public object Arvo{ get; set; }

    public Tyyppi(object par){
    Arvo = par;
    }
    }

    —-

    // Taas, vastaava F# 3.0 auto-propertyllä, ei-immutable:
    type Tyyppi(par) =
    member val Arvo = par

    —-

  23. Koodain - December 22, 2011

    Alkuun muutama lainaus:
    Heikniemi: "He olivat pitkään tehneet yhdessä vakuutusalan hanketta, jossa F# oli keskeisessä roolissa."
    Vakuutusmies: "En oikein ymmärrä miten tämä on mahdollista, sillä F#'n käyttö ei ole, ei ole koskaan ollutkaan, eikä hyvin todennäköisesti koskaan tule olemaankaan Tieto-Tapiolan linjausten mukaista."

    Eikö ketään oikeasti ihmetytä miksi tämä F#-koodi on alunperinkään edes ilmestynyt tuonne keskeiseen koodipohjaan?

    Mitä tulee funktionaaliseen ohjelmointiin, niin mikä onkaan se ongelma minkä se ratkaisee?

  24. Mitä koodailet? - December 22, 2011

    Ehkä se on ilmestynyt ratkaisemaan jonkun ongelman.

    Funktionaalinen ohjelmointi perustuu matematiikkaan.
    Mikä onkaan se ongelma, minkä matematiikka ratkaisee?
    Ehkä kaikki maailman ongelmat?
    Mitä tekee olio-ohjelmoinnilla, ilman toiminnallisuutta, puhtailla luokilla ilman metodeja?

  25. Koodain - December 22, 2011

    Ylimieliset vastaukset eivät varsinaisesti ole sitä mitä haen, mutta ehkä siitäkin on jotakin pääteltävissä.

  26. Torvi (totuuden) - December 23, 2011

    Koodain,

    Millaisia vastauksia tarkkaan ottaen oletit saavasi kysymyksiin jotka olivat hmm… "mielenkiintoisia"?

    Ensimmäiseen kysymykseen Tuomas vastasi vakuutusmiehen kommentin jälkeen. Toiseen kysymykseen sait hyvän ja kattavan vastauksen Mitä koodailet? nimimerkiltä.

    Yhtä hyvin voisit kysyä että mikä on onkaan se ongelma jonka ohjelmointi ratkaisee. Funktionaalinen ohjemointi ei ole mitään salatiedettä tai voodoota, jota tehdään tietokoneiden sijaan pimeissä luolissa uhrieläimillä. Lisäksi mitä tulee F#:iin, se on hybridikieli, jolla voidaan tehdä funktionaalisen ohjelmoinnin lisäksi olioparadigman mukaista koodia (ja vieläpä imperatiivistakin).

    Suosittelen aloittamaan funktionaaliseen ohjelmointiin tutustumisen jostain muualta kuin tästä blogista. Pääset nopeammin vauhtiin.

  27. Vakuutusmies - December 23, 2011

    On totta, että funktionaalisuuden keskustelusta on menty kauas. Syy tähän on se, että hyvin usein, jos ei aina, näissä keskusteluissa vedotaan siihen täysin turhaan seikkaan, että funktionaalisessa ohjelmoinnissa kirjoitettavien merkkien määrä on pienempi. Kuten jo aikaisemmin mainitsinkin, niin harvoin on nähty niitä projekteja, joissa aikataulun venyminen johtuu siitä, että aaltosulkuja tai sanoja on liian paljon. Mutta back to business sitten.

    Katsotaanpa vaikka tästä TIOBE:n pitkän ajan trendiä ja tsekataan siitä miten funktionaaliset kielet ovat pärjänneet vuosien saatossa.

    Object-Oriented Languages 56.6% -0.5%
    Procedural Languages 37.0% -0.9%
    Functional Languages 4.4% +0.9%
    Logical Languages 2.0% +0.5%

    Muistinko jo sanoa, että esim LISP on siis yli 50 vuotta vanha jo, joten ihan täysin uudesta paradigmasta ei enää voitane puhua. Mitä tästä sitten voi päätellä? No sitä, että ehkäpä suurin osa ohjelmoijista ei olekaan sitä mieltä, että funktionaalisuus on hyvä ratkaisu yhtään mihinkään. Tai sitten siitä voidaan päätellä sitä, että kaikki ohjelmoijat eivät olekaan matemaatikkoja. Ja miksi pitäisikään? Kun katsotaan mitkä kielet siellä on kärjessä, niin jostakin kumman syystä oliokielet on aika vahvoilla ja ovat olleet jo hyvin monta vuotta. Ja nyt ei kannata sitten funktionaalisuuden kannalta tarttua siihen, että "mutta nousussa ollaan", sillä 56,6 % on aivan eri asia kuin 4,4 % ja etenkin kun funktionaalisuus ei siis todellakaan ole mikään uusi ilmiö. Oma arvioni ja päätelmäni on se, että funktionaalisuus ei ole koskaan ollut valtavirran suosima, eikä siitä koskaan sellaista tulekaan. TIOBE:n mukaan esimerkiksi F#-innostuskin on jo laskussa.

    Ja mikäli matematiikka ratkaisee kaikki maailman ongelmat, niin näin joulun alla haluaisin nähdä millainen kaava lopettaa nälänhädän sekä sodat. Vai voisiko kenties olla niin, että näin väittävät henkilöt katsovat asiaa hieman liian mustavalkoisesti? Joten kysytäänpä vielä samaa mitä tuossa jo aiemminkin kysyttiin mutta tarkennuksella: minkä ongelman funktionaalisuus siis varsinaisesti ratkaisee paremmin mitä olio-kielet? Eli onko tosiaan niin, että 56,5 % ohjelmoijista (minä mukaan lukien) on niin tyhmiä, että he eivät joko tajua funktionaalisuuden etuja vai ovatko kielet niin hienoja, etteivät nämä raukkaparat opi niitä?

    Ja lopuksi sitten mallintamiseen ja suunnitteluun. Kun tein nopsaan haun Googlesta tämän asian tiimoilta, niin löysin juuri yhtä arrogantin vastauksen sieltä

    "I believe the modeling language for Haskell is called "math". It's often taught in schools." Give me a break.

  28. Vakuutusmies - December 23, 2011

    Tuomas,

    Kun sanoit

    "Se voi olla esim. bugittomuus, selkeä lähdekoodi, suurempi ilmaisuvoima, tai vaikka vain se, että huomaa, että pitkästä aikaa koodaaminen on taas kivaa."

    kaiken muun voin tosta ostaakin, mutta bugittomuus ei tule minkään kielen myötä. Se on utopiaa. Kantani tuosta ilmaisuvoimasta olen kertonut jo monta kertaa. Viimeinen pointti on ihan validi, mutta arkkitehtina sekään ei minulle kelpaa, sillä joka putkassa olisi syytä mennä sen mukaan mikä on "talon linja" ja mihin löytyy osaajia. Jokainen saa toki työajan ulkopuolella harrastaa mitä haluaa ml funktionaalisia ohjelmointikieliä, ja se voi olla avartavaakin. Itse olen vaan sen verran pragmaattinen ihminen, että minulle riittää kun osaa erittäin hyvin palvelinpään #1 kielen eli Javan erittäin mukaanlukien kaiken concurrencyyn liittyvän sekä #1 web-kielen eli Javascriptin. Javascriptillä voin sitten hyvällä omatunnolla harrastaa vaikka funktionaalista ohjelmointia ;-)

    t. Paci

  29. Vakuutusmies - December 23, 2011

    Torvi,

    Kysymys ei varmaankaan ole siitä, että joku haluaisi oppia funktionaalisuutta tämän blogin tiimoilla. Pikemminkin kyse on siitä, tiedätkö esimerkiksi sinä mitä hyötyä siitä on? Yhtään todellista hyötyä ei ole vielä näkynyt, mutta sellaista ongelmaa kun osaamisen puute on sen sijaan jo puitu. Jos sinä kerran osaat, niin mikset sitten kerro meille maallikoille niistä suurista eduista? Ja pliide, ei mitään aaltosulkeiden tai sanojen määristä.

  30. Torvi (totuuden) - December 23, 2011

    Vakuutusmies,

    toteamuksesi: "että minulle riittää kun osaa erittäin hyvin palvelinpään #1 kielen eli Javan erittäin mukaanlukien kaiken concurrencyyn liittyvän sekä #1 web-kielen eli Javascriptin"

    Minulle tulee mieleen (vaikka alunperin tarkoitettiin luonnollisia kieliä):
    "kieleni rajat ovat maailman rajat"
    - Ludwig Wittgenstein

    Ihmettelen kuitenkin vähän motiivejasi, sillä:
    - Selvästikään et ole kiinnostunut funktionaalisesta ohjelmoinnista, koska et näe sillä arvoa
    - Ilmoitat myös, ettet osaa sitä vaan kuulut siihen pragmaattiseen olio-ohjelmoinnin valtavirtaan
    - F#:a ei sinua kiinnosta, et osaa sitä etkä aio opetellakaan
    - Sanko on .net kehittäjäyhteisö, sinä liputat Javaa
    - Liitit itse Jounin esittelyssä mainitun "geneerisen vakuutusyhtiön" edustamaasi firmaan

    Luonnollisesti asioista voi ja pitää olla mieltä, mutta yksipuolinen toistaminen ja vastakkain asetteleminen ei ole oikein rakentavaa. F# ja funktionaalisuus eivät ole mikään uhka Javalle tai muillekaan valtavirran kielille. Ja me ollaan nyt blogissa, jossa käsiteltiin tapahtumaa, jossa puhuttiin näistä asioista.

    Tioben indeksit eiv√§t varmaan yll√§t√§ ket√§√§n, ei me funktionaaliset hemmot kuvitella ett√§ maailmanvalloituksemme olisi ihan viel√§ valmis :) Toisaalta, p√∂hin√§√§ kuitenkin on… valtavirrassa on jo paljon kieli√§, joissa on merkitt√§v√§sti funktionaalisia ominaisuuksia: esim. C#, javascript, ruby ja python. Ja noiden kielten yhteenlaskettu %-osuus on kyll√§ isompi kuin mainitsemasi 4.4%. Totta on, ettei mik√§√§n noista ole erlangin, haskellin jne. kaltainen "puhtaasti" funktionaalinen kieli, johon 4.4% osuudella viittasit.

    Mutta pisteet siitä, että ole nähnyt paljon vaivaa kirjoittaessasi tänne mielipiteitäsi. Itse en jaksaisi kirjoittaa pitkiä postauksia Java7 -ominaisuudet blogiin :)

  31. Torvi (totuuden) - December 23, 2011

    Vakuutusmies,

    "
    Jos sinä kerran osaat, niin mikset sitten kerro meille maallikoille niistä suurista eduista?
    "

    Omasta mielestäni osaan. Mutta moni guru voisi olla toista mieltä :)

    C#:ia osaaville: LINQ.

    Funktionaalisen paradigma hyötyjä on (lista ei tietty ole kattava, mutta jotain kuitenkin):
    - parantaa concurrencya (immutable datastructures).
    - Helpottaa koodin suorittamista asynkronisesti (continuations — async. F#:ssa on, C# v4.5 tulee)
    - Collections. Eri joukkojen käsittely erittäin tehokkaasti ja turvallisesti (immutability & tehokkaat joukko-operaatiot: map, window, zip, any, aggregate jne. )
    - vähemmän bugeja (no side effects!), tilallisuus on bugialttiimpaa
    - tehokas uudelleenkäyttö ja toiminnallisuuksien rakentaminen (higher order functions)
    - Ilmaisuvoima (parjattu vähäinen sanamäärä)
    - Rinnakkaisuus (parallelism) (immutability, no side effects, software transactional memory. PLinq (C#), Parallel module (F#))
    - Rx eli reactive extensions. Pull event mallista push & linq (eli observer + linq + schedulers). Vakiokamaa mm. windows phonessa (mango)

    Huom. concurrency != paraller execution

    Noi on niitä syitä, miksi itse näen funktionaalisessa paradigmassa potentiaalia. Ja monet modernit kielet ovat F#:n kaltaisia hybridejä, joista voi valita sitten vaikka sen olio- tai imperatiivisen paradigman ratkaisumallin mikäli se sopii johonkin ongelmaan paremmin.

    Ja tarkoituksena ei ole sanoa, ettei ilman funktionaalista paradigmaa noita asioita voi hanskata. Mutta se on huomattavasti virhealttiimpaa, vaatii helvetisti osaamista ja paljon koodia. Ja en näkisi, että esim. rinnakkaissuorittaminen olisi vähentymään päin ytimien määrän kasvaessa prosessoreissa.

  32. Koodain - December 23, 2011

    Niin, mikäli tietäisin että millaisen vastauksen haluaisin, niin ei kai sitä tarvitsisi kysellä sen enempää täällä kuin missään muuallakaan. Suhtaudun kriittisesti funktionaalisiin kieliin, koska en tiedä ohjelmistoteollisuudessa olevan sellaista ongelmaa, joka täytyisi ratkaista jotenkin uudella tavalla.

    Ensimmäiseen kysymykseen ei todellakaan ole vastattu, paitsi jos kapinointi ja piittaamattomuus säännöistä kelpuutetaan vastaukseksi. Omalla rahalla ja ajalla saa tehdä mitä haluaa, mutta muiden rahoilla tehdään niin kuin pyydetään. Tämän luulisi olevan itsestään selvää kaikille. Jos oma tapa tuntuu paremmalta, niin silloin keskustellaan organisaation teknologiavastaavan kanssa. Siinä asemassa olevan ihmisen luulisi ymmärtävän perusteltuja mielipiteitä. Voi kuitenkin olla että ne perustellutkaan mielipiteet eivät tuota omalta kannalta haluttua tulosta, mutta siinä vaiheessa on aika itse yrittää ymmärtää että ehkä "muutosvastarinta" on perusteltua. Silti voi olla niin, että asiaa vastustetaan pelkästään periaatteesta. Mutta niin tai näin, on kuitenkin vielä kaksi vaihtoehtoa; kääritään hihat ja ruvetaan hommiin tai vaihdetaan palkanmaksajaa ja toivotaan että omat ajatukset ottavat paremmin uuden työnantajan leivissä tulta alleen.

    Vai että kattava vastaus Mitä koodailet? -nimimerkiltä? Ymmärsinkö nyt oikein, että "ehkä se on ilmestynyt ratkaisemaan jonkun ongelman" tai "funktionaalinen ohjelmointi perustuu matematiikkaan" on mielestäsi, tai ylipäätään kenenkään mielestä, kattava vastaus? Ja loput Mitä koodailet? -nimimerkin kirjoittamista lauseista olivat kysymyksiä, ei vastauksia.

    Ennen Javan ilmaantumista ohjelmistoteollisuudessa oli ikävä ongelma; sovelluksen tekijän oli valittava mille käyttöjärjestelmälle sovelluksensa tekee. Toki silloinkin tehtiin monialustaohjelmia, mutta työ oli vaivalloista ja vaati jokaiseen toimitettavaan alustaan oman C- tai C++-kirjaston ja mahdolliset sovitteet omaan koodiin. Toki, POSIX:sta saattoi olla hyötyä mikäli toimittiin pelkästään UNIX-maailmassa, mutta 80- ja 90-luvun vaihteessa Windows alkoi olla vääjämättömästi joka paikassa ja POSIXin merkitys väheni sillä Windowsin POSIX oli kaukana täydellisestä. Yhtä kaikki, oli siis mahdollista kirjoittaa sovelluksia monille käyttöjärjestelmille, mutta käytännössä valittiin käyttöjärjestelmä, jolle sovellus kirjoitettiin. Mutta tämä ei suinkaan ollut ainoa näkökulma tähän ongelmaan. Noihin aikoihin yksi tärkeä liiketoimintastrateginen valinta oli sovelluksen käyttöjärjestelmän valinta. Virheellinen markkina-analyysi pelkästään käyttöjärjestelmän valinnan tiimoilta veti maton sovelluksen jalkojen alta ja esti näin ollen markkinoille pääsyn.

    Javan kehittäjillä oli tähän ongelmaan toisenlainen näkökulma. Tavoitteena oli saada aikaan kieli, jota voidaan ajaa ympäristössä kuin ympäristössä. Tämä tietenkin oli ideaali ja käytännön tavoite oli saada aikaan oliokieli jossa olisi mahdollisimman vähän ympäristöriippuvuuksia. Tämä puolestaan tarkoittaa sitä että kehittäjien on yhä edelleen ymmärrettävä eroja esim. levyjärjestelmien ja vaikkapa merkistökoodauksien välillä, jotta tehdyt ratkaisut olisivat oikeasti ajettavissa eri ympäristöissä. Joka tapauksessa, Java ratkaisee sen ongelman että enää ei tarvitse oman kuningasajatuksensa kanssa lähteä miettimään että mikähän olisi oikea käyttöjärjestelmä.

    Mutta ei se Javan idea tulkkaavine ytimineenkään mikään uusi idea ollut. BASIC on ollut alunperin tulkattava kieli ja käyttöjärjestelmäriippumattomuutta (lue: koneriippumattomuutta) yritettiin aikanaan MSX BASIC:lla (muistaakseni), joka ei kuitenkaan ollut mikään hirvittävä kaupallinen onnistuminen. Siinä kuitenkin oli jollain tapaa kylvetty Javan siemenet.

    Funktionaalisten kielien keskeisin piirre on tilattomuus ja siitä syntyvä sivuvaikutuksettomuus. Yleensä sitä käytetään funktionaalisten kielien sekä ominaisuuksien perusteluna ja sinällään hämmästelen ettei se täällä ole vielä tullut esiin. No, yhtä kaikki. Suurin osa ohjelmista kuitenkin käsittelee tilaa (sopimuksen voimassaolo, tilin saldo, jne.) tai "sivuvaikutuksia" (kuten esim. I/O-operaatioita), joten miten ohjelmointikieli, jossa nämä ominaisuudet hoidetaan aavistuksen keinotekoisesti (monadi), vie ohjelmateollisuutta eteenpäin?

    Eli, mikä on se ohjelmistoteollisuuden ongelma johon funktionaalinen ohjemointi tuo merkittävää liiketoiminnallista etua?

    Lopuksi olisin kiinnostunut tietämään, että millä perusteella, Torvi, ajattelet funktionaalisen ohjelmoinnin olevan minulle vieras käsite?

  33. Koodain - December 23, 2011

    Torvi näköjään kirjoitteli suurin piirtein samaan aikaan, joten viittaukseni siihen ettei tässä ketjussa olisi tuotu esiin funktionaalisten kielien tilattomuutta on niiltä osin virheellinen.

  34. Torvi (totuuden) - December 23, 2011

    Koodain,

    "Mitä tulee funktionaaliseen ohjelmointiin, niin mikä onkaan se ongelma minkä se ratkaisee?"

    Tosta voi hyvällä omatunnolla päätellä, ettet tiedä funktionaalisesta ohjelmoinnista mitään.

  35. Koodain - December 23, 2011

    Torvi,

    Voin vakuuttaa ettei ylimielinen päättelysi ole aukotonta.
    Lisäksi odottaisin filosofiasta kiinnostuneelta ihmiseltä hieman analyyttisempää lähestymistapaa esitettyihin kysymyksiin. Myöskään vastaukset eivät olisi pahitteeksi.

    Välttääkseni väärinymmärryksiä esitän kysymykseni vielä uudelleen.

    Mikä on se ohjelmistoteollisuuden ongelma johon funktionaalinen ohjemointi tuo merkittävää liiketoiminnallista etua?

    Minkä vuoksi organisaation teknologialinjauksista välittäminen on oikeutettua?

  36. Tuomas Hietanen - December 23, 2011

    Moi,

    Pasi:

    "Viimeinen pointti on ihan validi, mutta arkkitehtina sekään ei minulle kelpaa, sillä joka putkassa olisi syytä mennä sen mukaan mikä on "talon linja" ja mihin löytyy osaajia."

    Olen täysin samaa mieltä. Tässä sotkeutuu nyt kaksi eri asiaa:

    Tämä tilaisuus mitä kommentoidaan, oli SANKO-ihmisille, jotka ovat sellaisia, että usein he koodaavat myös vapaa-aikanaan. Usein ohjelmistoala vaatii niin paljon ammattitaitoa, että pelkkä "olen töissä täällä" ei riitä.
    Tämä oli siis perustelu lähteä kokeilemaan F#:pia, ei käyttää sitä business-softassa.

    Ja sitten jos mennään siihen toiseen asiaan, eli business-softan kehitykseen:
    Ylläpito on se missä ne ongelmat ja kustannukset tulee, ei uuden softan kehitys. Olen ollut aika paljon mukana softan ylläpidossakin, ja nähnyt niitä ongelmia.

    Ylläpidettävyyteen auttaa:
    - Helppo ja yksinkertainen koodi. Ei mitään kikkailuja.
    Tässä tapauksessa koodi on helppoa, ja siihen löytyi osaajia.
    "Talon linja" on sellainen käsite, että se on lähinnä vaan korkean tason arkkitehtuuri-ruoska, jolla voidaan jälkikäteen lyödä pikku-koodi-orjia:
    "Talon linja" tulee siitä, että pääarkkitehdit eivät voi tehdä kaikkea itse, mutta haluaisivat pysyä tietyllä tasolla kartalla missä mennään. Monenko tuhannen koodirivin tarkkuudella tätä voi vaatia?
    "Talon linja" pitäisi olla käyttää sopivimpia työkaluja sopivimpiin asioihin, ei koittaa määritellä sen vasaran muotoa, joka sopii kaikkeen. Koska sellaista vasaraa ei olekaan.

    - Pieni lähdekoodin määrä. Ja en tarkoita nyt mitään sulkukikkailua ja parin merkin säästöä, vaan:

    Ylläpidän mieluummin softaa jossa on 5000 riviä kuin miljoona riviä. Miljoonan rivin koodipohjan (usein osittain toisteisia, melkein samankaltaisia rakenteita)
    toiminnallisuuden sisäistäminen on vaikeaa.

    Yksi Javan ongelma on, että koodia on miljoonia rivejä.

    En sano että "funktionaalinen ohjelmointi" vastaa itsessään mihinkään. Haskell, LISP, yms. ovat liian vaikeita ja liian erilaisia peruskoodaajille. Niille peruskoodaajille, jotka "ovat vain töissä täällä".

    Sen sijaan, multiparadigm-kielet (C#, Scala, Ruby, Python, F#, …) koittavat ratkaista t√§t√§ Javan ongelmaa sill√§, ett√§ oliot hakevat v√§h√§n vauhtia funktionaali-puolelta ja siten saavutetaan korkeampi abstraktiotaso ja pienempi m√§√§r√§ koodia isoon m√§√§r√§√§n toiminnallisuutta.

    Ehkä liioittelin kun sanoin "bugittomuus", mutta pienempi määrä koodia on helpompi sisäistää ja testata. Siitä päästään sivuvaikutuksettomuuteen/tilattomuuteen:

    Ylläpidossa vaikeimmat löytää ovat sellaiset bugit, jotka näyttävät lähdekoodissa toimivan eri tavalla kuin toimivat tuotannossa. Ehkä kehittäjä jopa sanoo "mulla toimii".

    Tilojen synkronointi threadien välillä on hankalaa ja vaikea testata. Jos luen lähdekoodia, ja joku muu tulee jostain ulkoa, sivuvaikutuksella, vaihtamaan mun muuttujien arvoa, niin pulassa ollaan.

    Sivuvaikutukset ovat ongelma. Sivuvaikutuksettomuus on kaunis idea ja seuraan mielenkiinnolla mahdollisia ratkaisumalleja.

  37. Vakuutusmies - December 23, 2011

    Torvi,

    Ensinnäkin päättelyni siitä, että kyseessä olisi edustamani perustuu matematiikan ja tietojenkäsittelyn osa-alueeseen, joka tunnetaan nimellä logiikka. Päättelyketjuni oli seuraavanlainen:

    Tuomas on ollut työsuhteessa Tieto-Tapiolassa 2006-2010 AND F# tuli VS:n osaksi 2010 AND Tuomaksen edellisen työpaikan referensseissä ei ole yhtään vakuutusyhtiötä eikä ala oikeen mätsääkään

    Tästä tulin sitten siihen tulokseen, että varmaankaan Baswaren aikana tätä keskeistä osuutta ei olla tehty. Samoin olen hieman epäluuloinen siitä, että Tuomas olisi kenties Tieto-Tapiolassa työskennellessään tehnyt sivutulokortilla keskeisiä osuuksia jollekin muulle pumpulle. Mutta voin toki olla väärässäkin.

    Ilmoitin, että kuulun pragmaattiseen valtavirtaan, mutta en mielestäni liittänyt sitä olio-ohjelmointiin. Pidän erittäin pragmaattisen valintana myös ensimmäisiä ihan kieliä joilla olen aloitellut: x86 assembler ja C. Assembleria en enää juurikaan tarvitse muuhun kuin esimerkiksi ymmärtään vaikkapa artikkeleita jotka kertovat Javan/C#:n muistimallista tai JITterin toiminnasta. Eli siitä TIOBE:n listalta olen puuhastellut top kolmosen kanssa, C/C++:lla yli 20 vuotta ja Javalla sen ekoista betoista saakka. Myös LISPiä on tullut kirjoiteltua jonkin verrankin ihan työnantajan pyynnöstä jo noin 15 vuotta sitten, mutta en nähnyt siinä mitään erityisen ihailtavaa. Eikä siitä syntynyt keskeistä osuutta kenellekään, vaan läjä sellaista koodia jota ei kukaan ei halua eikä oikein osaakaan ylläpitää. Eli recycle bin'issä, missä se epäilemättä jo on, se koodi on ihan arvoisessaan paikassa.

    En myöskään liputa mitään muuta kuin sitä, että a) kerroin, että ainakaan Tapiolassa niitä *keskeisiä* F#-osia ei ole (varsinainen motiivi) ja b) ihmetystä "funktionaalisuushöyryämistä" kohtaan (motiivin kirjoittamisen sivutuotteena esille tullut asia).

    Mielenkiintoista on myös se, että kuvaat funktionaalisuuden etuja nimenomaan C#:n kontekstissa, etkä F#:n (kieli jota minä tässä nyt "parjaan"). Lisäksi on myös pidän hieman omituisena, kuten jo arvasitkin, että funktionaalisuuden nimissä omitaan piirteitä kuten asynkroninen suoritus tai immutablet. Tässä menee nyt nimenomaan sekaisin asiat kielen syntaksi, muuttumattomuus ja funktionaalisuus. Otetaanpa esimerkki oliokielestä X10 (josta en myöskään ole kiinnostunut sen enempää). Siellä vaikkapa tuo async-toiminnallisuus on helppo tehdä, siitä huolimatta että se on OO-kieli. Sama pätee kaikkeen muuhunkin tuossa listassa. Voit toki yrittää käännyttää minut jollain esimerkillä, jossa suuret hyödyt tulevat nimenomaan funktionaalisuudesta, ei C#:n syntaksista.

    Olen hieman epäluuloinen sen suhteen, että concurrency ongelmat häipyvät jollain kielellä. Kun sitten pitäisi osata näitä asioita, niin ei edes tiedetä niiden perusteita ja siten ei edes osata aavistaa mitä voi tapahtua. Otetaanpa esimerkki ihan tosielämästä. Kävin erään konsultin (tai tarkemmin ottaen lähes kaikkien mitään talossa on käytetty) kanssa keskustelua siitä, pitääkö muistilohkon luvussa käyttää synkronointia (tai volatilea) vai ei. No vastaus oli, että ei tarvitse "kun se on vaan lukua". Tietenkin se riippuu monesta asiasta, mutta jos tila voi muuttua initialisoinnin jälkeen (esim. setterillä), niin tietenkin tarvitsee, myös vaikkapa C#:ssa. Jos näillä ohjelmointitiedoilla sitten käytetään yhdenaikaisuutta (tässä siis concurrency), niin on suuri vaara, että ohjelmat ovat täynnä "race-ongelmia". Funktionaalisuus puhtaimmillaan toki poistaa tätä ongelmaa, mutta entäpä sitten näillä hybrideillä joissa se shared state saattaakin osua kohdalle? Kun aina vaan tuudittaudutaan siihen, että kieli ja ympäristö hoitaa, niin saattaa käydä vähän hassusti. Concurrent programming vaatii nyt ja jatkossa taitoja joita ei kaikilla ole. Tähän liittyen http://msdn.microsoft.com/en-us/library/dd997403.aspx

    Ja jos moderaattori ei tässä välissä taas tylsisty kun mennään aiheesta ulos, niin pyytäisi että kertoisit ihan omin sanoin miten concurrency ja parallel execution sitten eroavat, sekä erityisesti miksi näit sen tärkeäksi huomauttaa asiasta.

    Yksi asia kuitenkin on mistä olen täysin samaa mieltä: rinnakkaissuorittaminen tulee lisääntymään.

  38. Koodain - December 23, 2011

    Hups, todella karkea virhe edellisen kirjoituksen jälkimmäisessä kysymyksessäni, joten esitän ne molemmat vielä kertaalleen. Toivottavasti oikein tällä kertaa.

    Mikä on se ohjelmistoteollisuuden ongelma johon funktionaalinen ohjemointi tuo merkittävää liiketoiminnallista etua?

    Minkä vuoksi organisaation teknologialinjauksista _välittämättä jättäminen_ on oikeutettua?

  39. Torvi (totuuden) - December 23, 2011

    Vakuutusmies,

    Vastasin kysymykseesi funktionaalisuuden hy√∂dyist√§, joita kyseinen paradigma tarjoaa. C#:n syntaksista en puhunut postauksessani mit√§√§n. Monissa konsepteissa k√§ytin esimerkkin√§ my√∂s C#:n ominaisuuksia, ja miksik√§ ei… C# on hyv√§ kieli, jossa on huomattavasti funktionaalisuutta. F# on my√∂s hyv√§ kieli, ja sen osaaminen on hyvinkin avartavaa. Niin tietysti on hyv√§ osata useita kieli√§ muistakin paradigmoista.

    Kiitos, kun avasit motiivejasi. Minusta olisi mielenkiintoista katsoa tätä threadia ulkopuolisena. Olisi jännä nähdä, noinko funktionaalisuudesta kiinnostuneet ja sitä "puolustaneet" ovat syyllistyneet laajamittaiseen mainitsemaasi "funktionaalisuushöyryämiseen". Osallisena on vaikea katsoa tuota objektiivisesti.

    Minulle ei ole sattunut silmään, että täällä olisi ainakaan varsinaisesti vaikkapa hyökätty esim. olioparadigmaa kohtaan. Lisäksi olet käsittänyt kyllä väärin tarkoitusperäni, tarkoitukseni ei varmasti ole ollut yrittää käännyttää ketään. Postauksessani, jonka kyllä luit väärin kuin tarkoitin, vastasin vain suoraan kysymykseesi niinkuin minä asian näen. Mainitsemani asiat liittyvät hyvin läheisesti ja ovat oleellisia osia nimenomaan funktionaalisissa kielissä. Ja tietty hybridikielissä.

    Mielenkiintoista kuulla näkemyksiä, jotka ovat omani kanssa ortogonaalisia. Mutten varmaan jatka pidemmälle, tuskinpa kukaan enää löytää uusia pointteja jotka olisivat kovin käänteentekeviä :)

    Kysymykseesi, mitä ovat concurrency ja parallel execution on oikein hyvä määritelmä (Scalan isä Martin Odersky):

    Parallel programming = Execute programs faster on
    parallel hardware.

    Concurrent programming = Manage concurrent execution
    threads explicitly.

  40. Tuomas Hietanen - December 24, 2011

    Ennen Tieto-Tapiolaa olin töissä pikkufirmassa, jossa tein softaa usealle asiakkaalle.

    Jos johtavan IT-arkkitehdin pit√§√§ opettaa l√§hes kaikille talon konsulteille jotain muistimalleja ja synkronointeja, ja silti konsulttien linked-listasta (ihan perustietorakenne) tulee koodia jota ei ymm√§rr√§, kuulostaa, ett√§ koodataan aika matalalla abstraktiotasolla. Hyv√§ll√§ tahdolla ajateltuna tuo on pikkuruinen osa ei-toiminnallisia vaatimuksia, mutta silti… Onneksi .NET-maailmassa harvemmin tulee vastaan. Ei muistimallien ymm√§rt√§misest√§ toki haittaakaan ole, mutta ehk√§ johtavalla IT-arkkitehdilla olisi niin paljon muutakin hommaa, ett√§ ilmankin riitt√§isi ty√∂p√§iv√§lle tarpeeksi t√§ytett√§.

    Softahan on nyky√§√§n l√§hinn√§ sit√§, ett√§ varastossa (=tietokannassa) on jotain m√∂llej√§, ja sitten on http-protokolla, ja sitten k√§ytt√§j√§n n√§yt√∂ll√§ n√§ytet√§√§n eri m√∂llej√§. Loput on sitten kategoriateoriaa ja joukko-oppia, toteutettuna haluamallaan abstraktiotasolla… ;)

    Koodaimen peräänkuuluttama "merkittävä liiketoiminnallinen etu" saadaan vasta jos tajutaan, että (jos meillä on töissä ammattilaiset, niin) firman olemassaoleva legacy-koodipohja on rasite, eikä omaisuus.

    Funktionaalisuus voi kuulostaa arrogantilta olio-koodaajasta, vastaavasti olio-patternit voivat kuulostaa arrogantilta assembler-koodaajasta. Mulle on jäänyt käsitys, että Suomen yliopistomaailma elää niin omassa pilvessään, että suomalaisille leviää käsitys, että funktionaalisesta paradigmasta ei ole käytännön hyötyä. Paradigman hyödyt eivät tule esille 100 rivin harjoitustyössä, ja opettajilla harvemmin on edes käsitystä business-softan teosta. Ehkä tämä johtuu valtion omistuksesta ja liian pienistä palkoista? Onneksi netistä löytyy esim. Microsoft Research:in materiaalia, joka on kovinkin akateemista, mutta silti hyvin business-lähtöistä työtä.

  41. Vakuutusmies - December 27, 2011

    No niin, kinkut ja kalkkunat on nyt syöty ja taas on voimia väitellä turhanpäiväisistä asioista.

    Tuomas,

    Kun sanoit:
    "Jos johtavan IT-arkkitehdin pitää opettaa lähes kaikille talon konsulteille jotain muistimalleja ja synkronointeja, ja silti konsulttien linked-listasta (ihan perustietorakenne) tulee koodia jota ei ymmärrä, kuulostaa, että koodataan aika matalalla abstraktiotasolla. "

    Kuka koodaa ja kuka ei. Onko se Javan ongelma, jos konsultti haluaa välttämättä koodata asiat typerästi? Nyt näytän sitten ihan esimerkin suoraan ko. koodista, niin ei sitten tarvitse enää tätä ihmetellä. Ongelma: lista merkkijonoksi siten, että välissä pilkut. Tässä arvoituksellisen henkilön versio asiasta:

    static String concatUsingCommas(List list){
    LinkedList linkedList = new LinkedList();
    linkedList.addAll(list);
    return getConcatedString(linkedList, "");
    }

    private static String getConcatedString(LinkedList list, String value){
    if(list.isEmpty()){
    return value;
    }
    value += list.removeFirst();
    return getConcatedString(list, list.isEmpty() ? value : value + ", ");
    }

    Tätä minä kutsun koodaamiseksi matalalla tasolla. Itse päädyin korjaamaan tämän näinkin tylsään koodipätkään:

    String strs = c.toString( );
    String result strs.substring( 1,strs.length( ) – 1 );

    En tarvitse funktiota lainkaan, sillä en tarvitse rekursiota tms turhaa. Mittasin myös suorituskyvyn, ja tulos oli seuraavanlainen

    Paci Salminen consumed CPU 3 354 021 micros
    Karenina Jalmari consumed CPU 32 401 407 micros

    Eli tuo häntärekursioviritys vie siis CPU:ta noin 10X enemmän (seinäkelloaikaa en edes mitannut) ja kaatuu (stack overflow) jos listassa esimerkiksi 5000 elementtiä.

    Omaan ratkaisuuni olisi voinut päätyä esimerkiksi noudattamalla neuvoa Effective Javasta: "know your libraries", joka pätee tietenkin mihin tahansa ympäristöön.

    Luokassa AbstractCollection sanotaan näin

    /**
    * Answers the string representation of this Collection. The presentation
    * has a specific format. It is enclosed by square brackets ("[]"). Elements
    * are separated by ', ' (comma and space).
    *
    * @return the string representation of this Collection
    */
    @Override
    public String toString()

    Mutta hei, tuohan on juuri sitä mitä halusin ;-)

    Muihin väittämiin palaan vielä erillisellä postauksella.

    Uutta, vähemmän funktionaalista vuotta odotellen

    Vakuutusmies

  42. Tuomas Hietanen - December 28, 2011

    Tässä ketjussa on aiemminkin tullut esille oikean työkalun käyttö oikeaan asiaan.

    Oikealla kirjastojen käytöllä ei ole edes mitään tekemistä ohjelmointiparadigmojen kanssa, joten siten en edes lähde käsittelemään JVM tail-rekursion-puutetta tai linked-listoja.

    Lähtökohtaisesti jos koodin tehtävä on string-parsinta, käytetään nykypäivän oliokieliä väärin.

    Voin vakuuttaa että (Javan lisäksi myös) sekä F#:lle, että "köyhän miehen F#:lle" eli LINQ:lle löytyy tehokkaat listojenkäsittelyoperaatiot, jottei tarvitse koodata itse.
    (Tässäkin tapauksessa vaihtoehtoja on paljon, esim. F#: List.fold, C#: .Aggregate)

    Tästäkin huolimatta aina on niitä, jotka eivät tunne kirjastoja. Siksi versiohallinnasta edellisen päivän change-settien code-review on tärkeä juttu, turhat koodit saadaan tiimin sisällä kiinni alkuunsa.

  43. Vanhus - December 28, 2011

    Tässä "vanhana" koodarina keskustelua seuranneena niin mielenkiintoista on ollut kun mennään ohjelmointiparadigmoista, arkkitehtuuri asioihin ja itse kielen syntaksiin sekä kirjastoasioihin. Mukavasti on soppaa keitetty eri lisukkeilla kunkin kokin mieltymysten mukaan. Näin kun olen käynyt läpi alan historian aikana useita funktionaalisia sekä oliokieliä niin olisi kyllä mukava kuulla nyt hieman konkreettisimpia perusteita funktionaalinen vs. olio lähestyminen. Tai oikeastaan jos historian saatossa on siirrytty kohti oliomaisuutta niin miksi nyt yhtäkkiä funktionaalisuus olisi parempi ? Mitä rauta yms. puolella on tapahtunut, jotta kannattaisi palata taas takaisin funktionaalisuuteen ? Kertokaa please, jotain konkreettista.

    Sitten Tuomakselle viel√§ sellainen ohjelmistoalan business kysymys, ett√§ kun ihannoit "pieni√§" (5000 koodirivin) ohjelmia niin oletko ikin√§√§n tullut ajatelleeksi sit√§, ett√§ mit√§ se tarkoittaa ihan miss√§ vain suuressa,keskisuuressa yrityksess√§, jossa olisi noita "pieni√§" ohjelmia esim. helposti useita kymmeni√§ ellei jopa 100 kpl, jotta yrityksen prosessit yms. liiketoiminta py√∂rii ? Mihin saatetaan suurella todenn√§k√∂isyydell√§ ajautua ? Kun keksit vastauksen niin olet taas oppinut ohjelmistoalasta jotain ja kenties joskus p√§√§set siihen Suomen HUIPPU ohjelmistokavereiden joukkoon…

    Joka p√§iv√§ sit√§ oppii uusia asioita jos vain haluaa…

  44. Vakuutusmies - December 28, 2011

    Tuomas,

    Ensinnäkin merkkijonon tekeminen listasta ei ole parsintaa, enkä kyllä ymmärrä mitä väärää on parsinnassa tai merkkijonon tekemisessä ja miksi se on lähtökohtaisesti väärin. Toiseksi, uskon sen että sekä F#:sta että C#:sta löytyy vähintäänkin yhtä hyvät mekanismit asiaan. Eihän koodin lyhyys/tehokkuus ole missään kohtaa ollut minun repliikkini, vaan sehän oli teidän funktionalistien vuorosanoissa ;-)

    Mutta sitten "muistimalli on kiva osata" -osioon. Ensinnäkin, olen samaa mieltä siitä, että johtavalla IT-arkkitehdilla on paljon muutakin tekemistä. Toisaalta taas jonkun pitää kuitenkin katsoa asioiden perään ja jostain kumman syystä loppuviimeksi olen löytänyt hyvinkin usein itseni siitä tehtävästä. Toki asiaan saattaa vaikuttaa myös se, että concurrent-ohjelmointi on minulla "verissä", sillä niidenkin asioiden ympärillä on tullut puuhailtua lähestulkoon 20 vuotta. On ollut POSIX thread'ejä (Linux, AIX, z/OS), Win32 API:a, Javaa sun muuta.

    Sitten voimmekin edet√§ itse muistimalliasiaan. Omasta mielest√§ni muistimallin osaaminen ei ole mik√§√§n kiva asia vaan se on v√§ltt√§m√§t√∂n osa. Se on asia, joka on olemassa joka prosessoriarkkitehtuurissa ja useimmat (jos eiv√§t kaikki) virtuaalikoneet m√§√§rittelev√§t sen p√§√§lle oman muistimallinsa (Java, CLR, …). Muistimallia ei tarvitse v√§ltt√§m√§tt√§ osata ulkoa, mutta mik√§li sen keskeiset asiat eiv√§t ole hallussa, niin ehdottaisin lopettamaan koodin kirjoittamisen sek√§ muiden ohjelmointikielien opiskelemisen hetimiten ja keskittym√§√§n olennaiseen. Jos esimerkiksi CLR:n muistimallin keskeiset osat eiv√§t ole t√§m√§n foorumin keskustelijoiden keskuudessa rautaisesti hallussa, niin seuraavan SANKO-tapahtuman nimi voisi olla vaikka englanniksi "all the unrealized concurrency bugs I've left behind". Aikaisemmissa postauksissa mainitsinkin, ett√§ t√§t√§ asiaa sain selitt√§√§ er√§√§lle "hard-core" .NET-koodarille oikein huolella, tosin kyseess√§ oli silloin Java-koodi. Jos ja kun muistimalli Javassa ja CLR:ss√§ on kuitenkin suurelta, ja erityisesti keskeisilt√§ osiltaan, samanlainen niin pakko olla hieman huolissaan. Samaan aikaan h√∂yry√§minen F#:n ymp√§rill√§ oli kyll√§ jo k√§ynniss√§. Mutta yll√§tys, yll√§tys, t√§m√§ asia ei tietenk√§√§n poistu F#:n k√§yt√∂n, PLINQ:n tai mink√§√§n muunkaan taikateknologian my√∂t√§. Esimerkiksi PLINQ kyll√§kin helpottaa concurrent ohjelmointia paljonkin (mutta parallelismista sek√§√§n ei voi takuita antaa), mutta sitten j√§√§v√§t ne pikkuruiset kohdat sinne sun t√§nne, jossa bugit el√§v√§t ja aktivoituvat sielt√§ sitten ajan mukaan kun todenn√§k√∂isyys t√∂rm√§t√§ niihin kasvaa ydinten lukum√§√§r√§n ja VM:n/prosessorin optimointien kasvaessa. N√§m√§ ovat ne eritt√§in kalliit bugit, joita ei l√∂yd√§ sitten kun harvat ja valitut, ja silloinkin ty√∂ on aikamoinen kun mahdollisesti suuria m√§√§ri√§ koodia pit√§√§ k√§yd√§ l√§pi.

    Samoin performanssia ei saa kohdalleen vahingossa, vaan asia pitää ymmärtää ja koodata sen mukaisesti. Mitä tulee parallelismiin, niin nyt kuulostaa kovasti siltä, että moni F#-/Scala -koodaja tulee törmäämään siihen, että yritetään parallelisoida liikaa. Räiskitään vaan AsParallel'ia joka paikkaan. Sama koskee myös F#:a. Samalla suorituskyky romahtaa mm. turhien context switchien takia. Ja tästä ei pelastuta edes fork/join'in eikä work steeling'in avulla. Tästä yliparallellisoinnistakin löytyy hyviä juttuja Vance Morrisonin esityksessä (sivu 9, More Parallelism != Better Perf). Tämä kaikki on ihan tiedossa olevaa asiaa, jota vaan ei oikein haluta ottaa tosissaan. Erityisesti kun on niin paljon kaikenlaista kivaakin mitä pitäisi katella. Nojautuminen jonkun kielen tai platformin turviin on kuin pistäisi pään pensaaseen.

    Koska olemme nyt keskustelemassa .NET-ympäristön kontekstissa, niin olkoon lähdeaineistokin sitten MS-tavaraa. Linkkejä on MSDN:ää ja Microsoftille sinne sun tänne, Parallel platform kavereita sun muita. Microsoft tosin itse vittaa usein mm. Javan muistimalliin sekä Doug Lean kirjoituksiin asiasta. Myös osa MS:n patterneista asian tiimoilta on väärin. Esimerkiksi implementing singleton in C# (ja sieltä erityisesti multithreaded singleton) patternin kirjoittaja puhuu lukoista ja volatile-muuttujista ihan puppua. Tässä huomion arvoista on mm. se, että pattern on kirjoitettu concurrency mielessä toimivaksi, mutta asia itse on kerrottu väärin. Kyseessä on nk. "housut pysyvät jalassa paremmin kun on henkselit ja vyö". Tottahan se on, mutta suorituskyvyn ja koodin luettavuuden kannalta huono.

    Ensin Vance Morrisonin esitys: Parallelism for .NET Applications. Erityisesti painottaisin "Parallelism is Not Easy, Do you Homework" eli lue Vancen artikkeli "What Every Dev Must Know About Multithreaded Apps" joka onkin sitten tässä http://msdn.microsoft.com/en-us/magazine/cc163744.aspx. Nimi jo kertoo asian. Huom, nimessä ei jätetä pois vaikkapa C#- tai F#-ohjelmoijia. Tätä olen jo aikaisemmin suositellut myös Java-ohjelmoijille edustamassani yhtiössä, sillä muistimallihan on lähestulkoon sama ja tämä artikkeli erittäin hyvä. Osa vaan ei kerekä, kun painaa joku muu "kiva" tai seksikäs asia (esim. Scala tai Haskell) päälle niin pahasti. Asteen helpompi ja nopeammin kartalle vievä artikkeli on http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/ (kaveri on Microsoft Parallel Computing Platform team'issä). Kun katselette millaisia kavereita nämä artikkelit on kirjoittaneet, niin luulisi kiinnostavan.

    Eli jos nämä kaikki asiat olivat päivänselviä, niin sitten olen nähnyt turhaa vaivaa tämän postaukseni tiimoilta. Mutta hieman kuitenkin rohkenen epäillä, että lieneeköhän nämä asiat sittenkään ihan selviä.

  45. Vakuutusmies - December 28, 2011

    Ja sitten niihin sovelluksiin, HTTP:hen ja tietokantaan.

    Yksi t√§m√§n vuoden haastavimmista projekteista oli sellainen, miss√§ ei ollut lainkaan k√§ytt√∂liittym√§√§, ei HTTP:t√§ eik√§ edes tietokantaa. Sy√∂te luetaan tiedostosta ja ulos tulee toinen tiedosto. Erityisesti tulostiedosto ovat kuitenkin jo semi-iso, tyyliin satoja gigoja. Ohjelmaa ajetaan er√§ajona. T√§m√§ kyseinen ohjelma on kuitenkin siin√§ mieless√§ erikoinen, ett√§ sen yhden ajokerran k√§ytt√§m√§ CPU mitattiin alkujaan p√§iviss√§, joskin p√§√§asiallisena syyn√§ oli ainoastaan yhden ytimen k√§ytt√∂. Kyseess√§ on siis hyvin rankkaa matematiikkaa ja I/O:n osuus on l√§hes olematon. Kyseisen ohjelman tulosrakenteet ovat niin massiviisia, ett√§ mik√§li niihin aikoo soveltaa muuttumattomia rakenteita (immutable), niin voin heti sanoa, ett√§ ei tule onnistumaan. Kai kaikki tiet√§nev√§t, ett√§ isojen rakenteiden allokointi on hidasta? Tai onnistuu, jos paralleelisti on ajossa yksi tai kaksi s√§iett√§. Mutta kun tarvis olisi mahdollisesti kymmenille, jotta ajoaika saadaan oikeaan magnituudiin. N√§in ollen teimme muutoksia ohjelmaan, pienemsimme usein allokoitavien olioiden "yhtein√§ist√§ kokoa" ja rakensimme sen ymp√§rille hyvin yksinkertaisen s√§ikeisiin ja jonoihin (java.util.concurrent.ArrayBlockingQueue) perustuvan parallesointimekanismin. T√§ll√∂in yksi s√§ie lukee sy√∂tetiedostoa (voi olla hieman haastavaa parallelisoida, jopa F#:lla ;-)), pist√§√§ sy√∂tteen jonoon josta N-s√§iett√§ kilvan ottavat niit√§ k√§sittelyyn ja laskennan lopuksi kirjoittavat tulokset taas seuraavaan jonoon. Lopuksi yksi s√§ie kirjoittaa tulokset tiedostoon. Koodia t√§ss√§ rakennelmassa on eritt√§in paljon, mutta ei parallelismin takia vaan itse business-ongelman. Me emme kuitenkaan alkaneet itkem√§√§n, emme laittaneet p√§√§t√§ pensaaseen, emme sanoneet ett√§ t√§m√§ koodi on rasite ja se pit√§√§ kirjoittaa uusiksi Scalalla, vaan ratkaisimme sen loppuviimeksi hyvin yksinkertaisesti. Ja tulokset ovat sen mukaiset. L√§pimenoaika on nyt nelj√§ll√§ ytimell√§ jo 5-10% alkuper√§isest√§ (eli 10 h ajo -> 1/2-1h) ja osaamme my√∂s ennustaa mit√§ tapahtuu kun prosessointitehoa lis√§t√§√§n. Koska …

    Java-ohjelman parallellisointipotentiaalin pääteltiin olevan hieman yli 90% (P=0.9). Tähän tulokseen tultiin mm. lisäämällä käytössä olevien ydinten määrää yksitellen, kellottamalla läpimenoaikaa ja tarkkailemalla ydinten kuormitusta. Näin ollen Amdahlin lain mukaisesti parallelismin tuoma maksiminopeutus (verrattuna non-paralleliin) on siis 10X (kaavasta 1 / (1 РP)). Tähän päästään mikäli käytössä on 512 ydintä. En pitänyt kovin houkuttelevana suositella, että asiakas ostaisi koneen jossa olisi 512 ydintä. Sen sijaan näytimme Amdahlin lain graafista esitysmuodosta millaisella panostuksella saataisiin mitkäkin hyödyt. Graafista onkin helppo päätellä, että mikäli halutaan 8X nopeus, niin tarvitaan enää vain 32 ydintä ja mikäli hankitaan vain 16 ydintä, niin nopeutus tulee olemaan hieman yli 6X. Tämä yli 50 vuotta vanhaan teoriaan pohjautuva pohdiskelu siis johti siihen, että pystyimme ennustamaan luotettavasti läpimenoajat eri kapasiteetilla. Näiden juttujen teoriaosuuksia voi tarkastella vaikka täältä: http://en.wikipedia.org/wiki/Amdahl%27s_law tai http://en.wikipedia.org/wiki/Parallel_computing. Suosittelen lukemaan nämä niin voimme sitten nostaa keskustelun tasoa epämääräisistä heitoista lähemmäs totuutta. Vai onko sitten kenties niin että kaikki ongelmat joita ratkaistaan funktionaalisilla kielillä menevätkin kategoriaan "embarrassingly parallel"?

    Joten kun puhun concurrency'stä tai parallelismista, niin siinä kohtaa puhun ihan oikeiden ongelmien ratkaisuista en siis mistään concurrency-/parallelismi-harjoituksista. En voi kertoa mistä tarkemmin ottaen on kysymys, mutta sen voin kertoa, että tämän järjestelmän osuus on **ihan aikuisten oikeasti** keskeinen.

  46. Tuomas Hietanen - December 28, 2011

    Vanhus,

    Jos puhutaan nykyisistä keskisuurten/suurten firmojen softakehityksestä, niin softakehitysprosessin ongelmat harvoin ovat tiimien sisäisiä.

    Yleisiä ongelmia (perustuen omiin havaintoihin useista firmoista, mutta ei mihinkään tiettyyn):

    1) Yli viisi tiimiä yhtaikaa haluaa muutoksia samoihin common-luokkiin/palveluihin, ja sitten mergeillään.
    2) Ja ihmetellään mikä on yleiskäyttöistä ja mikä ei, ja mikä on kenenkin vastuualue, ja missä kulkee rajat.
    3) "Kommunikaatio ei pelaa tiimien välillä." Tiimit odottavat muiden hommia ja se vasta maksaa.
    4) Vain harvat osaavat käyttää firman sisäistä "common-frameworkkia/platformia" ja tietävät mitä löytyy mistäkin.
    5) Lähdekoodia on yli miljoona riviä ja ei edes oikein tiedetä mitä se oikeasti tekee. (Yleensä suurin osa koodista ei tee mitään, mutta olisi liian iso työ poistaa, kun pitää tehdä lisää.)

    On jopa kyseenalaista pystyykö iso firma tuottamaan ikinä kilpailukykyistä softaa (varsinkin urps:ien osalta), verrattuna softaan, jonka on kehittänyt alle 20 ammattitaitoista kehittäjää, jotka tietävät mitä tekevät (=ironista kyllä, se "nyrkkipajan" muodostanut porukka, joka alun perin kasvatti firman isoksi).

    Isoissa projekteissa (tai useissa softissa) yhteistä on siinä, että käsitellään suurta määrää lähdekoodia. Tiimienväliset vastuualueet voidaan jakaa usealla eri tavalla, esimerkiksi:
    A) Jaetaan tiimit feature-tiimeiksi yhdelle isolle koodimassalle.
    B) Jaetaan tiimit teknisten rajapintojen mukaan.
    C) Jaetaan tiimit business-featureiden mukaan.

    Huolimatta "Usean tiimin Agile"-kirjojen suosituksista, en ole n√§hnyt Suomessa toimivaa mallia A-kohdasta. T√§m√§ johtunee siit√§, ett√§ usein teknisen alustan hyvin osaavia koodaajia on v√§h√§n, ja ylemm√§n listani ongelmakohta 1 korostuu helposti…?

    En ole myöskään nähnyt toimivaa mallia kohdasta B, sillä se korostaa ongelmakohtaa 3, joka pilaa työilmapiirin, jolloin pätevimmät työntekijät karkaavat pois, ja loput eivät saa aikaan tarpeeksi. Softa-kehitys on ilmeisesti paljon enemmän ihmislähtöisempää kuin olettaisi.

    Voisin haastaa lukijat: Kertokaa ihmeessä, jos teillä on kokemuksia onnistuneista isoista projekteista, joita on ylläpidetty vielä yli viisi vuotta. Miten palvelut ja tiimien vastuualueet on rajattu?

    Ehkä toimivin näistä vaihtoehdoista on kuitenkin vaihtoehto C (?), jossa on vaihtelevasti kommunikaatiota tiimien välillä. Usein business-toiminnallisuukisen tai pienten softien välillä on SOA-arkkitehtuuri.

    Tällöin tiimit vastaavat jokainen omasta pienestä nurkastaan, ja interaktiota tiimien välillä on vähän. Tämä ei pelasta tilannetta, sillä jos tiimien välille tulee "tiivistä yhteistyötä", on yhä vaara ajautua jokaiseen listassa olevista ongelmakohdista. Siksi softien pitäisi olla pieniä itsenäisiä kokonaisuuksiaan, jopa asiaan perehtymättömät konsultit voivat tarvittaessa hallita.

    Ps. En syytä olio-ohjelmointia, mutta ei se kyllä itsessään myöskään auta kehittäjää välttämään listaamiani ongelmia.

  47. F#-koodaaja - December 28, 2011

    Vakuutusmies,

    Oletko kuullut tästä uudesta muodikkaasta teknologiasta, joka pelastaa kaiken async-ohjelmoinnin ja tekee siitä niin helppoa, että vastavalmistunutkin osaa, ei tarvita 20 vuoden "verenvuodatusta":

    http://channel9.msdn.com/posts/DC2010T0100-Keynote-Rx-curing-your-asynchronous-programming-blues

    Sen juuret ovat tietysti lähtöisin funktionaalisesta maailmasta (kuten Generics, lambdat, ja muutkin nykypäivän "oliokielten" uudet ominaisuudet).
    Testattu käytännössä ja hienosti toimii!

  48. Tuomas Hietanen - December 28, 2011

    Ja vielä kaksi selvennöstä:
    - Oikoluku ei korjannut, alussa mainittu Jaakko oli tietysti Jarkko.
    - "p√§tevimm√§t ty√∂ntekij√§t" ei viittaa t√§ss√§(k√§√§n) yhteydess√§ muhun, vaan niihin, jotka kokevat t√§rke√§ksi saada paljon business-featureita aikaan…

    Jouni: Aistinko Vakuutusmiehen halukkuutta järjestää Sanko-sessio? ;-)

    Mutta nyt menenkin tästä lukemaan noita linkkejä läpi.

  49. Tuomas Hietanen - December 29, 2011

    Hmm, funktionaaliset kielet ovat yleensä parhaimmillaan "rankassa matematiikassa" (ja DSL:issä).
    Vakuutusmiehelle tässä alalta referenssi Lontoosta, "isosta maailmasta":
    http://www.microsoft.com/casestudies/Case_Study_Detail.aspx?casestudyid=4000006794

    Mutta jos nyt puhutaan perus-business-softasta, niin ylläpidettävyys on tärkeintä, suorituskykyoptimoinnit voi tehdä jälkikäteen. (Tottakai silloin pitää tietää mitä tekee, suorituskykyä ei saa jälkikäteen millään moduulilla.)
    Mutta jos suorituskykyoptimoinnit tehdään etukäteen, niin yleensä toiminnallisuuden muuttuessa optimoinnit optimoivat väärää asiaa.

    Imperatiivinen ohjelmointi kertoo miten koneen pitää asia tehdä, deklaratiivinen kertoo mitä koneen pitää tehdä. Lähtökohtaisesti funktionaalinen lähestymistapa suosii jälkimmäistä. Miksi koodaajaa kiinnostaisi alusta-optimointi (=prosessorien määrä), matemaattisesti se on aika sama onko niitä 4 vai n. Itse oletan, että käyttöjärjestelmä hoitaa, ja nopeuttaa esim. listoissa jos n <= (listan itemien määrä).

    Ylläpidettävyyteen kuuluu se, että koodi on selkeää ja ei käytä kielen erikoispiirteitä perusjutuissa.
    Siihenkin pääsääntönä sanoisin: jos koodaaja käyttää 10 min ja oppii uutta, niin hyvä, mutta jos menee puoli tuntia, eikä vieläkään ymmärrä, niin ei-hyvä.

    Mutta kielen erikoispiirteit√§ eiv√§t ole uusimmat ominaisuudet: esim. lambdat opetetaan jo nyt Sovellon perus-.NET-kursseilla. Sen sijaan erikoispiirteit√§ ovat sellaiset ominaisuudet, mit√§ suuri osa koodaajista ei n√§e viikottain (esim. Flags-enumit, xor, bitwise-operaatiot, volatilet, …) tai koodaavat v√§√§rin, (esim. v√§litt√§v√§t volatile-muuttujia ref-viittauksina tai tekev√§t double-check-lockingin v√§√§rin,
    http://csharpindepth.com/Articles/General/Singleton.aspx ). Olen tainnut muuten lukea noi cache-linkit ennenkin, kuka lie laittanut ne mulle aikanaan. ;)

    Perustapauksessa, Mikaa lainatakseni, immutablejen kustannus (private setterit, parametrisoitu konstruktori) ei yleens√§ maksa mit√§√§n. (Samoin turhien singletonien v√§ltt√∂…)

  50. Vakuutusmies - December 29, 2011

    F#-koodari,

    Ensinnäkin toi video sanoi mulle: "Doh! Your browser doesn't seem to support Silverlight or HTML5 video or we don't have an HTML5 video for this one." Joten pitäkööt hyvänään. Ja kun sanot, että aloittelijakin osaa, niin sehän sitten nähdään. Jos katsot esim näitä esimerkkejä (http://rxwiki.wikidot.com/101samples#toc0), niin voi olla että tulee "vähän" bugista softaa kun aloittelijat pääsevät näiden kimppuun.

    Toiseksi, kun sanoit mistä generics'it sun muut ovat tulleet, niin ketä se oikeasti kiinnostaa? Minua ei itse asiassa lainkaan kiinnosta mistä joku piirre tulee. Pidän sitä erittäin hyvänä, että kielet "varastavat" hyviä piirteitä toisiltaan, kuten on käynyt koko ajan C++:n, Javan ja C#:n välillä. Mutta mitä sen alkuperä kiinnostaa ketään? Ne eivät ole **nyt tällä hetkellä** funktionaalisten kielien vahvuuksia verrattuna vaikkapa oliokieliin. Ja muistutan edelleenkin, että vain hieman yli 4% maailman koodareista on kiinnostunut funktionaalisesta ohjelmoinnista.

  51. Vakuutusmies - December 29, 2011

    Ai-jai Tuomas,

    nyt et lukenut tekstejäni kunnolla. Tarkkuutta, tarkkuutta. Minähän juuri sanoin, että niitä koodeja **ei haluttu** kirjoittaa uudelleen. Ne eivät ole rasite vaan arvokkaita assetteja. Javallakin voi tehdä matemaattispainotteisia ohjelmia ja on tehtykin varmuudella **huomattavasti** enemmän mitä F#:lla. Mietippä myös millainen testausrumba uudelleenkirjoittamisesta olisi aiheutunut. Kun sanoin, että kyseessä on ihan aikuisten oikeasti keskeinen järjestelmä, niin myös tarkoitin sitä: tässä puhutaan nyt siitä maapallosta, ei nuppineulan päästä (edes siitä isommasta). Ja syy kokoon ei ole kielessä. On naiivia väittää, että monimutkainen ongelma ratkeaa radikaalisti helpommin jollain ohjelmointiparadigmalla. Se voi päteä siihen, että lasketaan binääripuun noodien lukumäärä parallelisti, mutta ei mihinkään reaalimaailman ongelmaan.

    Se mihin viittasit F#-referenssin√§ l√§hinn√§ huvitti minua, eik√§ v√§hiten sen takia mit√§ er√§s kollegani (huomattavasti suuremmasta yrityksest√§ mit√§ edustamani yrityksen asiakas) sanoi heitt√§ess√§√§n Microsoft-teknologiat roskikseen: "kun pit√§is joskus pysty√§ kehitt√§m√§√§n t√§t√§ bisnest√§kin eik√§ vaan konvertoida koko ajan j√§rjestelmien teknologiapohjaa". T√§ll√§ viitattiin hyvin samantyyliseen sykliin mit√§ t√§ll√§ "referenssill√§" oli; C++ (todn√§k viel√§ MS C++) -> COM (ojasta allikkoon) -> .NET (F#) -> seuraava villitys. Ja toivottavasti niill√§ kavereilla on sitten my√∂s s√§ikeiden synkronointi sun muut hallussa sill√§ "Interoperability between the .NET Framework and COM technology also means that the firm can use existing models along with new models built more efficiently with the new capabilities in F# and the Microsoft Visual Studio development system" -lause antaa pahasti viitteit√§ tilasta ja s√§iemalleista. Taas PLINQ-dokumentaatiosta "Some technologies, for example, COM interoperability for Single-Threaded Apartment (STA) components, …, impose thread affinity restrictions that require code to run on a specific thread. "

    Me teimme hommat huomattavasti pienemmässä ajassa (syklillä Java -> Java) ja me pystymme tarjoamaan koodareille esimerkiksi mutable oliot ilman minkään valtakunnan ongelmia. "Businesskoodarin" ei tarvitse tietää säikeistämisestä yhtään mitään. Säikeistäminen on muutaman kaverin erikoisongelma, jolle ei ole tarvinnut tehdä pitkään aikaan yhtään mitään. Toisaalta näiden "business as usual"-kavereiden ei myöskään tarvinnut oppia **yhtään mitään** uutta. Ja muistinko jo muuten mainita, että voimme ajaa (ja ajamme) koodia myös muilla käyttiksillä kuin Windowsilta, ja luonnollisesti ilman koodimuutoksia?

    Kun haastat lukijat isoista yli viisivuotta ylläpidetyistä projekteista, niin niitähän on vakuutusyhtiöt ja pankit täynnä. Edustamassani yhtiössäkin useita. Vanhimmat järjestelmät joita ylläpidetään ovat useita kymmeniä vuosia vanhoja. Ne on kirjoitettu ohjelmointikielellä joka on ollut stabiili kymmeniä vuosia, elikkäs COBOL:lla. Vanhimmat Java-sovelluksetkin ovat noin 10 vuoden ikäisiä, ja kyllä, niitä ylläpidetään edelleen. Samoin kertomukseni matikkapläjäys on lähes kymmenen vuotta vanha ja sitä ylläpidetään ja kehitetään edelleen agressiivisesti.

    Mitä tulee esim. prosessorien määrään ja listakäsittelyyn, niin voin kertoa, että oletuksesi on väärä. Tuolla oletuksella nimenomaan ajaudut tilanteeseen, jossa yliparallelisoit. Ei se yksi ydin aja montaa säiettä **parallelisti**, joten kun pyydät parallelismia (ilman WithDegreeOfParallelism, ja vielä erityisemmin ilman fork/join'ia) "varastat" suoritussäikeen muilta (vrt fork/join, jossa "lainaat odottavaa" säiettä). Tässä kyseisessä tapauksessa varastat siis todennäköisesti vielä itseltäsi. Tällä menetelmällä et kunnioita väitettä "More Parallelism != Better Perf", vaan saat siitä sen samaisen kalvon "performance degration" kohdat 1 (context switches) ja 2 (memory contention). Jos teet joskus jotain nuppineulaa isompaa, tulet huomaamaan että olisi pitänyt sittenkin uskoa sitä lyijyarkkitehtia. Voit myös koittaa vakuuttaa minut reaalimaailman kokemuksella, ei binääripuun noodien määrän laskemisella. Oletko nähnyt tämän varoittavan lauseen PLINQ-dokumentaatiossa (http://msdn.microsoft.com/en-us/library/dd997403.aspx): "By using the AsParallel operator, you incur the overhead costs of partitioning the source collection and synchronizing the worker threads. The benefits of parallelization are further limited by the number of processors on the computer. There is no speedup to be gained by running multiple compute-bound threads on just one processor. Therefore, you must be careful not to over-parallelize a query." Jos katsot esimerkin, voit huomata että kun niiden funktioiden kanssa sählätään ilman tiukkaa kontrollointia, niin tilanne on juurikin sama mitä siinä nested queryssä. Se on vain yksi erikoistapaus.

    Samoin en ole lainkaan samaa mieltä siitä, että suorituskyky on järkevää tehdä jälkikäteen. Se on myytti, tai mantra mitä hoetaan. Tai ainakaan useimmissa tilanteissa. Hyvä suunnittelija ja ohjelmoija osaa haistaa ongelmalliset kohdat jo suunnitteluvaiheessa (kyllä, niitä isoja järjestelmiä myös suunnitellaan). Hyvä suorituskyky ei myöskään tarkoita etteikö koodi voisi olla ymmärrettävää. Sekin on myytti. (Itse asiassa se "Karenina Jalmarin" rekursiohässäkkä on hyvä todistus juuri toisinpäin: epäselvää koodia ja todella tehotonta). Ja sitä paitsi tähän auttaa dokumentointi (tätäkin tehdää isoille järjestelmille). Nämä suunnitelmat voi sitten käydä läpi vaikka IT-arkkitehdin kanssa, joka voi ottaa kantaa hänelle kuuluvaan asiaan. Jos jo design on väärin, niin siitä seuraa massiiviset ja hyvin virheherkät koodaustalkoot. Tämäkin on todistettu jo monta kertaa siellä sun täällä.

  52. Vakuutusmies - December 29, 2011

    BTW, koska "singletonit ovat turhia", niin kertokaa minulle miten te hoidatte vaikkapa kakutuksen? Onko kyseessä kenties immutable cache, jolla ei ole mutable tilaa lainkaan? Vai onko se aina tyhjä?

  53. Tuomas Hietanen - December 29, 2011

    Tätä ketjua lukeville, alkuperäiseen tapahtumaan osallistumattomille:

    Katsokaa nuo tapahtuman diat netistä, linkki alussa (ainakin mun osalta löytyvät suomeksi ja englanniksi, ja sisältävät notes-osiossa diojen selitykset).

    Nyt mennään sivuraiteilla, mutta alkuperäinen aihe oli:

    - Miksi ottaa F# solutioniin C#:pin rinnalle: mitä varsinkin C#:pin kipupisteitä F# helposti ratkaisee.
    - Kuinka saumattomasti ja helposti nämä kaksi .NET-ympäristön virallista kieltä toimivat yhteen.

  54. Tuomas Hietanen - December 30, 2011

    Mitä tietojärjestelmien suunnitteluun tulee, mitä olen dioilla tuonut esillekin, niin olio-ihmisille on tietysti täysin käsittämätöntä, että ohjelmaa voisi tehdä top-down perjaattella, eli määritellä auton ja sitten vasta myöhemmin määritellä niitä renkaiden muttereiden muotoja. Ei vaan pitää suunnitella, mahdollisimman tarkasti, ekana ne mutterit ja niiden kierteiden toleranssit, ja kaikki parametrit, vaikka ne eivät lopullista auton käyttäjää edes kiinnosta.

    "Kun haastat lukijat isoista yli viisivuotta ylläpidetyistä projekteista, niin niitähän on vakuutusyhtiöt ja pankit täynnä. Edustamassani yhtiössäkin useita."

    Mä tiedän, että sä tiedät, että mitkä projektit ovat menneet hyvin, ja missä olisi parantamisenvaraa. Jääköön tarkempi analyysi firman sisälle, katsotaan asiaa yleisemmältä tasolta, koska softa-alalla liian usein ylitetään aikataulut ja budjetit tietojärjestelmien toiminnallisuuksien rakentamisessa.

    Kuten vakuutusalan oppikirjoissakin todetaan, niin vakuutusala toimii niin, että monesti on lakisääteisesti määrätty sisään- ja ulostulevien rahamäärien yhtäsuuruus, ja vakuutusyhtiö toimii pitkän aikavälin korkovoitoilla. Asian ohi, en kerro tarkemmin, tulos kuitenkin on, että vakuutusalalla on paljon rahaa käytössään, joka pitäisi saada käytettyä jotenkin hienosti. Sikäli vakuutusyhtiö on poikkeuksellinen asiakas (noh, valtio on voisi olla toinen).

    Ainahan hyvät raaka-aineet ovat laadukkaan tuotteen lähtöedellytys. Suuresta rahamäärästä on paljon apua:
    Raudan tai ohjelmistolisenssien hankinnoissa ei pihtailla. Jos tarvitaan parhaat Java-koodaajat, ja kalleimmat Cobol-konsultit, niin se ei ole ongelma.

    Ja jos kaikki ovat tyytyväisiä, niin hieno homma. Prosessista voi jäädä optimoimatta lopputuotteen toiminnallisuus/hinta -suhde. Harmillista että (käyttökelpoisen, bugittoman) toiminnallisuuden ja ostohinnan suhdetta on vaikea mitata. Se mitä asiakas alunperin toivoo, on *toiminnallisuutta* siihen hintaan, että rahaa jää muuhunkin. Ja se muu on mm. lisää *toiminnallisuutta*.

  55. Vakuutusmies - December 31, 2011

    Moi Tuomas,

    Ennen kuin otan kantaa mitenkään, niin selvennätkö tätä: "Mitä tietojärjestelmien suunnitteluun tulee, mitä olen dioilla tuonut esillekin, niin olio-ihmisille on tietysti täysin käsittämätöntä, että ohjelmaa voisi tehdä top-down perjaattella, eli määritellä auton ja sitten vasta myöhemmin määritellä niitä renkaiden muttereiden muotoja. Ei vaan pitää suunnitella, mahdollisimman tarkasti, ekana ne mutterit ja niiden kierteiden toleranssit, ja kaikki parametrit, vaikka ne eivät lopullista auton käyttäjää edes kiinnosta."

    Oletko siis sitä mieltä, että ilman suunnitteluakin voi tehdä *isoja* järjestelmiä?

  56. Tuomas Hietanen - December 31, 2011

    (Sotkemaan keskustelua, eri firmat käyttävät termejä määrittely&suunnittelu ristiriitaisesti.)

    Varmaan suurin projekti missä itse olen ollut mukana (tosin onneksi vain vähän yli kuukauden) on Ajoneuvohallintokeskuksen uusi tietojärjestelmä. Projektin suunnitteli silloinen TietoEnator, ja sen jälkeen se kilpailutettiin (kuten valtion kuuluu) kahden ison välillä, TietoEnatorin ja silloisen WM-Datan. Jälkimmäinen voitti, joten seuraava homma oli konvertoida Tietoenatorin speksit WM-Datan spekseihin, ja sitten WM-Data toteutti järjestelmän. Kuten valtion projekteissa kuuluu, niin määrämuotoista dokumentaatiota oli hirvittävästi. Tässä tieto miten se sitten lopulta meni, budjetti ylittyi yli tuplasti: http://sektori.com/uutinen/ake%3An-tietoj%C3%A4rjestelm%C3%A4projekti-my%C3%B6h%C3%A4styy/7732/
    (Tietysti, hölmö ei ole myyjä, vaan ostaja.)

    Parin kymmenen vuoden aikana softan kehitystyökalut ja ohjelmointikielet ovat kehittyneet niin, että sama toiminnallisuus voidaan toteuttaa huomattavasti nopeammin. Mutta onko softan suunnitteluprosessi kehittynyt vastaavasti? Tarvitaanko enää niin tarkkaa suunnitelmaa?

    Toisen ääripään esimerkki, eräässä toisessa firmassa, käytettiin Sataman konsultteja, jotka koodasivat meille softan, ja kun softa oli valmis, niin kävin kysymässä että: "Ihan hieno softa, mutta ei yhtään sitä mitä suunniteltiin. Miksi ette noudattaneet suunnitelmia?", vastaus oli, että "Meillä ei ollut käyttöoikeuksia verkkolevylle, jossa suunnitelmat ovat."

    Lähtökohtaisesti softakehittäjät osaavat tehdä softaa, joskin tarkempi softan muoto saattaa vähän elää. (Domain-driven-designissa domain-olioiden roolien muutos on tuskallisen työlästä, joka on puhdas olio-ongelma.)

    En puolusta Agile-menetelmiä, se on vain vasara muiden joukossa. Se on kuitenkin nykyään eniten muodissa. Sen toimivuus perustuu ehkä kahteen ideaan:
    - Asiakas ei osaa m√§√§ritell√§ valmiiksi. Suunnitelmat aina muuttuvat. Mit√§ jos koitetaankin tehd√§ muutoksenhallinnasta helppoa? (Tykk√§√§n ideasta keskitty√§ derivaattoihin… ;)
    - Ihmiset ovat kunkkuja, ei A4-saaste. Asiakkaalla on edustaja, jolla on oikeus päättää business-toiminnallisuudesta. Ja kun tiimi huomaa, että tarvitaan tarkempaa teknistä suunnittelua yksittäiseen hankalaan kohtaan, niin arkkitehti tai joku senior-kehittäjistä tekee yhtenä sprintin taskina design-taskin, sen kohdan speksin seuraavaan sprinttiin.

    Täten vastaan: Ilman tarkkaa etukäteissuunnittelua voi tehdä järjestelmiä. Se, että paisuuko niistä ikinä niin *isoja* on toinen juttu.

    Asiakkaan toiminnallinen m√§√§rittely l√§htee prosessissa aina top-down: "Me tarvitaan sellainen j√§rjestelm√§, ett√§…"
    Siten, eikö olisi luonnollista, jos koodauskin voisi lähteä top-down?

  57. Tietohallintomies - January 2, 2012

    Hyvät funktionalistit,

    Voisitteko kertoa miten pitäisi ratkaista seuraavanlainen ongelma funktionaalisella ohjelmointikielellä:

    Kyseess√§ on er√§√§nlainen itsepelaava peli, jossa huoneista koostuvassa labyrintissa (esim. 10×10 taulukko) kulkee kahdenlaisia √∂t√∂k√∂it√§: kissoja ja rottia. Yhteen huoneeseen mahtuu vain yksi rotta kerrallaan, samoin kuin yhteen huoneeseen mahtuu vain yksi kissa kerrallaan. Jos kissa menee huoneeseen jossa on rotta, kissa sy√∂ rotan.

    Aivan kuten reaalimaailmassakin, kaikkien eläimien pitää pystyä liikkumaan labyrintissa toistensa ajoituksista välittämättä, joten jokainen eläin on siis yhdenaikaisesti ajettava tehtävä (säie). Miten tällainen yksinkertainen ongelma ratkaistaan funtionaalisella kielellä jossa ei ole tilaa lainkaan? Oliokielillä osaisin ongelman ratkaista ja olen ratkaissutkin, mutta nyt kun olen opettelemassa funktionaalista ohjelmointia niin tuli tällainen aloittelijan kysymys mieleen.

  58. Harrastelija-Funktionalisti - January 3, 2012

    Aika olio-mallinen lähtötapa, että yksi olio on yksi threadi. F# ilmasuvoiman takia asian voi n+1 eri tavalla, mutta tässä yksi vaihtoehto (ilman mutable-tiloja, jotka F# kyllä täysin sallisi). Speksit olivat aika lyhyet, joten softastakin suuri osa on kommentointia:

    http://pastebin.com/fPe6HfaD

  59. Virtanen - January 4, 2012

    Tuo ei noudata speksejä kovin tarkkaa, ainakaan esim sen osalta, että liikkumista ei ole rajoitettu, monta saman lajin edustajaa voi olla samassa "huoneessa". Mutta se olisi helppo refaktorointi liikkumisalgoritmin kohdalle.

  60. Vakuutusmies - January 4, 2012

    Hyvä Harrastelija-Funktionalisti,

    Nyt ollaan ehkä hieman heikoilla jäillä oman **F#-osaamiseni** suhteen, mutta arvaan nyt kuitenkin ja voit/voitte sitten korjata jos olen väärässä.

    Ensinnäkin, miten ohjelma huomio sen, että kissat tahi hiiret eivät ole samassa huoneessa? Tai miten random huolehtii siitä, että niitä ei jo luodessa laiteta samaan huoneeseen?

    Toiseksi, minusta näyttäisi, että kyseessä ei sittenkään ole toisistaan riippumattomat liikeet, vaan pikemminkin kyseessä on kissojen ja hiirien huonosti toimiva sulkeisharjoitus: kaikki liikkuminen tapahtuu "samanaikaisesti". Siksi "samanaikaisesti", että mikäli oikein ymmärrän, niin liikkumistahan ei parallelisoida vaan kaikki liikkuvat peräjälkeen yhdellä rysäyksellä aina kun jonosta luetaan Receive:llä uusi liikkumiskomento.

    Tarkoitus lienee ollut mallintaa reaalimaailmaa, jossa kissat ja hiiret liikkuvat täysin toisistaan riippumatta; eri/samaan aikaan välillä miettien kukin omaan tahtiinsa minne mennä. Asynkronisuudesta tässä harjoituksessa ei käytännössä ole mitään hyötyä, sillä ymmärtääkseni suoritat yhtä aikaa kuitenkin vain yhden liikkeen kerrallaan jossa liikutat kaikkia eläimiä. Ero siihen, että tässä ei olisi asynkronisuutta lainkaan on lähes olematon.

  61. Virtanen - January 4, 2012

    Lähtökohtaisesti en näe järkeä sille, että tehdään softasta niin paljon riippuvainen ajoympäristöstä, mielestäni softan olisi hyvä toimia samalla tavalla jokaisella ajokerralla. Ihan jo testattavuuden kannalta. Mutta toki voidaan tehdä älytöntä softaa, jos halutaan.

    Funktionaalisesti ajateltuna sillä ei ole merkitystä liikkuvatko kaikki eliöt kerralla vai vain yksi: ratkaisu on kuitenkin pitää kirjaa koko lista-kaikkien-eläimien-yhteisestä-liikkumishistoriasta.

    Kääntäjä osaa optimoida tämän: Jos teemme uuden liikkumishistorian, ja koska vanha historia oli immutable linked-list, uusi historia on vain yksi node ja pointteri vanhaan historiaan, ei vaadi isoja listojenkopiointioperaatioita.

  62. Vakuutusmies - January 4, 2012

    Virtanen,

    Ensinnäkin, ei nyt aleta heti selittelemään että on väärät speksit. Saako sitä tehtyä vai ei? Toiseksi, miten se on jotenkin erityisen riippuvainen ajoympäristöstä? Ja tällä tarkoitan sitä, että kyllä vain, softa on *aina* kiinni ajoympäristössä ja muutokset ajoympäristössä (esimerkiksi kuormitus) vaikuttavat usein lopputulokseen.

    On naiivia kuvitella, että asiat olisivat stabiileja ja toimisivat aina samalla tavalla. Ensinnäkin, kun suoritat vaikkapa selectin kannasta, niin rivithän voivat tulla missä tahansa järjestyksessä jos et erikseen niitä sorttaa.

    Ja jos viittaan nyt vaikka "kaikkien funktionalistien ihannekieleen", Haskel'in lazy eval malliin.

    "However, with lazy evaluation, it is difficult to combine with imperative features such as exception handling and input/output, because the order of operations becomes indeterminate. Lazy evaluation can introduce space leaks.[5] Also, debugging is difficult.". http://en.wikipedia.org/wiki/Lazy_evaluation

    Otetaanpa sitten toinen esimerkki: koitappa generoida "sopivia" satunnaislukuja vaikkapa tollaiset 10 kpl, laske niiden yhteisumma, sekoita lukujen järjestys ja laske uudelleen. Ja tulokset ovat esimerkiksi:

    Alkuperäisellä : 181.30749015479398
    Järjestyksessä 0: 181.30749015479395
    Järjestyksessä 1: 181.30749015479387
    Järjestyksessä 2: 181.30749015479387
    Järjestyksessä 3: 181.30749015479387
    Järjestyksessä 4: 181.30749015479392
    Järjestyksessä 5: 181.3074901547938
    Järjestyksessä 6: 181.3074901547938
    Järjestyksessä 7: 181.30749015479392
    Järjestyksessä 8: 181.3074901547938
    Järjestyksessä 9: 181.30749015479392

    Sekaisin on ja ei tarvittu edes säikeitä.

    En myöskään ymmärrä tuota "Funktionaalisesti ajateltuna" -kommenttia, sillä eihän sitä pyydetty ajateltuna jollain tavalla, vaan pyydettiin että se toimii tietyllä tavalla.

  63. Vakuutusmies - January 4, 2012

    Tarkennus vielä: lopputuloksen pitää tietenkin olla sama kuormasta huolimatta, mutta esim. parallelismiaste saattaa heitellä. Samoin asioiden väliset ajoitukset.

  64. Tuomas Hietanen - January 4, 2012

    Hyvä artikkeli:

    http://msmvps.com/blogs/jon_skeet/archive/2009/11/02/omg-ponies-aka-humanity-epic-fail.aspx

    Skeet summaa: Tehdään asiat ensin helposti ja korjataan jos on ongelma.

  65. Vakuutusmies - January 5, 2012

    Hyvät funktionalistit,

    Koska sitä Tietohallintomiehen speksien mukaista funktionaalisen ohjelman kuvausta, tai sen toteutusta, ei ole kuulunut, niin ajattelin antaa mallia millaista outputtia tällainen ohjelma voisi esimerkiksi tuottaa. Tämä esimerkki on toteutettu oliokielellä (olkoon anonyymi).

    Joten nyt sitten vaan jatketaan sen funktionaalisen version odottelua ;-) Ai niin, toki my√∂nn√§n ett√§ t√§m√§ ei skaalaudu m√§√§r√§√§ns√§ enemp√§√§, sill√§ s√§ikeiden maksimi tulee joskus vastaan kuitenkin. Mutta se nyt ei t√§ss√§ ollutkaan pointti, vaan piti pysty√§ pelaamaan laudalla jonka koko on esim. 10×10.

    Ja palatakseni vielä siihen F#-versioon, jossa ei oikeastaan ollut kuin luuppi jossa liikutellaan kaikkia eliöitä yhtä aikaa: voi olla hieman haastavaa löytää rautaa jossa laudan koko on ääretön. Jos demoat vaikka sellaisen esimerkin jossa laudan leveys on 2^65 niin saat papukaijamerkin.

    10:14:59.170 : Running 60 threads concurrently
    10:14:59.170 : Number of cores is 4 and thus true parallelism degree is restricted to 4
    10:14:59.170 : Predators annihilate each other on collission is set to true
    10:14:59.178 : Initial location of Cat 18 is set to (1, 5)
    10:14:59.178 : Initial location of Cat 15 is set to (2, 7)
    10:14:59.178 : Initial location of Cat 25 is set to (3, 1)
    10:14:59.178 : Cat 15 moved from (2, 7) to (2, 8)
    10:14:59.178 : Cat 25 moved from (3, 1) to (3, 2)
    10:14:59.178 : Cat 18 moved from (1, 5) to (0, 4)
    10:14:59.178 : Cat 25 thinking 568 millisecs before next move
    10:14:59.178 : Cat 18 thinking 150 millisecs before next move
    10:14:59.178 : Cat 15 thinking 576 millisecs before next move

    10:14:59.180 : Initial location of Rat 24 is set to (0, 0)
    10:14:59.180 : Thread pool-1-thread-2 serving Cat 2 is returned to the pool
    10:14:59.180 : Initial location of Rat 28 is set to (4, 3)
    10:14:59.180 : Rat 24 couln't move due to congestion near (0, 0)
    10:14:59.180 : Destroyed Rat 28 at (4, 3)

    Survived animals are (14) :
    Rat 24 at location (2, 3)
    Rat 26 at location (3, 3)
    Rat 9 at location (3, 4)
    Rat 19 at location (3, 5)
    Rat 7 at location (4, 0)
    Rat 17 at location (5, 3)
    Rat 18 at location (5, 5)
    Cat 23 at location (6, 2)
    Rat 22 at location (6, 3)
    Rat 16 at location (6, 6)
    Cat 13 at location (7, 0)
    Rat 12 at location (7, 8)
    Cat 8 at location (9, 7)
    Cat 26 at location (1, 8)

  66. Tuomas - January 8, 2012

    Vakuutusmies,

    "Koska sitä Tietohallintomiehen speksien mukaista funktionaalisen ohjelman kuvausta, tai sen toteutusta, ei ole kuulunut,"

    Millä tahansa yleis-ohjelmointikielellä voi tehdä minkä tahansa softan, sitä tuskin tarvitsee erikseen demota. Vai onko matalan tason näpertelyn taka-ajatus pitää koodaajat pois hyödyllisen softan koodaamisesta?

    Sen sijaan aiempi sulkeisharjoitus oli musta hyvä pointti, joten sen verran innostuin leikkimään koodilla, että vaihdoin koodin LiikutaKaikki-memberin rekursioimaan kaikki eläimet läpi ja postaamaan oliot yksitellen. Tein sen oletus-stäkillä, mutta Rx-kirjastoa käyttäen olisi kyllä tullut vielä siistimpi.

    Mikä on olio-ohjelmoinnin idea:
    Eristetään omat asiakokonaisuudet omiin erillisiin palasiinsa (joka auttaisi mm. helpottamaan refaktorointia).

    Mikä on "tila", miksi tilattomuus on hyvä asia:
    Tila on merkki siitä, että kommunikaatio kahden osapuolen välillä on kesken.
    Se (esim. temp-muuttuja) aiheuttaa sen, että näiden asiakokonaisuuksien toiminnallisuuksia ei voi yhdistellä vapaasti.

    Siksi oliot eivät ole omia erillisiä palasiaan.
    Olio-ohjelmointi oletuksena ei ohjaa hyvään (tilattomaan) koodaustapaan, joskin tilaton koodaus on mahdollista.

    Refaktorointi uudelle vaatimukselle (2^65-lauta) onnistuu vaihtamalla int-tietotyyppi bigint-tietotyypiksi.
    (K√§yt√§nn√∂ss√§ bigint on vain 2^64, mutta sen voi kiert√§√§ rakentamalla x-akselin kahdesta muuttujasta…)
    Lisäksi jos halutaan, että hiiri osaa hypätä, niin voidaan siirtyä 2D-koordinaatistosta 3D-koordinaatistoon.

    En ole nähnyt olio-version koodia, mutta tuolla pastebin-f#-koodilla seurasin vierestä kun koodia ennestään tuntematon f#-koodaaja teki bigint ja 3D-koordinaatisto -muutokset alle 7min ajassa. (Myös vahvasti tyypittävä kääntäjä auttaa paljon.)

  67. Vakuutusmies - January 8, 2012

    "Sen sijaan aiempi sulkeisharjoitus oli musta hyvä pointti, joten sen verran innostuin leikkimään koodilla, että vaihdoin koodin LiikutaKaikki-memberin rekursioimaan kaikki eläimet läpi ja postaamaan oliot yksitellen."

    Eli mikäli oikein ymmärsin, niin elukat (eivät siis oliot) liikkuvat nyt dedikoidussa säikeessä, kuitenkin vieläkin yksi kerrallaan? Jos liikkuvat yhtä aikaa, niin miten selvität vapaan huoneen ongelman (kaksi eläintä on juuri liikkumassa samaan paikkaan)?

    Syy miksi "lauta" voi olla bigint-tyyppinen on se, että oikeasti siinä ei ole mitään lautaa vaan koordinaatit. Mutta se taas taitanee tehdä sen, että kaksi elukkaa ei voi siirtyä yhtä aikaa. Jos meinaa siirtyä niin pitää selvittää onko ko. huoneessa ketään ja sitten alkaakin olla lukitusten aika. Muutoin selvityksen aikana tilanne voi muuttua ja tuleekin tehtyä väärä päätös. Tai voi sen tehdä muullakin tavalla, mutta lukkoa pitää käyttää joka tapauksessa.

    3D koordinaatistohan on ihan kakunpalanen (nyt HashMap:n avaimena Location, jossa x,y -> x, y, z). Ja voisin toki myös tehdä olioillakin nopsaan tuon isomman koordinaatiston (int x -> BigInteger x, etc), mutta sen rakenteen täyttäminen olisikin jo sitten haastavampi tehtävä. Itse venytin samplea siihen suuntaan, että joka eläimellä on elinaika ja sen kuluttua "eläin" poistaa *heti* itsensä pois pelistä. Jälleen yksi toimenpide missä tarvitaan dedikoitua säiettä (joko omaa tai timerin käyttämää).

    Mutta liikkuvatko ne eläimet siis nyt yhtä aikaa, ehkä funtsaten välillä, vai eivät?

    Ai niin, onneksi olkoon muuten ;-) F# oli taas noussut TIOBE:n listalla, joskin noin yleisesti ottaen funktionaaliset kielet vs oliokielet kääntyi olioiden voittoon (taas) lähinnä C#:n johdosta. Mutta aika kaukana ollaan vielä, sillä F#:n sijahan oli 33. Mutta onhan se ihan hyvin jos vertaa vaikka Scalaan, joka ei ole edes tarkan numeroinnin parissa (sijoitus on > 50).

  68. Vakuutusmies - January 8, 2012

    "Olio-ohjelmointi oletuksena ei ohjaa hyvään (tilattomaan) koodaustapaan, joskin tilaton koodaus on mahdollista."

    Tilaton hyvä. Kuten jo aiemmin kerroinkin, niin voihan säikeiden kanssa ihan vapaasti käyttää tilaa niin paljon kuin sielu sietää ilman minkään valtakunnan ongelmia. (Kts. esim. http://codeidol.com/java/java-concurrency/Sharing-Objects/Thread-Confinement/). Kyse on vaan siitä, että pitää ymmärtää mitä tekee. Esimerkiksi Javassa web-pyyntöjen (HttpServletRequest) olio *on tilallinen* (ja niinpä se taitaapi olla myös .NET:ssä), mutta siitä ei käytännössä aiheudu koskaan mitään ongelmaa. Tämä siitä syystä, ei sitä ei jaeta toisille säikeillä. Vain jaetuissa olioissa (esim. HttpServlet) tila on ongelmallinen, tai tarkemmin ottaen sitä pitää osata käsitellä oikein.

  69. Vakuutusmies - January 8, 2012

    Tuomas,

    Kun viittasit jossain vaiheessa muihin kieliin, jotka ratkaisevat Java "ongelmia", niin ihan ongelmatonta ei ole ton non-Microsoft puolen funktionaalinen ohjelmointikaan.

    http://lift.la/scalas-version-fragility-make-the-enterprise
    http://www.infoq.com/news/2011/11/yammer-scala
    http://www.tietoviikko.fi/artikkelikommentointi/?action=thread&thread=737637

  70. Vakuutusmies - January 8, 2012

    Hmm,

    Johtuikohan tuo moderointiodotus minusta vai jostain muusta?

  71. Jouni Heikniemi - January 9, 2012

    Moderointiodotukset johtuvat Akismet-pluginista, joka luultavasti katsoi sis√§lt√∂√∂n n√§hden runsaan linkkim√§√§r√§n suspektiksi. Mutta ei se siell√§ moderointijonossa puolta tuntia pidemp√§√§n hapantunut…

  72. Vakuutusmies - January 9, 2012

    Ahaa,

    Taas oli lähtenyt merkkejä sensuroitu. Yllä olevassa tekstissä luki siis

    Tilaton hyvä

    kun siinä piti lukea

    Tilaton on erisuuri kuin hyvä, pienempikuin ja suurempikuin merkeillä.

  73. Tuomas - January 9, 2012

    En laittanut koodiani nettiin, koska en ollut tyytyväinen ratkaisuuni määrittää "henkilöturvatunnuksia" päättelyyn, että kenellä on oikeus liikkua seuraavaksi (ellei se ole täysin random).

    "Jos nyt puhutaan realistisesti peiliohjelmoinnista, niin moniko tetris-koodaaja lähtee koodaamaan joka palikalle oman säikeensä?"

    Jos kuitenkin lähtee, niin "pelilaudan" on synkattava olioiden välillä. On kaksi tapaa:
    1) Helpoin, ja yleensä aina käytännössä riittävä:
    Tehdään laudan käsittely yhdessä säikeessä. Silloin ongelmia ei ole. Reaktiivisesti: otetaan koppi siitä, että joku olioista saa siirron tehtyä. F#:lla tämän voi tehdä joko ihan perus-koodilla, Rx-kirjastolla, tai myös niin, että laudan tarkistus ajetaan omassa async-threadissa (MailboxProcessor-instanssissa), joka juttelee muiden async-olioiden kanssa.
    2) Optimistinen: Ensimmäinen liikkuja on se, joka saa oman siirtohistoriansa läpi, ja lopuilla, anteeksi eläinrääkkäys, heitetään vesilintua. Käytännössä nykypäivän isot enterprise-vesilinnut voivat ottaa kopin ja mergata muutoksia muiden kanssa, jolloin päästään samoihin ongelmiin kuin Fowlerin PoEAA-patternissa "Unit of Work".

    Joo, tuo Scalan taaksepäinyhteensopivuus (ja muistaakseni vuosi sitten Clojurella oli sama juttu) on sellainen juttu, että se on pakko saada kuntoon, jotta softaa voidaan enterprise-ympäristössä kehittää. Olisin olettanut, että Scalan tekijät ovat jo näistä "kasvukivuista" päässeet yli, mutta ilmeisesti sitten ei. Se on vaan jossain vaiheessa kielisuunnittelijan myönnettävä itselleen, että "tästä tuli nyt vähän tällänen".

    Lopultahan tuo taaksepäinyhteensopivuus on juuri se, joka tekee kielestä sitten vuosien saatossa vanhentuneen, kun merkittäviä uusia ominaisuuksia ei voida enää kieleen tuoda rikkomatta entisiä.

    (Javan lisäksi) myös C# alkaa olla lähellä tätä pistettä. Sen (ja muitakin mielenkiintoisia pointteja) tuo esille pää-arkkitehti Anders Hejlsberg (C#) toisen kielisuunnittelijan, Gilad Bracha (Newspeak) kanssa:
    http://channel9.msdn.com/Blogs/Charles/Anders-Heljsberg-and-Gilad-Bracha-Perspectives-on-Programming-Language-Design

  74. Vakuutusmies - January 9, 2012

    "Jos nyt puhutaan realistisesti peiliohjelmoinnista, niin moniko tetris-koodaaja lähtee koodaamaan joka palikalle oman säikeensä?"

    Ei kukaan, sillä tetriksessä putoaa vain yksi pala kerrallaan. Ihan eri peli ;-) Ei siis ole tarvetta säikeille.

    Ko. "Tietohallintomiehen haasteen" ei ollut tarkoitus olla "järkevä peli", vaan sen oli tarkoitus näyttää, että joskus sitä tilaa tarvitaan ja silloin sitä pitää osata käsitellä. Ei liene täysin sattumaan että F#:ssa on funktio nimeltä lock? Ja edelleenkin tilaa ja lukkoja tarvitaan jos alkuperäiset speksit huomioidaan: useampi kuin yksi voi liikkua *samaan aikaan*, think time voi vaihtuilla per olio (liikkuminen ei siis perustu reaktioon, vaan vapaaseen tahtoon) ja "väärä pari" eläimiä ei saa mennä samaan huoneeseen. Itse lisäsin siihen vielä sen, että eläin voi kuolla vanhuuteen ja poistaa tällöin itse itsensä pelistä *heti*, joka siis myös tuo säikeet peliin. Mutta tätähän ei ollut alkuperäisissä "spekseissä".

    Jos voit tarkentaa esimerkiksi tuota reaktivisuus-juttua ja minä puolestani kerron sitten miksi se ei toimi speksien mukaan. Ja mitä tulee siihen MailboxProcessor-kuvioon, niin siinähän pitää sitten tehdä siten, että pyydät erillistä säiettä varmistamaan *ja* varaamaan paikan. Voi olla, että se ei onnistu ja sitten pyydät taas uudestaan. Kaiken prosessoinnin teet varmaankin sitten postaamalla kamat sisään ja odottamalla vastausta, ja siten tätä toimintaa palvelee *yksi* säie (se jossa MBP ajetaan, ja juuri siksihän et tarvitse lukkoa koska kaikki toiminta on sarjallistettu) ja aina käydään kaikki elukat läpi. Näin ollen parallelismiaste on jotain ihan muuta kuin esimerkiksi omassa OO-toteutuksessani, jossa otan lukon, teen yhden compare:n, mahdollisesti yhden non-volatile write:n ja vapautan lukon. Kaikki (esim. 60) säikeet ovat koko ajan ajossa täysillä ja sarjallistettu osuus on siis tuo edellä mainittu käskysarja. Tällä ei tietenkään *tässä* ole käytännössä mitään merkitystä, mutta mikäli teet jotain hieman monimutkaisempaa, niin saattaapi olla että romahdutat suorituskyvyn (viitaten taas Amdahlin lakiin), sillä lisäät sarjallisen (non-parallel tai sequential, miten vaan) koodin osuutta. Pari tällaista peräkkäin ja se on moro.

    Ainahan voi sanoa, että ei ole tarvis tehdä yhtäaikaa mitään, mutta kun olen niin monta kertaa urani aikana nähnyt niin kyllä pitää. Tästä esimerkkinä vaikkapa se matematiikkaongelma minkä kuvasin.

  75. Tuomas - January 10, 2012

    Se, että samat asiat voidaan tehdä usealla eri tavalla lisää ohjelmointikielen ilmaisuvoimaa.
    Se, että ohjelmointikieli ohjaa käyttäjää tekemään intuitiivisesti asiat hyvällä tavalla on kielen hyvyyttä.

    F#:ssa ei ole lock-funktiota siksi, että sitä pitäisi käyttää, vaan siksi, että sitäkin voi käyttää.

    Se on eri ohjelmointimalli.

    Mailboxprocessorisssa on concurrency ratkaistu jo ohjelmointikielen tasolla, samoin kuten tulevassa C# async:issa. En tunne tarkkaan sen sisäistä toimintaa ("se vaan toimii"), mutta alan ottaa selvää. :-)
    http://stackoverflow.com/a/2219907

    Reaktiivinen ohjelmointi on lyhyesti sanottuna sitä, että observer design pattern (GoF) on matemaattisesti sama kuin Iterator design pattern (myös GoF), mutta katsottuna eri näkökulmasta. Käytännössä se toimii niin, että tapahtumat ajatellaan ikuisina laiskoina listoina, jotka täyttyvät sitä mukaa kun tapahtumia alkaa tapahtua. Esim: Hiiren klikkaukset ovat vain lista olioita (joissa on koordinaatit), ja niistä filtteröidään kyselyllä ne, mitkä meitä kiinnostavat. Tästä selityksestä ymmärsi ainakin sen, että olen huono selittämään, mutta onneksi tästäkin on useita Channel9-videoita. Esim. tämä: http://channel9.msdn.com/shows/Going+Deep/Expert-to-Expert-Brian-Beckman-and-Erik-Meijer-Inside-the-NET-Reactive-Framework-Rx/

    Kuten muissakin, vierellä on linkki downloadattavaan videoon, joka ei ole Silverlight.

    Ps. Kyllä, olen kotona tiskatessani katsellut yli 50 tuntia (lähinnä teoreettisen puolen) Channel9 videoita, joten osaan suositella niistä parhaita. :-D

  76. Vakuutusmies - January 10, 2012

    State-of-the-art F#-ohjelmointia maailmalta:

    http://through-the-interface.typepad.com/through_the_interface/2010/11/misusing-mutable-state-with-f-asynchronous-workflows.html

    Tämä Autodesk-aasi on ..sessa muutaman hassun kokonaisluvun kanssa. Juuri tätä tarkoitin. Voiko joku oikeasti olettaa, että tällainen toimisi multicore-ympäristössä ilman lukkoja tai jotain compare-and-swap härpäkettä? Näköjään voi.

    "
    So it could be that the increment operation gets executed on two or more threads at exactly the same time. And if two threads read the variable at the same time, and then increment it before saving it back, we effectively lose one of our increment operations.

    This is all fairly unlikely…"

    Ehdottaisin, että ko. kaveri jättäisi nyt heti näppäimistön rauhaan ja siirtyisi lukemaan sitä paljon paasaamaani muistimallia.

    Tässä hyvä esimerkki siitä, että kun ei ymmärrä miten kone toimii, niin sitten pistetään pää pensaaseen ja toivotaan parasta. Ja miten hän sitten ratkaisee tämän "mystisen ongelman"?

    "In the end I decided to set a Boolean flag in the ‚Äúall jobs completed‚ÄĚ event, which avoids us having to count the completed tasks at all."

    Ikävä kyllä tämäkään ei tietenkään toimi, mutta hieman eri syystä (jota hän ei siis vieläkään ole keksinyt). Muutamalla lock-funktion kutsulla homma olisi hoitunut paljon vähemmällä häsläämisellä.

  77. Tuomas - January 11, 2012

    Mulle tulee vastaan l√§hes p√§ivitt√§in uutta bugista C#-koodia, jossa mutable tilalla aiheutetaan sivuvaikutuksia, joita koodaaja itse ei ole ymm√§rt√§nyt. (Blogeista tietty, ei tietenk√§√§n t√∂iss√§ meid√§n Intialaisten koodeista… ;)

    Koska F#:lla voi tehdä kaiken mitä C#:llakin (ja vähän enemmänkin), niin kyllä sillä voi myös käyttää mutable tilaa "väärin". Siinä on vaan se ero, että oletuksena mikään ei ole mutable-tila, vaan koodaajan pitää ymmärtää, että nyt hän on tekemässä poikkeuksen. Siksi ongelmia on niin paljon vähemmän, että niitä joutuu etsimään Googlen kanssa.

    Sehän monadien (kuten async) idea on, että niin kauan kuin pyörit monadin sisällä, niin ongelmaa ei ole, mutta sitten kun sieltä tullaan ulos (sivuvaikutuksella tai synkkauksella käyttöliittymäthreadiin tai miten vaan), niin siinä kohtaa se sivuvaikutus on. Tässäkin on se ero, että tiedän tasan tarkkaan missä kohtaa koodia on mahdollinen bugi, eikä niin, että se jakautuu tasaisesti minne sattuu tuhansien rivien joukkoon.

    Sivuvaikutusta voi välttää siten, että mennään monadiin sisään funktioparametrilla, jolloin varsinaista takaisinsynkronointia ei tarvita, vaan monadi suorittaa halutessaan funktioparametrin. Tällöin tietysti on mahdollista koodata sivuvaikutus funktioparametriin, ja jälleen tiedetään tarkalleen missä on mahdollinen bugi.

    Haskell:issa ei ole ollenkaan sivuvaikutuksia (=et pääse monadeista oikein ulos). Sen menestymättömyys kuitenkin osoittaa, että "mahdollinen bugi" on usein niin paljon helpompi koodata kuin matemaattisesti toimiva softa, että "mahdolliset bugit" kannattaa silloin tällöin sallia.

    Tuossa hiiri-mallissa voidaan myös laudan tarkistukset tehdä ilman mutable-tilaa. Jälleen tapoja koodata on useita, mutta tässä vain pari esimerkkiä:

    a) hiiri voi tarkistaa onko elossa sillä, että meillä on *muuttumaton* historia kissojen liikkeistä, ja siitä viimeisin laudan tilanne. Se, että onko hiiri elossa, true/false on aika triviaalia yhdistellä ilman lukkoa: false+true=false.
    Ja tämä oliokohtaisesti joka hiirelle eri säikeessä.

    b) Tai laudankin voi jakaa niin, että meillä on vaikka säiekohtaisesti monitorit tietyille alueille koordinaatteja (vaikka jokaiselle omansa, jos olisi ääretön määrä prosessoreita) ja taas tiedetään, että onko laudalla hetkellä t: kissa, hiiri, vai tyhjä. Jos on tyhjä+hiiri, on hiiri, jos on kissa+tyhjä=kissa ja jos on kissa+hiiri=kissa.

    Sivuvaikutuksettomuus (ja function composition) takaa sen, että threadien suoritusjärjestyksellä ei ole merkitystä: a+b = b+a. (Ja nyt puhuttiin kissoista ja hiiristä; tähän on turha vetää mitään satunnaislukuesimerkkiä: satunnaislukujen generointi perustuu aina itsessään sivuvaikutukseen: koneelle ei mikään ole satunnaista).

    Tuossa aiemmin joku nosti esille concurrencyn ja parallel executionin erot. Concurrency on nykyp√§iv√§√§ kaikkialla. K√§ytt√∂liittym√§√§ ei saa lukita, jne…

    Mutta parallel execution (jota kissa-hiiri-peli edustaa) on poikkeustapaus, jota tarvitaan yleensä vasta suorituskykyoptimoinneissa.
    Parallel executionia vaativat softat ovat usein joko:
    a) paljon laskuoperaatioita tekeviä softia (kuten kääntökoneet tai aiemmin esille tuotu eräajosofta) tai
    b) huonosti koodattua business-softaa, joka ei tarvitsisi sitä ollenkaan, jos softa olisi koodattu järkevästi, ilman tuhansien rivien turhaa koodia (joista osa voi olla, ironista kyllä, alunperin tehty suorituskykyoptimoinneiksi, ennen kuin asiakkaan vaatimukset muuttuivat).
    Siten kuulostaa ihan hyvältä ohjeelta, että jos ei tiedä mitä tekee, niin kannattaa jättää parallel execution sikseen.

    Mutta sama p√§tee kyll√§ jossain m√§√§rin muuhunkin koodaukseen: Alun perin tehtiin "ohjelmointi"-kieli, joka on niin helppo, ett√§ business-ihmisetkin osaavat sit√§ k√§ytt√§√§. Kuitenkin t√§ss√§ v√§h√§n ep√§onnistuttiin… Arvaa kielen nimi: Cobol, Visual Basic, SQL, vai kaikki n√§ist√§?

  78. Vakuutusmies - January 11, 2012

    Tuomas,

    "Mailboxprocessorisssa on concurrency ratkaistu jo ohjelmointikielen tasolla, samoin kuten tulevassa C# async:issa. En tunne tarkkaan sen sisäistä toimintaa ("se vaan toimii"), mutta alan ottaa selvää. :-)"

    Vakuutusmies kyllä auttaa. Aja tämä F# interactive:ssa ja nauti sen sarjallistamista suorituksesta ;-) Eli toimii, mutta juuri kuten epäilinkin. Näitä vaan käyttöön ja ohjelman parallelismi saadaan hävitettyä todella vähällä koodilla ja merkeillä, paljon vähemmällä mitä imperatiivisellä koodauksella kuluisi ;-)

    Muihin asioihin (niihin hiirien liikkumisiin, säikeisiin ja immutableihin) palaan myöhemmin. Tässä nyt tällainen viritelmä, jota saa toki kommentoida. Se on nimittäin ensimmäinen tekemäni F#-pätkä. Nähtäväksi jää, onko se myös viimeinen ;-)

    open System.Threading

    type Message =
    | Add of int
    | Get of AsyncReplyChannel
    | Quit

    let boxi = MailboxProcessor.Start(fun inbox ->
    let startTime = System.DateTime.Now.Ticks
    let rec loop( msgordinal, n ) =
    async {
    let! msg = inbox.Receive()
    match msg with
    | Get(replyChannel) ->
    replyChannel.Reply( n )
    return! loop( msgordinal + 1, n )
    | Add(x) ->
    do! Async.Sleep 2000
    printfn "Number of messages STILL in the queue: %d" inbox.CurrentQueueLength
    let span = System.TimeSpan(System.DateTime.Now.Ticks – startTime)
    printfn "Processing message %d in thread %d, %s after start of this MailboxProcessor" msgordinal Thread.CurrentThread.ManagedThreadId (span.ToString("G"))
    return! loop( msgordinal + 1, n+x )
    | Quit -> return ( )
    }
    loop( 0, 0 )
    )

    [1 .. 10] |> List.iter( fun x -> boxi.Post( Add x ) )
    printfn "And now start some serious waiting for results"
    let count = boxi.PostAndReply(fun replyChannel -> Get( replyChannel) )
    printfn "And (finally) we got response: %d" count

  79. Tuomas - January 11, 2012

    Tää blogi rikkoo koodit. Sisennykset häviää. Kannattanee käyttää vaikka (f#-syntax-highlightinkin osaavaa) pastebiniä, fsssnippiä tai githubia.

  80. Vakuutusmies - January 11, 2012

    Tuomas,

    Kissat&Hiiret -kamppailussa versiosi kohtaan a tulee tiukkaa kritiikkiä, sen jo tiedän, mutta mites ne monitorit kohdassa b. Mitä tarkalleen ottaen tarkoitit niillä?

  81. Tuomas - January 11, 2012

    Tuon sai toimimaan kun lisäsi puuttuvat suurempikuin & pienempikuin merkit ja miinuksen vaihtoi tavuviivasta miinukseen.

    Tässä on malliksi käytännön softa, joka surffaa netissä parallel executionilla asynkronisesti synkaten tuloksen konsolille:

    http://fssnip.net/65

  82. Torvi (totuuden) - January 11, 2012

    Vakuutusmies,

    Hienoa, että aloit kuitenkin tutustumaan F#:iin :)

    Esimerkissäsi olet eksplisiittisesti pyytänyt, että serialisoi suorittaminen. Mailprocessor on message passingiin (Actor) pohjautuva tsydeemi, ja esimerkissäsi olet pyytänyt odottamaan unit tyyppistä sivuvaikutusta.

    Tässä on korjaus esimerkkiisi:
    http://www.fssnip.net/9Y

    ja alla on suoritus interactivessa:

    And now start some serious waiting for results
    Number of messages STILL in the queue: 10
    Processing message 0 in thread 6, 0:00:00:00,0060003 after start of this MailboxProcessor
    Number of messages STILL in the queue: 9
    Processing message 1 in thread 6, 0:00:00:00,0070004 after start of this MailboxProcessor
    Number of messages STILL in the queue: 8
    Processing message 2 in thread 6, 0:00:00:00,0070004 after start of this MailboxProcessor
    Number of messages STILL in the queue: 7
    Processing message 3 in thread 6, 0:00:00:00,0080005 after start of this MailboxProcessor
    Number of messages STILL in the queue: 6
    Processing message 4 in thread 6, 0:00:00:00,0080005 after start of this MailboxProcessor
    Number of messages STILL in the queue: 5
    Processing message 5 in thread 6, 0:00:00:00,0080005 after start of this MailboxProcessor
    Number of messages STILL in the queue: 4
    Processing message 6 in thread 6, 0:00:00:00,0090005 after start of this MailboxProcessor
    Number of messages STILL in the queue: 3
    Processing message 7 in thread 6, 0:00:00:00,0090005 after start of this MailboxProcessor
    Number of messages STILL in the queue: 2
    Processing message 8 in thread 6, 0:00:00:00,0090005 after start of this MailboxProcessor
    Number of messages STILL in the queue: 1
    Processing message 9 in thread 6, 0:00:00:00,0100006 after start of this MailboxProcessor
    And (finally). we got response: 55

    type Message =
    | Add of int
    | Get of AsyncReplyChannel
    | Quit
    val boxi : MailboxProcessor
    val count : int = 55

    > 0 woke up
    3 woke up
    4 woke up
    5 woke up
    6 woke up
    7 woke up
    8 woke up
    9 woke up
    1 woke up
    2 woke up

    Serious waiting, huh? ;)

  83. Torvi (totuuden) - January 11, 2012

    Tein vielä simppelin esimerkin, joka on lähempänä "tavallista casea" rinnakkain suorittamisessa.

    http://fssnip.net/9Z

    Interactiven tulostus:
    item of 2 starts is calculation at 0:00:00:00,0060003
    item of 3 starts is calculation at 0:00:00:00,0090005
    item of 4 starts is calculation at 0:00:00:00,0090005
    item of 5 starts is calculation at 0:00:00:00,0100005
    item of 1 starts is calculation at 0:00:00:00,0060003
    item of 1 processed at 0:00:00:00,1260072
    item of 2 processed at 0:00:00:00,2150123
    item of 3 processed at 0:00:00:00,3120178
    item of 4 processed at 0:00:00:00,4100234
    item of 5 processed at 0:00:00:00,5150294
    Result of computations is 20
    Real: 00:00:00.518, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0

  84. Torvi (totuuden) - January 11, 2012

    vielä edelliseen, laittamalla parametriksi listan
    [1..200]

    interactive:
    ….
    item of 200 processed at 0:00:00:20,0471467
    Result of computations is 20300
    Real: 00:00:20.063, CPU: 00:00:00.046, GC gen0: 0, gen1: 0, gen2: 0

  85. Vakuutusmies - January 11, 2012

    Torvi,

    Ei, ei, ei. MailboxProcessor *sarjallistaa* ja se mitä sinä teit on se, että käynnistit uuden työn eri säikeessä poolista. "Async.Start starts the asynchronous computation in the thread pool. Do not await its result." Kts. http://msdn.microsoft.com/en-us/library/ee353487.aspx. Eikö helpompaa olisi sitten vaan käynnistää koko homma omassa säikeessään ja unohtaa koko mbp? Eli siis näin

    async {
    do! Async.Sleep 2000
    printfn "%d woke up" 1
    } |> Async.Start

    Koska sleepissä ei useinkaan ole mitään järkeä, eikä ainakaan asynkronisesti, niin tuntuu hieman oudolta laittaa se ja tulostus omaan säikeeseensä. Vai oletko kenties eri mieltä? Itse pistin sen sleepin siihen ikäänkuin simuloimaan raskasta laskutoimitusta.

    Mutta laitappa myös itse laskutoimitus sinne ja katsotaan sitten onnistutko siinä ja toiseksi tuleeko oikeita tuloksia. Tällöinhän se lopussa oleva Get palauttaa jotain hyvin satunnaista, riippuen siitä missä vaiheessa laskennat ovat. Tai tietenkin lukoilla voit hoitaa homman ;-)

    Seeking for it. Huh? ;-)

  86. Vakuutusmies - January 11, 2012

    Torvi,

    Niin, tolla uudella esimerkillähän nyt ei sitten enää ole mitään tekemistä mbp:n kanssa. Ja ainoa asia mitä se todistaa on se, että monta säiettä voi nukkua yhtäaikaisesti kuluttamatta sepua (ja näin ollen seinäkelloaikaakaan ei kulu kun se n * 100 ms).

  87. Torvi (totuuden) - January 12, 2012

    Minusta toi sleep nimenomaan kuvaa unit tyyppistä side-effectiä, eikä mitään raskasta laskutoimitusta. Mikäli halutaan tehdä raskas laskutoimitus, ja yhdistää tulokset niin silloin toi jälkimmäinen tapa on parempi tapa tehdä asia. Message passing ei ole mikään yleissapluuna, itse asiassa async -lohkot on ainakin sen 50x yleisempi.

    Lukoilla? Montako lukkoa tarvittiin esimerkissä kaksi? Montako itse laittaisit siihen? Ehkäpä voisit pikkuhiljaa pastebinittää omaa koodiasi "anonyymillä oliokielellä" niin nähdään miten elegantti, hieno ja helppotajuinen ratkaisu on kyseessä?

  88. Torvi (totuuden) - January 12, 2012

    Esimerkin 2 ideana ei kyllä ollut demonstroida CPU:n kulutusta.

  89. Vakuutusmies - January 12, 2012

    Torvi,

    Voin laittaa sen heti kunhan joku ensin toteuttaa saman asian. Tai edes kertoo miten asia voidaan toteuttaa ilman lukkoja. Eikä siinä ole kyse siitä onko se elegantti vai ei; se on toistaiseksi ainoa joka toteuttaa speksin, toimii ja ainakin minä ymmärrän miten se toimii. Kaikki muut ovat olleet joko yhdessä tai kahdessa (toinen turhaan) säikeessä ja niistä on puuttunut esimerkiksi thinktime. Ne ovat siis elegantilla ja vähällä koodilla toimineet toisin mitä speksattiin.

    Minähän olen sitä mieltä, että ilman lukkoja tai vastaavaa mekanismia (esim. MailboxProcessor sarjallisena) ongelmaa ei saa ratkaistua. Minun on vaikea tehdä ohjelmaa jolla todistan, että jollain tavalla sitä ei saa ratkaistua. Mutta ne jotka ovat sitä mieltä että lukkoja ei tarvita, niin heitä pyytäisin todentamaan asian.

    Oma kissat/hiiret/koirat -toteutukseni on noin 400 riviä sellaista löysää Javaa, mutta sitä ei voi verrata mihinkään koska se on a) ainoa speksit+ toteuttava toteutus ja b) en ole pyrkinyt pieneen rivimäärään koska mielestäni se ei ole tämän homman juju. Lisäksi siinä on extra-toiminnallisuutta, mm. eläimien kuoleminen vanhuuteen timerin avustuksella. Ja koska "Terävän mukaan scala tarvitsee noin puolet javan rivimäärästä", niin olettaisin että jos näin siis Scalallakin, niin F#:lla koko homma on sitten varmaan huomattavasti alle 200 riviä. (Ja lukkoja käyttäen se voi jopa ollakin). Mielestäni olisi myös hieman noloa jos ensimmäinen F#-toteutus sitten tulisi minulta, aloittelijalta.

    Ja sitä nyt en ala selittämään enää miksi CPU:n käyttämättäjättämistä (eli sleep) voidaan suorittaa yhtä aikaa.

  90. Vakuutusmies - January 12, 2012

    Torvi,

    Olisin myös hieman "perinteinen" tuollaisten frasien kanssa kuten 50x yleisempi. Tulee vähän samanlainen olo kun Lorealilla saa 30 % tuuheammat hiukset (ehkä vaikka niitä ei olisikaan) ;-)

  91. Vakuutusmies - January 12, 2012

    No niin,

    Koodirivejä on näköjään kaikkine rajapintoineen yli 500. Itse tilanhallintaan liittyvät lukot sun muut ovat hyvin yksinkertaisia. Esim. AbstractAnimal:ssaa ei ole yhtään lukitusta, mutta volatile- ja atomic-kenttiä kylläkin. Maze lukitaan aina siirron vahvistamisen ajaksi.

    http://pastebin.com/WwvvUqxF

  92. Tuomas - January 12, 2012

    Vakuutusmies,

    Minäkin uskon että F#:lla lukkoja käyttämällä koodi ei vaatisi tuollaista urheiluhenkeä (sormilihasten kuntoilumielessä). En sitä todista, koska lähellä ei ole kehitysympäristöä, ja en tunne Javan AtomicIntejä, yms (ehkä Guid vai?). Sen sijaan, mun mielestä se ei ole ollenkaan noloa, jos ensimmäinen F#-toteutus tulee alottelijalta, koska F# on niin helppo. :-)

    Yleensä puhtailla olio-kielillä kun luokkien määrä alkaa kasvaa, niin sitten tehdään yleiskäyttöisyyttä käännösaikaisen virhetarkistuksen kustannuksella. Olen positiivisesti yllättynyt, että Javalla on onnistuttu tekemään seitsemän luokkaa ja vielä ei ole yhtään reflectionia! (Naurakaa vaan, mutta vahva tyypitys säilyy!)

  93. Vakuutusmies - January 12, 2012

    Tuomas,

    Atomic-tyypeillä ei ole mitään tekemistä Guidin kanssa, vaan ne ovat lukoton tapa päivittää jotain, ja perustuvat pääsääntöisesti jonkinlaiseen prosessoritason compare-and-set käskyyn. Kts. http://en.wikipedia.org/wiki/Compare-and-swap.

    Ja sitten siihen reflection'iin. Reflectionin käyttö ei ole lainkaan kovin yleistä Javassa, jos unohdetaan taas esimerkiksi ne konsultit joiden pitää jättää oman "hiilijalanjälkensä" asiakkaan koodiin. Vaikka itse olen aika hc-reflection-käyttäjä ja pidän siitä paljon (oikeassa paikassa), niin en kuitenkaan todellakaan käytä sitä usein. Useimmat ohjelmoijat eivät käytä sitä koskaan. Ja hyvä niin. Sekin on taas työkalu, mitä pitää osata käyttää *oikeassa* paikassa, ja nykyään niitä paikkoja on todella harvassa.

    Ja jos nyt oikein ymmärsin kommentin tuosta vahvasta tyypityksestä, niin olen samaa mieltä siitä lauseen loppuosasta; olen nyt yli 20 vuotta katsonut kuinka joku dynaaminen scriptikieli tulee ja valloittaa maailman ja samoin on käynyt kuin LISPin maailmanvalloituksenkin. Tosin poikkeuksena on Javascript, joka on valloittanut maailman, mutta hieman vastatuulessa on sekin (http://en.wikipedia.org/wiki/Dart_%28programming_language%29). Ja viitaten taas TIOBE:een

    Statically Typed Languages 71.4% +3.5%
    Dynamically Typed Languages 28.6% -3.5%

    Esimerkiksi Javascript, joka sinällään on ihan veikeä kieli, on todella rankkaa koodattavaa mm. koska siihen ei ole mahdollista tehdä kunnollista intellisenseä (koska tyypitys on niin heikko). Ja kun sitä ei käännetä (vaikka ClosureCompiler hieman asiaa auttaakin), niin sitten vaan odotellaan koska ensimmäinen bugi hyppää tuotannossa silmille.

  94. Vakuutusmies - January 12, 2012

    Pian on 100 responsea kasassa ;-)

    Tuomas,

    Satuitko muuten huomaamaan, että tässä vinkkaamassasi esimerkissä http://fssnip.net/65 *on* tila jota luetaan/päivitetään eri säikeistä (eli sieltä mutable state taas hiipi kehiin). Ja tämä kaveri onkin näköjään konkurenssi-tietoinen, sillä se on tehty oikein (toisin kuin esimerkiksi se Autodeskin "Gurun" tekeleet).

  95. Tuomas - January 12, 2012

    Tyyppijärjestelmä on hyvä juttu, olen suuri fani.
    Oliot ovat vähän niin ja näin, en vastusta, koneille haittaa, ihmisille hyötyä(?).

    Sen sijaan se, että logiikka, joka lähes aina liittyy useampaan olioon, laitetaan metodeihin olioiden sisään, on ajatuksena jotenkin sairas. Sitten ei koskaan tiedä missä on mikäkin logiikka ja miksi.

    "Minähän olen sitä mieltä, että ilman lukkoja tai vastaavaa mekanismia (esim. MailboxProcessor sarjallisena) ongelmaa ei saa ratkaistua."

    Jos tekninen speksi oli näin oliolähtöinen, että säikeet pitää jakaa olioiden kesken, ja pitää olla yhteinen lauta, niin miten voisikaan saada? Se on taas toinen juttu, että kannattaako softan speksi tehdä noin lähelle rautaa. Voihan säikeet jakaa monella muullakin tapaa. Rautakin voi muuttua.
    Mitä jos meillä ei olekaan yksi kovalevy, vaan on SSD, joka kirjoittaa monta bittiä samaan aikaan?
    Mitä jos meillä ei olekaan prosessori, vaan laskennan suorittaakin näytönohjain?
    Mitä jos meidän ei tarvitse sitoutua edes siihen, että "kaikki on matalalla tasolla vain ykkösiä ja nollia"?
    Mitä jos meillä ei olekaan yhtä höyrykonetta, vaan pilviarkkitehtuuri, satoja pieniä koneita, ilman synkronista tilaa?

    MailboxProcessor piilottaa teknisen (lukkojen?) toteutuksen korkeammalle abstraktiotasolle:
    imperatiivisten lockien (=miten kone tekee) sijaan määrittelen deklaratiivisesti (=mitä kone tekee).

    Esitän vielä kolmannen tavan (kiistellään sitten, että onko tämä "vastaava mekanismi"), tämän Rx:än:

    http://pastebin.com/mN5r6SGd

  96. Tuomas - January 12, 2012

    Ja heti korjaus koodiin, nimen omaan interactiveen tarvitaan siis nämä kaksi riviä:
    //#r "System.CoreEx"
    //#r "System.Reactive.dll"

    Itse projektiin ne pitää lisätä perus add referencellä.

  97. Vakuutusmies - January 12, 2012

    Tuomas,

    Olikohan sun koodi juuri suorituksessa siellä Pastebin:issä? Se sano mulle näin:

    Pastebin.com is under heavy load right now :'(

  98. Tuomas - January 12, 2012

    Ehk√§ sinne oli karannut pari hiirt√§, mist√§ lie implementaatiosta…

  99. Tuomas - January 13, 2012

    Koitan tässä postissa haastaa F#:lla Javaa ihan oliokielenä.

    Käyn tässä samalla pienen code-review:n keskustelun Javakoodille. Kuten aiemmin tuli ilmi, Java-koodi on tehty 20 vuoden kokemuksella, ja siten voidaan olettaa, että se on Javakoodiksi poikkeuksellisen laadukasta.

    Perus interface-/luokkamäärittelysyntaksi ja logiikkarakenteet for/if on kummissakin kielissä mahdollista. Niissä en näe mitään ihmeellistä, F#:lla on vähemmän noisea, mutta se on vain kuriositeettiä.

    Esimerkki 1: http://pastebin.com/UyRfHHwM

    .NET:issa on Tuple-luokka, jota F# hyvin tukee. Tuplen idea on niputtaa pieniä asioita kiinni toisiinsa, kun ei tarvita erillisiä luokkia.
    Lista on n kappaletta, yhtä tyyppiä. Tuple on yksi kappale, n tyyppiä. Tämä säästää välillä paljon koodia. (Varsinkin turhaa "infrastruktuuria".)

    Esimerkki 2: http://pastebin.com/yPR02Htq

    Tosin F#:ssa for ja if-käsittely on usein turhaa, menemättä edes rekursioihin, tehokkaiden listafunktioiden takia.

    Tosin, koodissa k√§ytetty dictionary rooms on ilmeisesti table-lookup…
    Table-lookup konseptihan on "funktio jolla x:stä konvertoidaan y" (=tässä Locationista Room), eli ihan normaali select (/map/projisio, rakkaalla lapsella on monta nimeä).

    Paikka paikoin Java-koodi on hyvin imperatiivista koodia, kerrotaan koneelle mitä kone tekee, mutta ihminen joutuu miettimään pidempään, että mikä onkaan tarkoitus.

    Esimerkki 3: http://pastebin.com/vkcvtzJA

    Sitten pattern-matching:
    Usein koodista tulee erilaista business-sääntöjen if-viidakkoa, ja tämä on ratkaisu siihen, jolla logiikkaviidakosta saa häröpallon sijaan siisti. Koodi alkaa muistuttaa järjestäytyneisyydessään jopa sotilaallista muodostelmaa.

    Jos linq tukisi tätä niin se olisi jotain tällaista:
    switch {…}
    case where {…} select {…}
    case where {…} select {…}
    case where {…} select {…}

    Sisäisesti tämä on hyvin lähellä if-else if-else if-else -ketjua, kuitenkin sillä erolla, että if-ketju voi koskea vain yhtä asiaa ja funktiosta palautuu arvo.

    Perus switch vs pattern-matching:

    Esimerkki 4: http://pastebin.com/2uKMDRsx

    Mutta oikea hyöty saadaan vasta kunnon logiikkaviidakossa:

    Esimerkki 5: http://pastebin.com/BQfCu0fS

    (Tässä Javan nestaus vähän vähenisi, jos eka if olisi invertoitu, mutta se on kuriositeetti.)

    Sitten kommentti noin ylipäätään, null-käsittelyn sijaan pitäisi hoitaa "tyhjä huone" mieluummin Special Case -patternilla (Fowler PoEAA).

    Olioperustelu (jolla eräs konsultti mut aikoinaan käännytti ja olen täysin samaa mieltä):
    K√§yt√§ null:ia aina vain virhetilanteena. √Ąl√§ assignaa sit√§ oletustoiminnallisuuteen, se johtaa kasaan null-checkej√§ ja sit√§, ettei saada oikeaa null-reference-exceptionia kiinni.

    Ainakin .NET:issa on tyyppi Nullable (=sama kuin lista jossa on 0 tai 1, Enumerable.Empty) ja F#:ssa lisäksi Option type.

    Funktionaalinen perustelu:
    Nullable (=maybe-monad) on samanlainen monad kuin async. Se on sopimus, jonka piiriin voi mennä. Ja aina kun tullaan sopimuksesta lopulta ulos (=kaivetaan itse arvo nullablesta), on suoritettu jonkun sortin sivuvaikutus (=hävitetty nulluus).

    Tämä ei kuitenkaan tarkoita, että haluaisin, että kaikki olemassaoleva koodi kirjoitetaan F#:lla uudestaan. Esim. Jos nyt jo koodaatte C#:pia, niin sehän toimii mainiosti yhteen F#:pin kanssa. Mutta uudessa koodissa F# on varteenotettava vaihtoehto.

  100. Vakuutusmies - January 14, 2012

    No niin, nyt mentiin sitten kolminumeroisille luvuille postauksissa.

    Java-koodi on tehty yli 20 vuoden ohjelmointikokemuksella, mutta koska Java ei ollutkaan kuin vuodesta 1995, niin vähennetään siitä nyt pikkuisen. Laadukkuudesta en nyt lähtisi sanomaan mitään, sillä se rykäisty nopeasti kasaan. Siellä on paljon asioita, joista ei voi olla kovin ylpeä. Tein kamat sillä mielialalla, että kunhan konkurenssimielessä toimivat.

    Sitten siitä tuplesta. Tuple on kaksiteräinen miekka. Toisaalta se on ihan kätevä tapa välittää useampia tietoja, mutta toisaalta taas näen sen staattisen tyypityksen kannalta ongelmallisena. En tosin ole ihan varma, mutta jos toimii kuten luulen, niin se on kyllä selvä paluuta taaksepäin näin tiukan tyypityksen fanin suhteen. Eli

    let a = ( 61,"Timo Harjakainen" )
    let b = ( 5000000,"Suomi" )
    let c = ( 1000000000,"Kiina" )

    let tulostaMaanTiedot( x ) =
    let ( population,country ) = x;
    printfn "Maassa nimeltä %s asuu %d henkilöä" country population

    tulostaMaanTiedot( a )
    tulostaMaanTiedot( b )
    tulostaMaanTiedot( c )

    Niin vaan menee Timo Harjakainen sisään kunhan nyt suurinpiirtein ovat samanlaisia. Jos vastaan otettaisiin luokka/interface näin ei varmaankaan kävisi. Tämän takia pidän tuple-käsitettä lähinnä huonona, vaikka kohinaa ilman sitä tuleekin enemmän.

    Sen tanssikuvion idea on se, että eläin *yrittää* siirtyä johonkin itse parhaaksi katsomaansa koordinaattiin (arvotaan randomilla). Jos ei onnistu, niin yritetään seuraavaa, mutta tällä ei ole mitään tekemistä edelliseen onnistuneen liikkeen kanssa. Yritetään siirtyä kaikkiin suuntiin kunnes joku onnaa tai sitten ei siirrytä mihinkään jos ei onnistu. Olioilla se pitäisi tehdä jotakuinkin näin (tosin käyttäen enum'ia):

    http://pastebin.com/rf8ANziL

    Enemmän koodia, mutta abstraktio on huomattavasti parempi. Esim. jos suuntia tulee lisää, ei vaikuta muuhun kuin Translators luokkaan.

    "Sitten kommentti noin ylipäätään, null-käsittelyn sijaan pitäisi hoitaa "tyhjä huone" mieluummin Special Case -patternilla (Fowler PoEAA)."

    Martin Fowler'in mielipiteet eivät kiinnosta minua yhtään. Mikäli Javasta puhutaan, ja nyt puhutaan, niin kääntyisin paljon, paljon mieluummin Joshua Blochin suuntaan. Konsultti, joka hyvin todennäköisesti on Rami, on ymmärtänyt asian ihan väärin. Ensinnäkin, Java kielen kehittäjät samoin kuin lähes kaikkien muidenkin kielien kehittäjät eivät ole varmaankaan tyhmyyttään ottaneet sellaista käsitettä kuin null kieleen. Toiseksi, ja ironisesti, se haittaa erityisesti immutable tyyppien tekemistä (tulee idioottimaisia konstruktoreita). Ja jos on mutable tilaa, niin sitten siitä vasta tyhmää tuleekin. Kolmanneksi, tästä aiheutuu todella vaikeasti löydettäviä ongelmia, jotka saattavat tulla eteen vasta klusteroidussa ympäristössä. Jos tämä null-marker olio deserialisoidaan, niin yllätys yllätys, koodi meneekin rikki. Koskakohan Martin on viimeksi koodaillut jotain lottopalloarvontaa vakavampaa? Esimerkki: http://pastebin.com/G6iMXfxi

    Ja tulos:

    Ensin alkuperäinen. Onko NULL-marker? true
    Sitten alias serialisoinnin jälkeen. Onko NULL-marker? false

    Ja neljänneksi, me emme omista koko maailman koodikantaa ja siksi meidän on pelattava yhteisillä säännöillä, eli käytämme siis nullia. Sen null-markerin tekeminen on *lähes aina* turhaa kohinaa. Enempää en jaksa kirjoittaa, mutta huomautan vielä, että jos se olisi niin hyvä juttu, niin varmaan sen olisi joku muukin keksinyt ja ottanut mukaan kieleen.

  101. Tuomas - January 14, 2012

    Tupleista:
    Sama kuvaamasi riski on jos metodeissa (tai konstruktoreissa) on useita samaa tyyppiä olevia parametreja. Kuitenkin sellaista koodia on todella paljon (varsinkin parametreina perustyyppejä int ja string), joten oletan, että asia ei ole kovin olennainen.

    Nullista (mutta nyt mennään taas asian vierestä):
    Olio-ohjelmoinnissa on sellainen käsite kuin "Single Responsibility Principle": Yhdellä luokalla pitäisi olla vain yksi "vastuualue". Mutta null:illa on kaksi "vastuualuetta": 1) toimia alustamattomana tilana (ja aiheuttaa null-reference-exception, jos muuttujan alustus unohtui), 2) toimia "Special casena" tyhjänä. Näin ollen null rikkoo olio-ohjelmoinnin pääperiaatteita, jos sitä käytetään kahdella eri tavalla.

    Konstruktoreista:
    Immutablejen ystävänä olen sitä mieltä, että mahdollisimman paljon konstruktoriparametreja, (ja private setterit,) niin, että olio saadaan jo alustettaessa mahdollisimman validiin tilaan. (Ja mahdollisimman vähän globaaleita tai luokkamuuttujia. Ja Rx:llä asian voi viedä vielä paljon pidemmälle halutessaan.)

  102. Rami Karjalainen - January 14, 2012

    "
    "Sitten kommentti noin ylipäätään, null-käsittelyn sijaan pitäisi hoitaa "tyhjä huone" mieluummin Special Case -patternilla (Fowler PoEAA)."

    Martin Fowler'in mielipiteet eivät kiinnosta minua yhtään. Mikäli Javasta puhutaan, ja nyt puhutaan, niin kääntyisin paljon, paljon mieluummin Joshua Blochin suuntaan. Konsultti, joka hyvin todennäköisesti on Rami, on ymmärtänyt asian ihan väärin
    "

    Paci,

    En olisi kovin kärkkäästi tuomitsemassa julkisesti jonkun näkemyksiä väärin ymmärryksiksi.

    Nulleja vastaan on puhunut Fowlerin lisäksi myös mm. Robert C. Martin, joka on olioiden puolesta puhuja henkeen ja vereen. Tunnetaan myös nimellä Uncle Bob. Vilkaise vaikka kirjaa Clean code, kappaleet "Don't return null" ja "Don't pass null".

    Minusta parempi on käyttää nullien sijaan tyhjiä collectioneita (jos siis collection tyyppi) tai special caseja, mikäli puhutaan olioviittauksista. Minusta myös fail fast on hyvä käytäntö, ja silläkin on nullien käyttöä vähentävä vaikutus. (Ja tämä on linjassa Uncle Bobin näkymyksen kanssa)

    Mutta en ole täällä julkisesti väittämässä, että edustamasi käsitys olisi väärä. Puhumattakaan, että se olisi väärä koska toinen "ei vaan käsitä". Mutta tämä kommenttisi kertonee vain ja ainoastaan sinusta keskustelijana.

    Terveisin,
    Rami

  103. Vakuutusmies - January 14, 2012

    Ihan ekaksi pelkästään nullista (terveiset moderaattorille):

    All that theory and no reality makes Paci a dull boy. Java language spec: "In practice, the programmer can ignore the null type and just pretend that null is merely a special literal that can be of any reference type." http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html. Kuten jo mainitsinkin, jos haluaa lähteä kikkailemaan niin sittenhän noita null-placeholdereita voi käyttää. Mutta tämä tie vie ohjelmoinnin pimeälle puolelle (muistat varmaan miten kävi Anakin Skywalkerille). Esimerkiksi se serialisointi ongelma tulee heti, jos yksi serveri pistetään alas (tai se feilaa) ja switch-over'in yhteydessä sessio migroituu toiselle serverille. Tai sitten vaan ihan normaalissa EJB-kutsussa remote rajapinnan läpi. Eli Java EE ympäristössä erityisesti tällainen koodi on anti-pattern, ei mitään mistä kannattaisi olla kovin ylpeä. Ja tälle tosiseikalle ei voi mitään Martin Fowler eikä Rami (tai kuka se konsultti sitten olikaan). Myös suorituskyvyn kannalta tämä voi joskus olla katastrofi. Muistat varmaan sen laskentahässäkän josta kerroin? Siellä oli valtavia taulukoita joita alustettiin jollain oletusarvoilla (turhaan) juuri tällaisen special case:n hengessä ja näiden arvojen jatkuva renkutus aiheutti valtavan CPU-kulutuksen. Oletusarvot menevät ineen hyvin alhaisen tason käskyillä ( toisin kuin sellaiset arvot joita kieleen ei ole suunniteltu. Kokoelmien suhteen tilanne on yleisesti ottaen täysin eri, sillä siihen kielen kirjastoissa on suora tuki. Kts. http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#emptyList%28%29. Mutta niiden kanssa tavoite on ihan eri, eli tuki for-in loopille. Identiteetin tsekkaus feilaa ihan yhtä lailla ja sen tekeminen osoittaa rajoittuneita Java-taitoja. Eli olio-ohjelmoinnin suhteen kehotan hylkäämään tämän "mestarisi" ja pyrkimään pois pimeältä puolelta ;-)

    Ja mitä tulee sitten vielä siihen single responsebility principlee:n, niin se on tehty jotain paradigmaa varten ja ei siten minusta palvele oikein ketään. Taitaa niillä sedillä alushousut pyöriä jalassa kun katselevat miten hybridikielet raiskaavat olioita funktionaalisuudella. Kuten olen jo maininnutkin, niin esim lambdat ovat erittäin hyvä asia OO-kielessä vaikka sitä ei mikään olemassa oleva teoria todistaisikaan.

    Ja selvennys konstruktoreista:
    "Immutablejen ystävänä olen sitä mieltä, että mahdollisimman paljon konstruktoriparametreja". Samaa mieltä, mutta tämä ei ollutkaan se pointti. Toi null-marker tekee sen, että on pakko asettaa jotkut arvot joka kenttään vaikka parametrejä ei käytännössä useinkaan ole. Eli siis joudut tekemään toisen konstruktorin *vain* tämän special case:n takia. Boring.

    class Immutable {
    private static final Immutable NULL = new Immutable( );
    private final String a;

    private final String ö;

    private Immutable( ) {
    // Onko tässä mitään järkeä?
    a = null;
    b = null;
    c = null;
    d = null;
    e = null;
    f = null;
    g = null;

    ö = null;
    }
    public Immutable( String a,…,String √∂ ) {
    this.a = a;

    this.ö = ö;
    }
    }

    Se, että konstruktori ottaa järkyttävän määrän parametreja ei ole myöskään ongelmatonta (mm. sen takia miten puolustit tupleja). Tätä varten on sitten bygattu builder patternin variaatio, joka tekee koodista huomattavasti selvempää käyttää, mutta on kyllä jonkinasteinen riesa kirjoittaa.

    Esimerkki täällä:
    http://java.dzone.com/articles/immutability-with-builder-design-pattern

    Jos katsot sitä lopussa olevaa client-koodia, niin se näyttää sellaiselta säädylliseltä ja ne arvot joita en ylikirjoita menee oletuksilla (ja siksi builder on hyvin, hyvin kiinteästi kiinni varsinaisessa luokassa jonka se instantio).

  104. Tuomas - January 14, 2012

    Aiempaan vielä, että jos pelkää stringien tai inttien väärinkäyttöä, niin enum:it ovat ratkaisu.
    Mutta ne toimivat myös tuplejen sisällä, ei liity tupleihin.

    Tässä vielä kaksi F#:pin työkalua olio-koodaajille:

    Discriminated Unions:
    Tilanteeseen, jossa haluat tehdä yhteisen koodin luokille, joilla ei ole yhteistä rajapintaa tai geneerisyyttä.
    Usein oliokielillä on kolme vaihtoehtoa yleiskäyttöisyyteen tässä tapauksessa:
    a) Räjäytä perintähierarkia käsiin ja mene koodaamaan uusia rajapintoja. Paha jos oliot eivät ole omia.
    b) Tehdään yleiskäyttöisyys reflectionilla
    c) Tehdään yleiskäyttöisyys käyttämällä kaiken-kantaluokkaa ja castailuilla

    F# tuo vielä yhden lisää:
    d) Tyypin voi m√§√§ritell√§ olemaan "joko t√§m√§ tai t√§m√§ tai…"
    silloin voi tehdä vahvasti tyypitetyn type-switchin (jälleen pattern matching).
    Erona siis, että a ja d ovat compile-time, b ja c ovat runtime.

    Object Expressions:
    (Koitan selitt√§√§ ilman monadeita yms…)
    Tyyppijärjestelmää voi käyttää varsinkin kirjastojen koodauksessa hyväkseen niin,
    että käyttäjä ei voi käyttää softaa väärin, eli olkoon meillä prosessi esim:
    Ensin pitää tallentaa, sitten pitää validoida, sitten pitää lähettää.
    Jos kaikki tekee saman olion kylkeen, käy niin, että voit vahingossa lähettää validoimattoman olion.
    Jos taas tekee joka metodin palauttamaan eri olion:
    tallentamaton
    tallennettu
    validoitu
    …ja seuraava mahdollinen metodi on vain palautetun olion yhteydess√§, niin ratkaisu on
    "idioottivarmempi": Pakko validoida, koska muuten et pääse lähetys-metodiin.
    Tämän idioottivarmuuden suuri kustannus on, että jollain pitää konvertoida
    melkein samanlaisia olioita toisiksi, joka aiheuttaa hankalia konstruktoreita tms.
    F#:ssa voi helposti tehdä uuden melkein-samanlaisen olion ja lisätä with-sanalla erikoispiirteen.

  105. Vakuutusmies - January 14, 2012

    Ja tarkennuksena vielä tähän F# vs oliot. Javalla ja C#:lla on yksi asia mitä Scalalla ja F# ei ole: valtava määrä osaajia ja käyttäjiä. Näin ollen yrityksen arkkitehtina minun tehtäväni on pitää tämä asia hallussa ja siksi valitsen valtavirran paradigman. Se ei ehkä ole paras, mutta se on riittävä ja varma valinta (huom, olen riskienhallintayhtiössä töissä). Ja koska Windows ei ole edustamassani yhtiössä, eikä minun päässäni, kovasti arvossaan, niin kieli on siis käytännössä Java.

    En koe mielekkäänä väitellä onko Java parempi kuin C# tai F#. Se riippuu kontekstista. Olisin myös hieman varovainen esimerkiksi COBOL:in pilkkaamisen suhteen. Ensinnäkin yleisesti ottaen ne ihmiset jotka sitä parjaavat eivät ymmärrä mitään siitä ja toiseksi, se on todennäköisesti kaikkien aikojen menestyjä ohjelmointikielissä.

  106. Tuomas - January 14, 2012

    Nyt hyp√§ttiin keskustelussa taaksep√§in, asioihin, jotka jo k√§siteltiin… Kumpi on parempi ty√∂ntekij√∂iden osalta: m√§√§r√§ vai laatu?

    Se, ett√§ kaikki eiv√§t osaa k√§ytt√§√§ k√§nnyk√∂it√§ ei ole est√§nyt niiden yleistymist√§. Oleellista on, ett√§ yhteensopivuus on kunnossa (=xml/wcf/dll/…) ja ett√§ kokonaisuudet s√§ilyv√§t pienin√§ (tehdashallin kokoinen puhelin olisi rasite).

    Maailma muuttuu, myös ohjelmointikielten ympärillä, hitaasti ja vähitellen tosin. Uusiin asioihin pitää silti sopeutua: moniko 20v sitten Cobolia koodannut osasi aavistaa, että webservice-requesteja koodiin voi tulla satoja lähes samaan aikaan, ja että esim concurrencystä tulisi siten olennaista? Tietoturva on toinen esimerkki.

    Se että on IT-alalla töissä on merkki siitä, että on hyväksynyt muuttuvan maailman.

    Agile on hyvä esimerkki siitä kuinka alan "oletusmenetelmä" voi vaihtua. Väitän, että osittain se saavutti asemansa niin, että pätevät ammattilaiset olivat kiinnostuneita parantamaan työolojaan: Agilella tehdyt projektit onnistuivat, mutta ei agilen takia (=työkalu muiden joukossa), vaan siksi, että siitä kiinnostuneet työntekijät olivat muutenkin päteviä ammattilaisia.

    Yleensä muuttuvassa ympäristössä kiinnostus uusia asioita kohtaan on hyväksi, ja jopa muidenkin kuin käytössä olevien asioiden osaaminen auttaa ymmärtämään vaihtoehtoja ja taustoja.

    Motiivi F#:piin voisi olla esim. että voi keskittyä mielenkiintoisiin itse ongelmiin, eikä kapselointiin/boilerplate/infrastruktuuri/tms-koodiin.

    Jos firman linja on tehdä päivityskelvotonta koodia halvalla ja maksimoida codebasen koodirivien määrä, niin, että pienet muutokset ovat mahdottomia ja kukaan ei ymmärrä kokonaisuutta, niin sitten on tietysti hyvä, että voidaan palkata valtava määrä ammattitaidottomia koodareita.

  107. Vakuutusmies - January 14, 2012

    Ouch,

    Minähän jo vähän vihjailin, että ei kannattaisi lähteä puhumaan liikoja asiasta josta ei tiedä.

    "moniko 20v sitten Cobolia koodannut osasi aavistaa, että webservice-requesteja koodiin voi tulla satoja lähes samaan aikaan, ja että esim concurrencystä tulisi siten olennaista?"

    Tämä on niin puppua kun vaan olla voi. Ajattelitko ehkä, että Microsoft on keksinyt OLTP:n? Ensimmäinen kaupallinen OLTP-järjestelmä näki päivänvalon 1969, ja nimeksi tuli CICS (http://en.wikipedia.org/wiki/CICS). Ja miten OLTP-ympäristöt toimivatkaan? Transaktioita ajetaan *konkurentisti* ja vähän haipakkaa vauhtia (tuhansia tai kymmeniä tuhansia sekunnissa). Taas lainaus "When CICS was first released, it only supported application transaction programs written in IBM 360 Assembler. COBOL and PL/I support were added years later", eli COBOL-tyypit ovat tehneet tätä 70-luvulta lähtien (ennen kuin Microsoft oli edes perustettu), koodia on ajettu yhdenaikaisesti *tilan kera*. Näin edelleenkin. WebService'jä he eivät käyttäneet koska koko webbiä ei ollut olemassakaan. Ja sitten tällainen:

    "As per a survey conducted in 2005 by Ovum1, the mainframe is fit and well. The mainframe is not going to disappear any time soon, nor is IBM’s commitment to it. Brand new MIPS continue to grow by around 15% a year, and the number of lines of COBOL Code in production continue to grow by 3 to 5%.

    CICS is the premier teleprocessing monitor on the mainframe. Globally, CICS processes an average of 30 billion transactions per day totaling over $1 trillion ‚Äď that is, more transactions than the entire internet. CICS is used by 490 of the Fortune 500 firms as well as thousands of smaller companies."

    Muihin asioihin *palaan* myöhemmin erillisellä postauksella.

  108. Tuomas - January 14, 2012

    Itse olen sen verran kieli-friikki, että olen vähän kaikkea opetellut, mutta Cobol-kirjat ovat vähän vähissä, samoin se ei ole ihan se yleisin ympäristö kotikoneelle. USA:sta San Franciscosta löysin aikanaan divarin takahyllyltä pölyisen kirjan (painettu 1977), jossa oli 70 sivua Cobol-tutoriaalia ja 100 sivua PL/I:ta ja sen tietysti ostin ja olen lukenut, mutta siinä ei puhuttu Cobolin osalta halaistua sanaa transaktioista tai concurrencystä.

    Eli kiitos sivistyksestä, tuli tarpeeseen. :-)

  109. Vakuutusmies - January 15, 2012

    Tuomas,

    Lueppa tämä:
    http://www.cio.com/article/696188/Java_Apps_have_Most_Flaws_Cobol_Apps_the_Least_Study_Finds

    Ja sitten vähän hailaitteja sieltä

    "Bill Curtis, chief scientist at Cast, said he believes Cobol did best because the code is older. Programmers "have been beating on it for 30 years" and in that time have fixed some of the most critical violations, he said."

    Tähän viittaan sillä, että on hyvä että kieli on stabiili eikä uusia piirteitä tule solkenaan.

    "there are many people going into Java now that really don't have strong computer science backgrounds. We may just be seeing the fact that there is an awful lot of people writing code who aren't gurus in software engineering."

    Täysin samaa mieltä, kysymys on osaamisesta, ei kielestä. Ei tarvitse olla guru, mutta jotain pitäisi voida olettaa. Ja sitten vielä niistä nykyajan "guruista", jotka tietävät kaikesta enemmän kuin "vanhat pierut" (joihin itsenikin lasken). Jälleen kerran otamme reaalimailman kokemuksia. Eräs konsultti, kutsutaan häntä tässä vaikka nimellä Ismo "karies" Kokko, jota pidettiin tosi kovana osaajana, valitteli kuinka Javan hashmap:ssä on bugi, koska taulukossa jossa entryt ovat on "nulleja joukossa". Mitä ihmettä? Jos hajautustaulun idea on näin hukassa, niin ainakin minun silmissäni ei missään nimessä voida puhua kovasta osaajasta, ja siten minusta tuo "strong background in computer science" ei toteudu. Tietorakenteiden peruskurssi taisi jäädä käymättä. Ehkä samaan aikaan oli juuri joku agile kurssi?

    Tai miten olisi tämä, viitaten vähän siihen tietoturva/COBOL -aspektiinkin: http://blogs.wsj.com/tech-europe/2011/12/09/counting-the-cost-of-bad-code-in-business-applications/?mod=google_news_blog

    Java was not the worst in terms of security, as .NET posted the worst security score and Cobol the best. But Java was the worst in performance, contributing to its overall poor score. ‚ÄúModern development languages such as Java-EE are generally more flexible and allow developers to create dynamic constructs that can be riskier in operation,‚ÄĚ Cast wrote in its report. ‚ÄúThis flexibility is an advantage that has encouraged their adoption, but can also be a drawback that results in less predictable system behavior.‚ÄĚ

    Nii-in, enemmän mahdollisuuksia, enemmän sähläystä.

  110. Vakuutusmies - January 15, 2012

    No niin, tulihan se Ramikin sieltä pienen provokaation jälkeen linjoille ;-)

    Minulle on oikeasti ihan sama mitä "Uncle Sam" on mieltä asiasta. Ajattelen tämän jutun omalla päälläni, johon luotan kuitenkin enemmän kuin Uncle Samin päähän. Mutta nyt "Vakuutusmiehen haasteeseen". Eli homman nimi on nyt sitten se, että minä olen julkisesti ilmaissut, että tällaiset kikkailut (special case vai miksi sitä nyt sitten nimitetäänkin) ovat turmiollisia (paitsi siis se Collections.emptyList (jota sitäkään useimmat eivät osaa käyttää), ja niiden vaikutukset tulevat esiin vasta todellisessa ympäristössä. Minun ei liene enää tarvis todistaa, että serialisoinnin jälkeen tämä special case kopioituu (koodi on jo pastebinissä) ja siten esimerkiksi tämä sekvenssi feilaa serverin switch-overin yhteydessä:

    1. sessiossa pitää olla kurantti asiakas, mutta jossain vaiheessa se voi olla vielä NULL (vaikka ennen login-proseduurin päättymistä). No sinne laitetaan sitten "special case" Customer.NULL, jotta ei tarvitse testata NULL:ia.
    2. tapahtuu switch-over ja tämä koodi if( session.getAttribute( "customer" ) == Customer.NULL ) antaa tulokseksi false
    3. asiakasta ei siis alusteta koska se on mukamas jo tehty (ei ollut "special case")

    Näin käy siis aina, ennenmin tai myöhemmin, switch-overin yhteydessä. Tämä menetelmä toimii jos ajaa jotain kaalimato.com'ia yhdellä tomcatillä, mutta ei toimi HA-ympäristössä. Näin ollen se on anti-pattern (koska se ei ole klusterikelpoinen ratkaisu). Nyt sitten itse haasteeseen: osoita, että olen väärässä tämän asian kanssa. Nyt voit sitten

    a) vedota siihen, että minulla on väärä lääkitys tai jos ei ole lääkitystä, niin pitäisi olla
    b) häipyä areenalta, vedoten siihen ettet nähnyt koko keskustelua
    c) vedota esim. meemeihin tai entropiaan, ja osoittaa että sinulla on tietoa kaiken takana olevista perimmäisistä mekanismeista joita minä en vaan ymmärrä
    d) myöntää, että etpä ole tullut ajatelleeksi tuota ja todeta, että ei olisi pitänyt uskoa Uncle Samia

    Ratkaisuehdotuksia joita ei hyväksytä.

    if( Customer.NULL.equals( session.getAttribute( "customer" ) ) // Tässä ei ole mitään järkeä
    if( Customer.isNull( session.getAttribute( "customer" ) ) // Ei ole tässäkään

    Ja sitten siihen don't pass null asiaan. Siinä on osittain järkeä, mutta yleisenä periaatteena se johtaa entropiaan. Oletaanpa, että sinulla on tarve tehdä metodi, jonne annat vaikkapa neljä parametria, joista jokainen voi olla null. Siis

    ContentManager cm = …
    cm.store( a,b,c,d );

    vai

    // Nämä on tehty näin koska Uncle Sam sanoi niin ;-)
    cm.store( a );
    cm.store( b );
    cm.store( c );
    cm.store( d );
    cm.store( a,b );
    cm.store( a,c );
    cm.store( a,d );
    cm.store( b,c );
    cm.store( b,d );
    cm.store( c,d );
    cm.store( a,b,c );
    cm.store( a,b,c,d );
    cm.store( a,b,d );
    cm.store( a,c,d );
    cm.store( b,c,d );

    Ja tuo sitten vaikka kymmenelle metodille. Enempää ei kai liene syytä kertoa. Mutta pääasia nyt on siis se, että ratkaiset tuon special case -pulman.

  111. Tuomas - January 15, 2012

    Moi,

    Javan sisäinen toiminta ei ole tän foorumin softakehityksen kannalta kovin merkittävää, joten ei viedä keskustelua siihen (vaikka epäilemättä Vakuutusmies haluaisi).
    Esim. tuohon Javan public Immutable( String a,‚Ķ,String √∂ ) -esimerkkiin keksii jo perus .NET-koodaaja helposti useita eri ratkaisuja, C#: (pari vinkki√§: optional parameters, params-array, …), F# samat plus tuo yll√§ kuvattu with plus function composition: parametreja ei ole edes pakko m√§√§ritell√§.

    Micorsoftin alustan tietoturva on sitä luokkaa, että koodaajien on yritettävä varautua myös siihen, että IIS:istä tms alustasta voi löytyä aukkoja. Sitä on turha puolustella. Silti Windowssia käytetään.

    Vakuutusmies,
    Tuo Java-vs-Cobol kiinnostaa mielenkiintoiselta. Mä tuossa ennen tätä tapahtumaa ihan kokeeksi valitsin ongelmaforumin (paras tietämäni on stackoverflow) ja koitin siitä hakea ongelmien määrät vs ratkaistut ongelmat.
    (Ratio = Unanswered jaettuna Total) Tulos oli tämä:
    http://photos3.meetupstatic.com/photos/event/c/2/f/7/600_25429911.jpeg
    Mä tietysti sinisilmäisenä tulkitsen tuota, että vahvasti tyypitetyn funktionaalisen kielen koodaajalle tulee suhteellisesti vähemmän käytännön ongelmia. Mutta miten sä näkisit tuon, miksi ratio on noin?

    Jos kritisoit tässä stackoverflowta, niin valitaan joku toinen saitti, josta löytyy yhtä hyvin kaikkien kielten ongelmia.

    Sitten pyöräytin saman Exceliin ja suhteutin niin, että C-kieli on vastaamattomissa 1 ja totalissa 1. (Okei, Excel-graafeja voi vääristellä miten haluaa, mutta musta tuo kuulosti reilulta: C-kieli on aika hyvä vertailukohde mihin vaan, ja mun akselit ovat leikkaamattomia ja lineaarisia.)
    Kuva näyttää tältä:
    http://photos1.meetupstatic.com/photos/event/6/1/4/f/highres_25464911.jpeg

  112. Rami - January 15, 2012

    Moi Paci,

    Miksi oli tärkeää saada minut linjoille provoamalla? ;)

    Jos olet varma, että uncle {{Bob}} tarkoitti ohjeistuksellaan juuri nimenomaisesti tuota esittämääsi casea niin olen kanssasi samaa mieltä, eli valitsen vaihtoehdon d).

    Tosin: Special Case ei tarkoita tuota minkä olit toteuttanut ja pastebinittänyt. Mutta erittäin kokeneena ja taitavana Java ohjelmoijana tiedät sen kyllä itsekin.
    Mitä tohon konstruktorihässäkkään tulee, luonnollisesti asiat pitää tehdä fiksusti. Eihän kukaan ole täällä ollut sanomassa, että omaa järkeään ei saisi käyttää.

    En nyt lähde pastebinittämään Java koodia, mutta katsotaan ehdinkö tutkimaan tota kissa-koira-rotta -labyrinttiä illemmalla F#:n merkeissä.

    Terveisin,
    Rami

    ps. Muille sen verran, että Fowlerin special case tarkoittaa sitä että periytetään alkuperäisestä luokasta "erikoistapaus" joka täyttää näin alkuperäisen luokan rajapinnat. Niille on sitten annettu erikoismerkitys. Esim: Customer luokasta voisi olla periytetty "NullCustomer" luokka, jonka isValidCustomer palauttaisi aina false.

    Tämä on ekvivalentti case (C#)
    var enumerable = Enumerable.Empty();

    Joka on "erikoistapaus" ienumerablesta, jonka toteuttaa kyllä ienumerable (mm. foreach) muttei tee mitään. Javassa siis Collections.emptyList().

  113. Tuomas - January 15, 2012

    Edelliseen postiini alleviivaan vielä, että Stackoverflow on sellainen forum, jossa auki jäävä ongelma on oikeasti paha ja jolle ei ole work-aroundeja. Tuolla tuhannet koodarit kisaavat, että kuka saa pisteet ongelman ratkaisusta ja perus-kysymykset ratkeavat sekunneissa.

    Näin ollen se, että C#:ssa on jokaista sataa ongelmaa kohden 12 ratkaisemattoman pahaa ongelma, ja Javassa on sataa kohden on 13 ratkaisemattoman pahaa ongelmaa, on huomattava ero, varsinkin jos ongelma osuu omalle kohdalle.
    Tietysti yksikin on liikaa.

  114. Vakuutusmies - January 15, 2012

    Rami,

    Tuomas sanoi: "Sitten kommentti noin ylipäätään, null-käsittelyn sijaan pitäisi hoitaa "tyhjä huone" mieluummin Special Case -patternilla (Fowler PoEAA)."

    Näin ollen te olette nyt eri linjoilla, mutta koska tämä ei ole Java-foorumi, niin keskustelkaa asiasta tämän foorumin ulkopuolella ;-)

  115. Vakuutusmies - January 15, 2012

    Tuomas,

    "Stackoverflow on sellainen forum, jossa auki jäävä ongelma on oikeasti paha ja jolle ei ole work-aroundeja".

    Itse olen aina pystynyt ratkaisemaan *kaikki* ongelmat Javalla mitä eteen on tullut, mukaanlukien esim. z/OS:lla integraation assembler-kieliselle mokkulalle. Eli joskus olen toki joutunut turvautumaan asm'iin tai C:hen. Näin ollen on vaikea sanoa, kun en tiedä mitä nämä "oikeasti vaikeat" ongelmat ovat. Veikkaan, että niillä ei ole mitään tekemistä itsesään Javan kanssa vaan pikemminkin integraatiosta johonkin muuhun härpäkkeeseen (esim joku open source -..skakasa).

  116. Vakuutusmies - January 15, 2012

    … mukaanlukien kissat ja hiiret speksien mukaisesti ;-)

  117. Tuomas - January 15, 2012

    Kyse ei ollut sun ongelmista, vaan kielen käyttäjien ongelmista ylipäätään. Tuo on forum, jossa advanced-käyttäjät auttavat ei-advanced-käyttäjiä. Kyse ei ole edes siitä, pystyisitkö ratkaisemaan jonkin noista vaikka pari päivää vanhoista ongelmista niin, että se kysyjälle kelpaisi: kyllä pystyisit. Mutta perus-koodaaja ei pysty, ja sultakaan ei kelpaava vastaus synny alle puolessa tunnissa.

    Sun vastauksen mun kysymykseen voisi tulkita, että "Verrattuna muihin guruihin, Java-guruja ei kiinnosta auttaa muita käyttäjiä, vaan he pihtaavat vastauksia omana tietonaan". Niinkö?

    Ympäristöllä, tarkemmalla tekniikalla, tai ongelmien kokonaismäärällä ei ole väliä. Nyt puhutaan nimenomaan suhdeluvusta, paljonko on vaikeita ongelmia suhteessa kaikkiin ratkaistuihin ongelmiin.

    Mun kuva on vähän vanha, mutta sama suunta on yhä (siksi päivä on selvästi merkitty). Keräsin nuo ihan vaan URL:eilla, ja kuka vaan voi toistaa kokeen.
    Esim Javan osalta, tässä on kaikki:
    http://stackoverflow.com/questions/tagged/java
    Tässä on ne, joille ei ole saatu ratkaisua:
    http://stackoverflow.com/unanswered/tagged/java
    Juuri nyt kun katson, niin 28 078 / 196 248 = 0,143074.
    Ja jos uskot, että tilastoja voi manipuloida helposti, niin siitä vaan ratkaisemaan 28 078 vaikeaa ongelmaa niin, että se kysyjälle kelpaa.

  118. Vakuutusmies - January 15, 2012

    "Sun vastauksen mun kysymykseen voisi tulkita, että "Verrattuna muihin guruihin, Java-guruja ei kiinnosta auttaa muita käyttäjiä, vaan he pihtaavat vastauksia omana tietonaan". Niinkö?""

    Ei, vaan minulla on muutakin tekemistä kuin ratkoa *toisten* ongelmia, mm. väitellä täällä turhanpäiväisistä asioista. Kun en kyseistä saittia aktiivisesti käytä, enkä koskaan siihen ole sen koommin tutustunut, niin en tiedä mitä siellä on. Mutta tuntuu vaan kovin oudolta, että jos siellä on niitä guruja, niin miten niitä ongelmia jää niin paljon sitten siihen tilaan, ettei niihin löydy mitään ratkaisua?

    No nyt k√§vin katsomassa. Huoh. Heti ensimm√§inen kysymys oli juurikin Tomcat-ongelma. Kysymys ei ole Javasta, vaan l√§hinn√§ tietyn tuotteen konfiguroinnista. Siell√§ oli l√§j√§p√§in ongelmia, jotka eiv√§t mitenk√§√§n ole Javan ongelma. Oli build-ty√∂kaluja, editoreita, tietokantoja, eri sovelluspalvelimia, … Mit√§ tekemist√§ n√§ill√§ on Java ohjelmointikielen kanssa, paitsi sen suhteen ett√§ ne toteutettu sill√§ tai ett√§ niill√§ editoidaan ko. ohjelmointikielen sorsia? Ei varmaankaan C/C++:llekaan olla laitettu ongelmia vaikkapa z/OS -k√§yttiksest√§, vaikka se onkin toteutettu sill√§? Itse Java:an liittyv√§t ongelmat olivat l√§hinn√§ todella helppoja.

    Ihan oikeesti, jos käyt katsomassa mitä on esim. Java:n alla, niin siitä ei voi päätellä mitään muuta kuin sen, että Javan ollessa "vanha" kieli, niin kaiken maailman tauhkaa kerääntyy sen ympärille. Näin ollen noilla tuloksilla ei mielestäni voi todistaa yhtään mitään.

  119. Tuomas - January 15, 2012

    Yrityksen arkkitehtina sun tehtävä on tietysti valita yritykselle ongelmaton teknologiapino. Mutta sitä on vaikea mitata mitenkään.

    Jos se on puhdas Tomcat-ongelma, niin se tuskin saa Java-leimaa. Jos se on taas "miten koodaan Javalla kun Tomcat-rajapinta bugittaa", niin se on jossain määrin erään Java-kehitysympäristön ongelma. Sitten taas jos tilalla on joku toinen web-serveri niin sillä on omat ongelmansa. Näistä pystyy tietysti porautumaan tarkemmalle tasolle, mutta:

    Raakana keskiarvona silti kehitysympäristöissä, joissa käytetään Javaa (esim. Android), on tuon mukaan huomattavasti vähemmän ongelmia kuin niissä, joissa käytetään Objective-c:tä (Apple). (Tämä myös todistanee sen, että open source ei itsessään takaa huonoa laatua.)

  120. Vakuutusmies - January 15, 2012

    Kyllä se vaan on niin, että lähes kaikki ovat nimenomaan ei-Java-liitännäisiä, vaikka niissä se tagi onkin. Kolme joihin katsoin sisällä ovat *puhtaasti* Tomcat-specifejä. Ei mitään tekemistä Javan kanssa.

    http://stackoverflow.com/questions/8540467/out-of-memory-on-tomcat-shutdown
    http://stackoverflow.com/questions/4153176/tomcat-security-roles-mapping
    http://stackoverflow.com/questions/4158468/tomcat-context-management

    Eli java-leima ei missään nimessä tarkoita näköjään sitä, että sillä olisi mitään tekemistä itse Java-ohjelmointikielen kanssa.

    Ja jos lasket esimerkiksi kaikki Spring'iin liittyvät ongelmat yhteen, päästään melko mukavaan prosentuaaliseen osuuteen. Spring on upotettuna sinne sun tänne (mm. java -> xml -> spring) ja jos Spring ei toimi tai on monimutkainen, niin siitä pitää valittaa Rod Johnssonille. Se ei ole Javan vika. Eli tällä ei jälleen ole mitään tekemistä Javan monimutkaisuuden kanssa, vaan sen että Spring (oma semi-suljettu open source frameworkinsa) on sellainen monsteri, että ei ihme jos yhdellä jos toisella menee sormi suuhun. (Harmi, että moderaattori tykkää kyttyrää tämän asian keskustelusta, sillä siinäkin olisin voinut heittää löylyä ja haasteita oikein huolella).

    Ja tässä vielä yksi erinomainen esimerkki Java-ongelmasta: http://stackoverflow.com/questions/8405545/ie8-error-there-are-multiple-root-elements-for-simple-string-returning-mvc-req

    Pysyn siis kannassani.

  121. Jouni Heikniemi - January 15, 2012

    Tuomas, moitin jo kesän SANKO-sessiossa tuota Stackoverflow-laskelmaasi, ja niin tekivät muutkin yleisössä (jos kohta eivät ihan yhtä äänekkäästi). Minusta se on edelleen harhaanjohtavaa arvailua eikä edusta mitään todellista pääteltävää aineistoa. Melkeinpä koen yleisön halventamiseksi sen esittämisen uudelleen ja uudelleen.

    C#:n, Javan ja F#:n asetelmat ovat keskenään niin erilaiset, että eroavien vastausprosenttien taustaselitykseksi ei todellakaan voi olettaa kielten ongelmatiheyttä jossain tietyssä käytössä. Itse yritin joskus kahlata hyväntekeväisyyshetkenä vastaamattomia C#-kysymyksiä läpi eikä siitä mitään tullut; suurin osa on sellaista huonosti kirjoitettua kuraa ettei jaksa yrittääkään, eikä todellakaan liity C#:iin vaan sen ympärillä oleviin kirjastoihin; näinhän Vakuutusmieskin Javan osalta totesi.

    http://stackoverflow.com/questions/tagged/c%23?sort=unanswered&pagesize=50

    vs.

    http://stackoverflow.com/questions/tagged/f%23?sort=unanswered&pagesize=50

    paljastaa karusti sen tosiasian, että C#:n unanswered-kysymyksissä on merkittävästi pienempi prosenttiosuus nimenomaan kieleen liittyviä kysymyksiä kuin F#:ssa. Tästä ei pidä päätellä että F#:n käyttö olisi jotenkin erityisen vaikeaa, vaan että on luonnollista, että uuden (no, kaikki on suhteellista, mutta tiedätte mitä tarkoitan) paradigman kielessä ongelmat kohdistuvat syntaksiin ja kielen ominaispiirteisiin kuten immutabilityyn.

    Kun F# elää aikansa, sille käy kuten C#:lle: kieli tägätään mukaan entistä enemmän myös soveltaviin kysymyksiin, koska vastausten esimerkit halutaan suoraan oikealla kielellä. Voi myös sanoa, että ero on siinä, kuinka kovat jätkät niitä kysymyksiä esittävät.

  122. Vakuutusmies - January 15, 2012

    Hi five, Jouni ;-)

  123. Tuomas - January 15, 2012

    Hmm… Kaikki mun yritykset tarkentaa Javan core-kysymyksiin veiv√§t suuntaa siihen, ett√§ kysymyksist√§ on huomattavasti suurempi prosenttiosuus avoinna kuin Javan "yleiskysymyksist√§".
    Esim. java-ee-6: 125 / 622 = 0,20.

    En heti keksinyt miten tuonne saa eksklusiivisesti vain tietyn aiheen kysymykset ilman kaikkia muita.
    Tein asiasta kysymyksen, palataan toivottavasti…

    Kyllä minäkin muistan ajan kun C# oli nuori. Silloin ei ollut Stackoverflowta, vaan kaksi foorumia, sittemmin maksulliseksi tullut expert-excange, ja Codeproject. Codeprojectista oli kiva lukea kaikki koodit, siellä oli aluksi vain C#-core- ja web-juttuja, sitten vähitellen aiheet laajenivat, oli sarjaporttiohjelmointia, jne. Nykyään se on lukemakelvoton, sillä viikossa enemmän kuin yksi intialainen julkaisee oman XML-käsittely-frameworkkinsa, koska ei ole osannut käyttää LINQ-to-XML:aa tms valmista kirjastoa.

    Lasken sen osittain koko ohjelmointiympäristön luonnollisen hapettumisen piikkiin, että kirjastojen ja frameworkkien ja platformien ja oheistuotteiden määrä kasvaa, ja ongelmat niiden parissa.

    Vastaavasti hyvä kirjasto voi myös parantaa ohjelmointiympäristöä. Sehän se on mikä tekee Javasta ja .NET-kielistä käyttökelpoisemman kuin vaikka Haskell.

  124. Koodain - January 15, 2012

    Myös täällä kompataan Jounia. Stackoverflowhun perustuva kompleksisuusanalyysi on aivan liian suorasukainen ja vaikuttaa suorastaan tarkoitushakuiselta.

  125. Tuomas - January 16, 2012

    Okei, vastaus tuli. Siihen voi lisätä perään plussilla lisää ja plusmiinuksilla pois, esim:
    http://stackoverflow.com/questions/tagged/java+-tomcat+-spring+-android

    Nyt, kuten kuvasta n√§kyi, niin noilla vahvasti tyypitetyill√§ funktionaalisilla kielill√§ oli alle 2% kysymyksist√§ avoimia. Pystyttek√∂ l√∂yt√§m√§√§n filttereill√§ vastaavaa tasoa muille kielille? Ja mieluiten niin, ett√§ total on suurempi kuin 1000, koska muuten se ei ole en√§√§ kovin luotettava…

    Ja kun koodaajia olemme, tästähän voisi koodata ohjelman, joka surffaa nettiä parallel executionilla asynkronisesti ja hakee tuon kombinaation automaagisesti. Helppo homma, tuossa ylempänä oli F#-malli 200 rivillä surffaus ja siihen vaikka 100 riviä logiikkaa, niin oletan, että siististi koodattuna Cobol/Java/C#-softana tämä olisi rivimäärällisesti sitten se tupla, eli max 600.

  126. Tuomas - January 16, 2012

    Ja siisti ei tarkoittanut lainausmerkeissä "siisti", vaan sellainen mitä kelpaa katsella myös business-koodissa. ;-)

    Jos Stackoverflow ei kelpaa, niin saisiko kritiikin lisäksi myös rakentavia vaihtoehtoja?

    Koodain,
    Tuon idea lähti siitä, että yritin mennä vastaamaan netissä F#-ongelmiin (itsekkäästi, saadakseni guru-pisteitä), mutta harmikseni sain huomata, että F#-käyttäjillä ei ollut ongelmia. Siksi oletin että F# on korkealla, mutta yllätyin kun näin tuloksen.

  127. Jouni Heikniemi - January 16, 2012

    Tuomas, jos tutkimuskysymyksesi on "Minkä kielen ohjelmoijilla on eniten/vaikeimpia ongelmia?", en usko että siihen saa hankittua vastausta Googlella. Oikea tapa olisi varmaan joku seurantakoe, jossa ihmiset koodaisivat esimerkiksi viikonlopun yli, ja joku seuraisi eri kieliä käyttävien ja eritaustaisten tiimien ongelmanratkaisua ja työn etenemistä.

  128. Vakuutusmies - January 16, 2012

    Tuomas,

    On vaikea antaa mitään kovin rakentavia vaihtoehtoja, sillä en oikein usko tuohon lähestymistapaan lainkaan. Ja monestakaan syystä. Esimerkiksi se, että sitä sun tätä on tagatty jollain kielellä (vaikkapa nyt sitten se Java tai C#) ei oikeesti kerro vielä mitään. Jos halutaan päästä edes lähelle oikeaa, sen filtterin pitäisi ottaa pois kaikki ja lisätä siihen vain ne joilla ei ole mitään muuta ja vielä sen pystyn jotenkin näkemään reiluna, että siihen lisätään Java EE ja siihen liittyvät teknologiat. Mutta mielestäni on lähestulkoon selvää, että mikäli kyseessä ei ole joku tuote tai jonkun tekemä kirjasto, niin kyllä siihen vastaus löytyy, oli kieli sitten Java tahi C#. Minun on ihan oikeasti vaikea kuvitella mikä olisi sellaista mihin näissä kielissä ei löydy ratkaisua, paitsi jos kysymys on täysin järjetön. Ja niitähän siellä myös piisaa.

    Mutta … kun katsot Java EE -tagin alla olevia kysymyksi√§, niin vain aniharvalla niill√§ on mit√§√§n tekemist√§ itse Java EE:n kanssa, vaan j√§lleen kysymyksess√§ ovat tuotteet/open source-kirjastot tai sitten kysyt√§√§n jotain niin absurdia, ettei siihen ole kukaan joko vastannut tai nostanut yht√§√§n vastausta siihen asemaan ett√§ se olisi katsottu vastatuksi. Kts esim. t√§m√§ http://stackoverflow.com/questions/5578738/how-to-store-javascript-variable-value-in-jsp-session.

    Näin ollen en siis usko, että tulet saamaan millään tuosta mössöstä aikaan mitään järkevää.

  129. Vakuutusmies - January 16, 2012

    Jouni,

    Sellainen seurantakoe on jo meneillään. Sen nimi on kissa ja hiiret speksin mukaisesti ;-)

  130. Tuomas - January 16, 2012

    Jouni, tuokaan ei oikein toimi: Softan yll√§pito on se mik√§ maksaa. Ne k√§yt√§nn√∂n ongelmat nousevat yll√§pidossa, ja sitten niit√§ taklataan Googlella, StackOverflow:lla tai yksin. Mink√§ tahansa purkkaviritelm√§n koodaa viikonlopussa. Esim. turhan xml-k√§sittelyframeworkin. Mutta kuka muu kuin kehitt√§j√§ itse haluaa rakentaa softaa sen p√§√§lle… Kyseisen frameworkin huonouden n√§kee vaikka sill√§, ett√§ Google ei l√∂yd√§ vastattuja kysymyksi√§ sen ongelmiin.

  131. Tuomas - January 16, 2012

    Ja vakuutusmiehelle, mä en koskaan ymmärtänyt niitä speksejä niin yksiselitteisesti, että voisin tehdä softan niiden perusteella. Siksi tyydyin näyttämään miten koodin ei tarvitse olla imperatiivista. Eli halusit mutable-tilan, mutta et halunnut. Ja hiirien piti tanssia jotain määrättyä kuviota, yhtaikaa mutta itsenäisesti? Eli saiko hiiri a liikkua 2 kertaa ennen hiirtä b, vai ei? Entäs 1000 kertaa?
    Mulle jäi se käsitys, että ensin syntyi toteutelma ja sitten vasta suunnitelma, ensin hiiri-koodi ja sitten vasta tämä speksi. Ainakaan en nähnyt yksikkötestienomaisia hyväksymistestejä tms missään muodossa, ainoastaan olemassaolevan softan outputin.

  132. Tuomas - January 16, 2012

    Skeetin OMG-Ponies-termein:
    Tietohallintomies: – It'll be simple!
    Vakuutusmies: – It works on my machine.

    V√§h√§n jopa ihmetytt√§√§, ett√§ miten nuo pelasivat niin hyvin yhteen…

  133. Vakuutusmies - January 16, 2012

    Tuomas,

    Tuomas: Eli halusit mutable-tilan, mutta et halunnut.
    Vakuutusmies: En halunnut, epäilen vaan miten muuten asian voi ratkaista.
    Tuomas: Ja hiirien piti tanssia jotain määrättyä kuviota, yhtaikaa mutta itsenäisesti?
    Vakuutusmies: Minulla eläimet siirtyvät siten, että jokaisen siirron välillä on random thinktime (välillä 100 ja 1000 ms) ja suunta on myös random. Eli jokainen eläimen jokainen siirto on periaatteessa erilainen näiden aikojen ja suunnan suhteen. Jos ei pääse mihinkään pää- tai väli-ilmansuuntaan, niin sitten ei liikuta.
    Tuomas: Jos kumpikaan eläin ei voi siirtyä mihinkään, niin se muuttaa asiaa, mutta muutoin rajan asettaa thinktime (100-1000ms).

    Tuomas: Mulle jäi se käsitys, että ensin syntyi toteutelma ja sitten vasta suunnitelma, ensin hiiri-koodi ja sitten vasta tämä speksi.
    Vakuutusmies: Ei todellakaan näin. Pyydän vielä Tietohallintomieheltä lausunnon asiasta.
    Tietohallintomies: Kyllä näin on, ensin oli speksi ja vasta sitten toteutus. En kertonut tästä kenellekään ennen julkaisua.

    Tuomas: Ainakaan en nähnyt yksikkötestienomaisia hyväksymistestejä tms missään muodossa, ainoastaan olemassaolevan softan outputin.
    Vakuutusmies: Java on niin helppoa, että en tarvinnut mitään testejä ;-)

  134. Vakuutusmies - January 16, 2012

    Tuomas,

    "Helppo homma, tuossa ylempänä oli F#-malli 200 rivillä surffaus ja siihen vaikka 100 riviä logiikkaa, niin oletan, että siististi koodattuna Cobol/Java/C#-softana tämä olisi rivimäärällisesti sitten se tupla, eli max 600."

    Ainakaan COBOLilla en suosittele aloittamaan, sillä siellä ei oikein tunneta sellaisia käsitteitä kuin URL tai HTTP.

  135. Vakuutusmies - January 16, 2012

    Tuomas,

    Yksinkertaistan kissat ja hiiret ongelmaa näin: kerro miten ilman mutable tilaa voi kolme (kaksi on vielä tehtävissä) *toisistaan riippuvaa* asiaa tapahtua yhtäaikaa, ei siis peräkkäin? Ja sitten tarkennuksia:

    1) Oletetaan, että ytimiä on min 3, joten oikeasti on mahdollista että ytimet suorittavat näitä kahta asiaa paralleelisti.
    2) Toisistaan riippuvuus voi tässä nyt sitten tarkoittaa vaikka sitä kissoista ja hiiristä jo niin tuttua liikkumista *vapaaseen* ruutuun *yksi* kerrallaan. Jokainen "eläin instanssi" menee vuorotellen yhteiseen ruutuun ja siirtyy vaikka ihan heti pois siitä (mihin vaan). Seuraava menee sisään ja tulee pois. Mutta siten, ettei sinne koskaan mene useampi kuin yksi kerrallaan.

    Ei tarvitse koodata, kerro vaan tarkkaan. Ja miksi sitten yhtä aikaa? Miksi ei? Miksi Petricekin koodissa http://fssnip.net/65 tehdään asioita yhtä aikaa?

    Ja lopuksi:

    Tuomas: "Tietohallintomies: ‚Äď It'll be simple!
    Vakuutusmies: ‚Äď It works on my machine."

    Vakuutusmies: – It works on your machine, too ;-)

  136. Tuomas - January 16, 2012

    Vakuutusmies,

    Jos meillä on kolme juttua: [1,2,3] ne voidaan helposti hajauttaa eri säikeille -> [1], [2], [3]
    Ne voivat harjoittaa toisistaan erillistä suoritusta vapaasti (joka voi joskus riittää, jos design on mietitty hyvin), mutta hankalaksi menee jaettu tila. Yksi muoto jaettua tilaa on kirjoitus UI:lle/konsolille, kun konsoli on omassa säikeessään.

    .NET:in System-namespace tuntuu keskimäärin sisältävän vähemmän bugeja kuin kehitysaikaiset custom-toteutukset.

    Koska en tykkää aiheuttaa helposti piiloon jääviä bugeja, niin kutsun mieluiten jotain Microsoftin suunnittelemaa korkeamman tason metodia (esim. F# Mailboxprocessor, tai Rx: ObserveOn()) hoitamaan threadien välistä kommunikaatiota ja synkronointia.

    Petricekin koodissa synkronointi tehdään thread-safe-collectionilla (.NET: ConcurrentQueue) lukemalla sitä omassa sitä varten omistetussa async-threadissaan, ja eri mailboxit vaan hoitavat kommunikaatiota threadien välillä.

    Jos Petricek haluaisi välttämättä välttää viimeiseen asti mutable-tiloja, niin synkronointijonoja voisi olla kaksi: käsitellyt ja käsittelemättömät:
    - Silloin kummankaan jonon itemien tila ei tarvitse olla mutable. Listoihin vaan lisätään eteen uusia arvoja (=linkedlist).
    - Jonojen itsessäänkään ei tarvitse olla mutable, jos tehdään rekursiivinen metodi, joka palauttaa meille aina uuden listan, sisältäen vanhan listan plus uuden arvon.

    Mutta j√§rjenk√§ytt√∂ saa olla sallittu, ei ne pari mutablea F#:lle mit√§√§n myrkkypillereit√§ ole. Immutable on hyv√§ best-practice, ja exception… siis poikkeus vahvistaa s√§√§nn√∂n.

    Ps. Mun koneella ei ole Javaa…

  137. Vakuutusmies - January 18, 2012

    Tuomas,

    Kun kerroit miten Petricek voisi tässä välttää tilaa ja sen muutosta, niin kerrotko vielä tarkemmin miten nuo kaksi jonoa toimivat. URL:than laitetaan toisessa mailboxprocessorissa käsiteltäväksi ja luetaan toisessa pois jonosta. Väitätkö siis, että muuttamatta ohjelman säikeistysmallia (eli montako mbp:tä ja kuka tekee mitäkin) jonot voisivat olla ei-concurrent'eja? Ja jos, niin miksi muka?

  138. Vakuutusmies - January 18, 2012

    Tuomas,

    Sillä aikaa kun odottelen Ramin kissa&hiiri -ongelman ratkaisua ja sinun lisäselvitystäsi siitä miten se kahden mailboxin yhteiselämä ilman ConcurrentQueue:ta onnistuu, tein sen Web crawlerin "eräällä" oliokielellä. Se on täällä http://pastebin.com/VcYYLgFx.

    Ei kulunut kaikki rivit mitä sillä Tomas Petricek:llä, joten jätin siis kommentointivaraa noin 50 riviä. Lisäsin myös vähän toiminnallisuutta, sillä se Tomasin toteutus oli aika hupaisa. Eli lisäsin sen, että ei lähdetä haahuilemaan koko webbiä läpi, vaan rajoitetaan sen johonkin tiettyyn syvyyteen (nyt 3). Myös parallelismia on lisätty tässä, sillä yhtäaikaisia crawlereita on nyt 10. Tulostus tietenkin sarjallistetaan kuten alkuperäisessäkin.

    Tulos näyttää tältä (tosin lyhynsin sitä aika lailla, kun crawler kävi läpi tuhansia ennen kuin lopetin sen).

    URL http://www.google.com/history/optout?hl=en crawled by agent 23. Depth is 1
    URL http://www.google.com/imghp?hl=en&tab=wi crawled by agent 22. Depth is 2
    URL http://www.google.com/webhp?hl=en&hl=en&tab=fw crawled by agent 22. Depth is 2
    URL http://www.google.com/webhp?hl=en&tab=iw crawled by agent 22. Depth is 2
    URL http://www.google.fi/imghp?hl=fi&tab=wi crawled by agent 30. Depth is 2
    URL http://www.google.com/webhp?hl=en&tab=lw crawled by agent 31. Depth is 2
    URL https://plus.google.com/103345707817934461425 crawled by agent 34. Depth is 2
    URL https://accounts.google.com/ crawled by agent 37. Depth is 3
    URL http://video.google.com/?hl=en&tab=iv crawled by agent 37. Depth is 2
    URL http://news.google.com/intl/en/about_customized_news.html crawled by agent 37. Depth is 2
    URL http://support.google.com/news/bin/answer.py?hl=en&answer=40237 crawled by agent 39. Depth is 2

  139. Tuomas - January 19, 2012

    En meinannut ett√§ jonot voisivat olla "ei-concurrentteja", vaan, ett√§ jonoista saataisiin enemm√§n tilattomat. √Ą√§rett√∂m√§st√§ jonosta voidaan kahdella pointterilla saadaa normaali jono: t√§st√§ se alkaa, ja t√§h√§n se loppuu. Vastaavasti meinasin, ett√§ olisi kaksi jonoa, jotka toimisivat threadien v√§lill√§ vastaavasti kuin tuo yksikin.

    En nyt vielä kauheasti keulisi tuolla rivimäärällä, kummastakin koodista kommentit poistamalla Petricekin koodissa merkkejä on 2985 sulla 3350. Tietysti muuttujat voidaan nimetä lyhyemmiksi, jne, mutta koodin lyhyys ei ole Petricekilläkään ollut homman pointti.

  140. Tietohallintomies - January 19, 2012

    Niin, eihän sillä tarkoitus ole keuliakaan. Pointti onkin se, että tässäkin nähdään se, että se valtava koodin vähyys funktionaalisella ohjelmoinnilla saattaa sittenkin olla lähinnä myytti. Saatan kohta lähettää Tietoviikkoon: "Tapiolan tietohallinnon Salminen kertoo, että funktionaalinen ohjelmointi saattaa johtaa joissakin tapauksissa jopa 33% suurempaan rivimäärään".

    Itse asiassa olin täysin varma, että joku lähtisi laskemaan merkkejä koodista. Javassa on enemmän kohinaa mitä monissa muissa kielissä (joskin osa poistuu Java 7:n myötä), mutta se on täysin yhdentekevää. Minä koen näiden merkkien laskemisen lähinnä huvittavaksi. Ja sitä paitsi, itse koin sen F# Web crawlerin melkoiseksi bordelliksi; koodissa pompitaan koko ajan sinne sun tänne ja siitä (kuten omastanikin koska osittain apinoin alkuperäistä) puuttuu vaikka mitä (mm. suhteelliset urlit ja base-tagin tunnistus). Eniten aikaa meni sen selvittämiseen. (Tosin F#-taitoni eivät ehkä ole vielä kovinkaan täydelliset).

    Ja mitä tulee sitten niihin jonoihin (jotka varmaankin ovat aina tilallisia, mutta eivät välttämättä mutableja): jos samaa jonoa luetaan/kirjoitetaan useammasta kuin yhdestä säikeestä sinun on pakko käyttää jotain josta joka pitää prosessorin kakut/muistin järjestyksessä. Onko se sitten lukko, volatile write/read, jompikumpi näistä mailboxprosessorin toimesta, tms on eri asia, mutta ilman sitä et selviä. Referenssi jonoon joko muuttuu (jolloin osa muutoksista voi mennä "ohi") tai ko. olion (lista) muutetaan (jolloin on käytettävä lukkoa tms). Jos haluat ymmärtää miten concurrency/parallelismi voi toimia tai olla toimimatta ja missä tullee raja vastaan kts. http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2009.04.05a.pdf.

  141. Tietohallintomies - January 20, 2012

    Mitäs tällä Web crawlerilla pitikään tehdä? Tein nyt siitä F#-hässäkästä oman versioni, joka toimii huomattavasti paremmin mitä alkuperäinen. Joten nyt odottaisin jotain tarkennusta tähän aikaisempaan kommenttiin: "Ja kun koodaajia olemme, tästähän voisi koodata ohjelman, joka surffaa nettiä parallel executionilla asynkronisesti ja hakee tuon kombinaation automaagisesti. Helppo homma, tuossa ylempänä oli F#-malli 200 rivillä surffaus ja siihen vaikka 100 riviä logiikkaa, niin oletan, että siististi koodattuna Cobol/Java/C#-softana tämä olisi rivimäärällisesti sitten se tupla, eli max 600".

    Rivimäärä vieläkin vähemmän ja toiminnallisuutta selvästi enemmän. On base-tagin ymmärtämistä, relatiivisten URL:ien käsittelyä, pysymistä yhden domainin sisällä sun muuta. Eikun taas laskeskelemaan merkkejä, sillä rivimäärä on *tällä* toiminnallisuudella jotakuinkin sama ;-)

    Huomatkaa tokis myös se, että en alkanut itkemään siitä, että on väärät tai huonot speksit, tai että alkuperäinen on liian funktionaalista.

    http://pastebin.com/0gaVNgqW

  142. Tuomas - January 21, 2012

    Moi,

    Noh, alkuperäinen, vahvasti kritisoitu, stackoverflow-analyysi-ideani (myönnän että ei ole ongelmaton, mutta parempiakaan ei ole, ja hei, käytetäänhän taloustieteissäkin bicmac-indeksiä, yms) oli,
    että kun stackoverflowssa on aina kaksi toisiaan vastaavaa urlia, questions ja unanswered, esim:
    http://stackoverflow.com/questions/tagged/java
    http://stackoverflow.com/unanswered/tagged/java

    ja sitten sivulla on myös tuo h4 id="h-related-tags" jonka jälkeen tulee div joka sisältää urlit (esim. href="/questions/tagged/java+android")

    ja lisäksi noiden sivujen lähdekoodissa on aina div css-luokalla "summarycount al", jossa on kyseisen tägimäärän kysymysten/vastaamattomien määrä. (Siitä pilkku-tuhaterotin pois.)

    Niin tätä voisi käyttää siihen, että etsii ne tekniikat, joissa on:
    - questions määrä yli 1000 ja
    - unanswered jaettuna questions mahdollisimman pieni

    Siten löytyisi käyttäjille mahdollisimman ongelmattomat tekniikat.
    Unanswered jaettuna questions tyypitetyillä funktionaalisilla kielillä oli alle 0,02.

    Mutta koska nyt oli alunperin kyse core-javasta, niin ajattelin että tuon +tekniikka sijaan muokkaa urlia sen verran, että laittaa miinuksen ekan jälkeen kaikkiin, se olisikin
    href="/questions/tagged/java+-android" ja seuraavan saa seuraavalta sivulta ylimpää, valmiiksi oikein, paitsi miinus viimeiseen osaan urlia, se olisi sitten "/questions/tagged/java+-android+-hibernate"

    Toivottavasti crawleri ei hammeroi stackoverflowta kyykkyyn. ;)

  143. Tuomas - January 21, 2012

    600 riviä oli tietysti vaan mun alkuperäinen arvio siitä, mikä on Java-työmäärä.

    Koitin pikaisesti vääntää F#-version, en optimoinut, ja testasin vain vähän, käytin sync-requesteja, koska tehokas async olisi vaatinut codeplexistä lisäkirjaston.

    Tässä koko softan koodi: http://www.fssnip.net/a9

  144. Tuomas - January 21, 2012

    Annoin tuon jauhaa jotain 15min niin kyll√§ se stackoverflown palomuuri viimein pisti j√§√§hylle…

  145. Koodain - January 22, 2012

    Hetkinen, ollanko nyt vuodessa 2012? Nimittäin kun tulee jotenkin mieleen noin vuosi 1980, jolloin laskin ensimmäisen kerran ohjelmakoodin merkkejä. Tosin, silloin siihen oli hyvä syy, sillä muistia oli ruhtinaalinen yksi kilo. Myöhemmin asiat menivät vielä pidemmälle kun sulautettuja järjestelmiä tehdessä laskettiin bittejä koska muistia oli yhä edelleen rajallisesti. Viimeisen kerran muistelen tehneeni tämmöisiä laskutoimenpiteitä ehkä joskus 90-luvun puolivälissä ja silloinkin yhä edelleen sulautettujen järjestelmien parissa. Ja nyt niitä merkkejä lasketaan taas. Mikähän tälle mahtaa olla syy nykyään kun jo rannekellostakin löytyy muistia enemmän kuin tarpeeksi? No, oikeasti (joissakin) sulautetuissa järjestelmissä lasketaan bittejä vieläkin, mutta finanssialan järjestelmistä puhuttaessa en oikein ymmärrä pointtia. Ja sama pätee rivimäärien laskemiseen. Toki esim. Scalaa mainostetaan siten, että mitä vähemmän kohinaa, sitä vähemmän virhemahdollisuuksia. Tämä on periaatteessa ihan totta, mutta kenellä on ollut oikeasti kriittisiä ongelmia esimerkiksi gettereiden ja settereiden kanssa? Varsinkin kun ne tehdään generoimalla. Tai että pakollisten puolipisteiden kanssa olisi kriittisiä virheitä. Sen sijaan on niin, että kun puolipistettä ei vaadita voi esiin tulla mielenkiintoisia asioita (lue: vaikeasti löydettäviä bugeja). Esimerkki Scalalla:

    val list1 = List
    {
    ….println("list1") // …. = sisennys
    }
    val list2 = List;
    {
    ….println("list2") // …. = sisennys
    }

    list1.getClass() ei palauta ihan sitä mitä ehkä odottaisi.

    On selvää, että uusien kielten kanssa on vähemmän kohinaa, mutta niin pitääkin olla sillä muutoinhan ei olisi otettu oppia menneestä. Kohinan poistossa on kuitenkin kääntöpuolensa. Esimerkiksi:

    Scala:
    val names = Array("Star Trek", "Moonbase Alpha", "Star Wars")
    println((0 /: names) { _ + _.length })

    Java:
    String[] names = { "Star Trek", "Moonbase Alpha", "Star Wars" };
    int total = 0;
    for(String name : names)
    ….total += name.length(); // …. = sisennys
    System.out.println(total);

    On kyllä vähän kohinaa Scalassa, mutta kumpi koodeista on ymmärrettävämpää?

    Ja pienellä luovuudella se Java-koodikin saadaan lyhyeksi, mutta lyhyyden varjolla en siltikään seuraavaa koodia hyväksyisi kolmesta syystä; se on epäselvää, performoi heikommin eikä edes toimi oikein kaikilla mahdollisilla merkkijonoalkioilla (esimerkki tietenkin toimii oikein). Tässä kuitenkin se lyhyt versio:

    String[] names = { "Star Trek", "Moonbase Alpha", "Star Wars" };
    System.out.println(Arrays.toString(names).replaceAll("[\\[\\]]|, ").length());

    Ja se että kieli pakottaa ohjelmoijan kirjoittamaan muuttujan tyypin on vain ja ainoastaan hyvä asia. Oman navan (= uuden koodin kirjoittamisen) sijaan kannattaa joskus katsella asiaa toisista saappaista (= koodin ylläpitäjä). Se että kieli pakottaa kirjoittamaan tyypin se samalla auttaa ylläpitäjää löytämään helposti muuttujan tyypin myöhemmin ilman arpomista.

    "Mieluummin 100 riviä selkeää ja ymmärrettävää koodia, kuin 50 riviä epäintuitiivisia konventioita sisältävää koodia".

  146. Tuomas - January 23, 2012

    Koodain,

    Tietotyypit ovat ohjelman oikeellisuuden tarkistusta. Koodaaja ei tee niillä mitään.
    Ainoa paikka missä niiden puutteesta voisi teoreettisesti olla haittaa on, jos tekee codereviewn muulla kuin IDE:llä.
    Suurin haitta on, noisen lisäksi, että n-kerrosarkkitehtuurissa domain-mallin pienessä tyyppinimenmuutoksessa joutuu puukottamaan joka kerrosta.

    Aikanaan koulussa tein c-kielen funktiopointterin (ironista että aihealue on sama), koska harjoitustyössä käskettiin. Silloin en ymmärtänyt mitä hyötyä funktiopointtereista voi olla, eikä opettajakaan osannut selittää. Kuten se, tämäkään ei toimi 100 rivin koodilla, ja ei näytä aukeavan selittämällä, voin vain rohkaista kokeilemaan:

    Kyse ei ole mistään rivimäärän puristuksesta syntyneestä lineaarisesta koodisäästöstä, vaan deklaratiivisuudesta ja korkeammasta abstraktiotasosta (eksponentiaalinen säästö).

    Toinen iso muutos, joka ei toimi ilman koodimäärällisesti pieniä olioita, on REPL-interactive-ympäristön tuoman kehitystavan muutos:
    Voi keskittyä itse ongelmaan, ei siihen, että miten lisätään testiprojekti ja tehdään yksikkötestit ja poljetaan niitä debuggerilla läpi suorittaen kymmentä fileä ja kasaa IoC-stubeja/mocckeja.

    Olet oikeassa siinä, että business-koodin pitää olla selkeätä. Scalan syntaksi voi vaikuttaa Java-koodaajasta kryptisemmältä kuin Java. Ei ihme, mustakin englannin kieli vaikuttaa kryptisemmältä kuin suomi.

    Vakuutusmies esitti (epäsuorasti, mutta kuitenkin) varsin asiallisen kritiikin talouslehtien mainonnasta:
    Vaikka koodaisin 1000 riviä Javaa tai vastaavat 500 riviä Scalaa, niin Scala ei kuitenkaan synny suoraa puolet halvemmalla/nopeammin:
    - Toiminnallisuus on sama. Kumpi kestää kauemmin: koodata syntaksirivit vai ajatella läpi toiminnallisuus?

  147. Tietohallintomies - January 23, 2012

    Tuomas: "Tietotyypit ovat ohjelman oikeellisuuden tarkistusta. Koodaaja ei tee niillä mitään."
    Vakuutusmies: Ei pidä paikkaansa. Esimerkiksi

    let foolish( a,b,c ) = a (b * c)
    val foolish : int * int * int -> bool

    No niin, ihan väärä tyyppi. Pitää pystyä antamaan sisään myös desimaalilukuja! Mitä teen? No tyypitetään (joo, ymmärrän toki että olen tekemässä tyhmyyksiä, mutta F#:han ei siitä minulle kerro)

    let foolish( a:float,b:float,c:float ) = a (b * c)
    val foolish : float * float * float -> bool

    Testataan

    foolish( 10.0,50.0,0.2 )
    val it : bool = false

    Toimii! Ei kun tuotantoon. Siellä sitten tuleekin vastaan tällainen (ei tosin literaaleina)

    > foolish( 2.9,0.1,29.0 )
    val it : bool = true

    Voi voi, nythän se menikin sitten väärin. No syy on tietenkin liukuluvuissa ja olisi mennyt (nyt tällä kertaa) oikein jos olisi tyypittänyt luvut oikein desimaaliksi.

    let foolish( a:decimal,b:decimal,c:decimal ) = a (b * c)
    val foolish : decimal * decimal * decimal -> bool

    foolish( 2.9m,0.1m,29.0m )
    val it : bool = false

    Tarinan opetus? Koodarin on joskus kuitenkin annettava tyyppi ja tunnettava miten se toimii. Erityispainoa asialle tulee jos määrittelen rajapinnan vaikkapa C#:n käyttöön. Siinä alkaa yleensä tyypin kirjoittaminen jo maittamaan.

    Itse en kyllä kovin hirveästi pidä type inference'stä ja olen täysin varma, että pystyn elämään ilman sitä.
    Tuomas:
    "Vaikka koodaisin 1000 riviä Javaa tai vastaavat 500 riviä Scalaa, niin Scala ei kuitenkaan synny suoraa puolet halvemmalla/nopeammin:
    - Toiminnallisuus on sama. Kumpi kestää kauemmin: koodata syntaksirivit vai ajatella läpi toiminnallisuus?"
    Vakuutusmies: Juurikin näin

  148. Tietohallintomies - January 23, 2012

    Arrrgh,

    Taas jäi pienempikuin ja suurempikuin merkit pois. Piti olla siis

    let foolish( a,b,c ) = a erisuurikuin (b * c)

  149. Tuomas - January 23, 2012

    Tietohallintomies,

    Tarinan opetus meni nyt ihan pieleen…

    Jos nuo ovat sulla samassa lähdekoodissa (ei interactivessa), niin F# etsii geneerisimmän rajapinnan ja käyttää sitä.

    Interactivessa se ei tietenkään voi sitä etsiä kun ei tunne käyttötapauksia.

    Kummassakin tapauksessa voit halutessasi tehdä geneeristä koodia näin:
    let inline foolish( a,b,c ) = a erisuurikuin (b*c)

    Jälleen: tyyppi pitää kirjoittaa kääntäjälle vain, jos *kääntäjä* ei sitä osaa. Lähdekoodissa *koodaaja* ei tarvitse tyyppiä mihinkään.

    Pysyn aiemmassa lausunnossani.

  150. Tuomas - January 23, 2012

    Piti lukea:
    F# etsii *vähiten* geneerisimmän rajapinnan.

    Tai siis järkevimmän. Suoritukselle riittävän.

  151. Vakuutusmies - January 23, 2012

    Tuomas,

    se voi etsiä nuppineulan kokoisessa projektissa, mutta ei "ison maailman" sovelluksessa. Eivät ne sorsat pyöri kaikkialla, vaan pitäisi pystyä käyttämään myös käännettyjä kikkareita. Varmuudella en sano mitään, mutta ihmettelen vaan mitenköhän toi inline mahtaa toimia jos annat minulle F#:lla toteutetun assemblyn C#:n käyttöön? Tai minkä kokoisen funktion uskallat inline:ta? Eikä se kuitenkaan ratkaise sitä, että joka tapauksessa pitää ymmärtää miksi vaikkapa 2.9 != ( 0.1 * 29.0 ) ja tyypitys on tehtävä desimaaliin jos haluaa koodin toimivan edes jotakuinkin järkevästi. Jos taas haluaa, että koodi suorituu (nuppineulan päätä isommissa jutuissa) pitää osata käyttää molempia. Esimerkiksi Javassa double on aivan sikana nopeampi kuin BigDecimal. Ei ole ympäristöä millä testata, mutta en näe mitään perusteita miksi näin ei olisi myös .NET:ssä. Ja syyhän löytyy taas ihan sieltä hardwaresta saakka.

  152. Vakuutusmies/Tietohallintomies - January 23, 2012

    Hyvät funktionalinistit ja muut,

    Se alkaa olla nyt Vakuutusmiehen sekä Tietohallintomiehen tarinat sitten tässä. Kiitos Jounille "varastamastani" levytilasta ;-)

    Mitä tästä kaikesta meuhkaamisesta sitten jäi käteen? No, minä opin hieman uutta sieltä sun täältä kun jouduin varmistelemaan sitä sun tätä, jotta en väitä mitään MUTU-periaatteella. Ja koska opettelin vähän myös F#:a, niin myös sellaista iisiä Scalaa osaan nyt lukea melko sujuvasti.

    Mit√§ mielt√§ sitten olen funktionaalisuudesta? Funktionaalisissa kieliss√§ on toteutettuna muutamia ihan kivoja asioita, mutta juuri mik√§√§n niist√§ ei itse asiassa ole funktionaalisten kielten "yksityisomaisuutta". Esimerkiksi X10 (oliokieli) on paljon samoja asioita mit√§ funktionaalisissa kieliss√§, mutta my√∂s muutamia sellaisia asioita joita voi olla hieman hankala muista kielist√§ l√∂yt√§√§ (esim. kielen suora tuki FPGA:lle ja GPU:lle, distributed parallelism, …). N√§iss√§ kieliss√§ (F#, Scala) on kuitenkin yksi yhteinen tekij√§: niill√§ ei ole riitt√§v√§sti k√§ytt√§ji√§ eik√§ osaajia. Jos esimerkiksi luette t√§m√§n blogin l√§pi voitte itse tehd√§ johtop√§√§t√∂kset vaikkapa F#:n concurrency/parallelism asioiden osaamistasosta. Jos nyt puhun pelk√§st√§√§n Scalasta ja F#:sta, niin uskon ett√§ kumpikin n√§ist√§ kielist√§ s√§ilyy hengiss√§ *vain ja ainoastaan* sen takia, ett√§ niist√§ pystyy k√§ytt√§m√§√§n host-platformin oliokirjastoja. Ilman .NET-kirjastoja F# olisi n√§√§ntynyt jo laboratorio-olosuhteisiin. Sama koskee Scalaa. N√§ht√§v√§ksi j√§√§ miten n√§m√§ kielet selviytyv√§t jatkosta. Ainakaan itse en olisi liian toiveikas. Kun esimerkiksi Java 8 l√§ps√§ht√§√§ saataville (mukana funktionaalisista kielist√§ p√∂llittyj√§ ominaisuuksia), veikkaan ett√§ n√§emme kohtalaisen jyrk√§n taantuman Scalalle. Osittain uusien piirteiden takia ja osittain vain sen takia, ett√§ Javasta tuli vihdoinkin taas uusi versio.

    Eritt√§in suurena miinuksena funktionaalisille kielille on my√∂s se fakta, ett√§ nykyiset suunnittelumallit (joita en l√§htisi kovasti kritisoimaan) perustuvat l√§hinn√§ vain ja ainoastaan olioihin. Ihmiset, min√§ mukaanlukien, nyt sattuvat ajattelemaan monista asioista oliomaisesti. Olen n√§hnyt miten oliosuunnittelulla ja oliokielell√§ toteutettuna homma toimii erinomaisen hyvin (t√§st√§ kokemusta sellaiset 20 vuotta). Toisaalta olen nyt my√∂s viime aikoina n√§hnyt projekteja joissa propelip√§√§t ovat tulleet kertomaan ett√§ agilea ja scrumia peliin vaan ja mit√§√§n suunnittelua ei tarvita. Ja juuri n√§m√§ projektit ovat ep√§onnistuneet ja laatu on ollut, anteeksi moderaattori, kauheaa paskaa. Vain IT-alan ihmiset ovat niin arrogantteja, ett√§ kuvittelevat ett√§ jotain j√§rkev√§√§ voi tehd√§ ilman suunnittelua (vrt talon rakennus, auton rakennus, …). T√§m√§ oli siis kannanottoni siihen suunnittelun tarpeeseen.

    No, joka tapauksessa minä vaihdan nyt varastomiehen univormun päälleni ja siirryn tietovarastoinnin ihmeelliseen MPP-maailmaan, eli taas ihan sellaista real life parallelismia.

    Onnea ja menestystä kaikille,

    Vakuutusmies/Tietohallintomies

  153. Tuomas - January 24, 2012

    F# ei ole ensisijaisesti tarkoitettu kevyeksi skriptikieleksi (kuten esim. Python), vaan dll-logiikka-kirjastojen rakennukseen.

    Menemättä tarkemmin CLR/IL-puolelle, niin yhteensopivuushuoli on turha. Vastaavasti C#:lla voi tehdä VB-yhteensopivia dll:iä. F# on (ML-pohjainen) OCaml-kieli .Net-ympäristöä varten.

    Oman kokemukseni mukaan "let" saa tyypin noin 80% tapauksista ilman lisäohjeita. Se on paremmin kuin esim. C#, jossa "var" ei voi olla Func, ja metodiparametrit pitää määritellä aina. Yleensä inline-koodia ei tarvitse kirjoittaa. Generic-tyypit merkitään pilkulla: 'a 'b 'c

    Uudet kielet tuovat hyvää painetta vanhojen kielten kehitykseen. Silti, kuten muukin softa, vanhat ohjelmointikielet kulkevat tiensä päähän aikanaan. Ei se C++ ole onnistunut nousemaan enää valtakieleksi, vaikka .NET-puolella siihen on saatu paljon uusia ominaisuuksia. On sille paikkansa, mutta käyttö on vähenemään päin.

    Omasta puolestani kiitos Vakuutusmiehelle käytetystä ajasta, linkeistä ja keskustelusta.

  154. Varastomies - February 10, 2012

    Ei oikein lenn√§ toi funktionaalisuus viel√§k√§√§n jos tuosta TIOBE:n listasta voi mit√§√§n p√§√§tell√§ …

    Object-Oriented Languages 57.6% +0.4%
    Procedural Languages 36.3% -1.0%
    Functional Languages 4.2% -0.1%
    Logical Languages 1.9% +0.7%

  155. C#-koodaaja - February 22, 2012

    TIOBE:n listalla OO-kielet (57%) pitävät sisällään mm. C# (8.7%).

    Nykyisellään C# (LINQ:ineen) on about kolmasosan funktionaalinen kieli. Siitä siirtyisi heti reilut 2,5% OO-kieliltä funktionaalisille.

    Ja mikäs Javascript sitten on? Tekijöidensä mukaan (Crockford) funktionaalinen. Mutta Javascript+Python>4.2, eli listan mukaan ei.

    Kategoriat eivät ole noin mustavalkoisia. Ehkä ne pitäisi jakaa uusiksi, ehkä lisätä Multi-paradigm Languages?

  156. Varastomies - February 27, 2012

    Entä miten pitäisi huomioida se, että suuri osa oliokielten ja osittain jopa funktionaalisten kielten ohjelmoijista ei kuitenkaan kirjoita ohjelmiaan oliomaisesti/funktionaalisesti vaan proseduraalisesti? Eli laitetaanko sitten sellaiset +50% proseduraalisille kielille heti samoin tein?

    Ja sitten Javascriptiin. Kuka sanoo, että Javascript on funktionaalinen? Jos vetoat Douglas "Cockford":iin, niin hänen kaikkia sanomisiaan en ottaisi ihan vakavasti. Hän ei myöskään ole Javascriptin isä, vaikka niin ilmeisesti oletit. Jos katsot vaikkapa http://www.crockford.com/javascript/private.html, niin hän esittelee siinä Javascript-patterneja, mutta ei muista kertoa, että osa niistä onkin eräänlaisia anti-patterneja (esim. juuri tuo privileged methods). Fakta on se, että toistaiseksi Javascriptistä ei ole täysveriseksi oliokieleksi (mm. koska tilan piilottaminen ei ole mahdollista järkevästi), eikä siitä myöskään ole kovin hyväksi funktionaaliseksi kieleksi. Sanon tämän kokemuksesta, en siitä että Douglas "Cockford" on sanonut niin. Oliokieleksi siitä voi tulevaisuudessa ehkä ollakin, mikäli tämä menee läpi http://wiki.ecmascript.org/doku.php?id=harmony:classes.

  157. Vakuutusmies - March 16, 2012

    Jäi vähän viime tinkaan tämä kun yllättäin Don'in maili oli mennyt roskapostin joukkoon ja löysin sen vasta nyt kun putsailin postilodjuani ;-)

    Tässä Don Symen vastaus esittämääni kissat ja hiiret haasteeseen, johon pyysin siis hänen mielipidettään ja mahdollista ratkaisua. Tai tarkemmin ottaen halusin hänen kertovan, että kyllä sitä mutable tilaa tarvitaan tässä ongelmassa.

    Kevätterveisin,

    Vakuutusmies

    Don Syme:

    "Hi Salminen,

    Its an interesting problem, and I think its great to challenge functional-think in this way.

    I can't write up an answer due to lack of time, and in any case it may well be I'd recommend the use of agents or mutable state – I'm no functional-fundamentalist :-) But I would encourage you to blog this and to ask this kind of question on stackoverflow or stackexchange – and ask for working code for the answer :-)

    Kind regards

    don
    "

    ja Vakuutusmiehen kysymys:

    On the other hand I'm also interested to know what functional programming is really good for and what it doesn't fit well. That’s why I joined discussion thread. However, these guys are just repeating the mantra about immutable objects, how shared state is root of all evil (which is partly true) and with functional programming is not needed at all (which I don't buy). I personally think this is crap, but I wanted to get a second opinion and decided to contact "trusted source", which in this case means you.

    First, I describe the challenge together with its restrictions. Here we go:

    The idea is to have self-playing game with a number of animals (rats and cats) in the maze. The maze contains rooms and each room can host only one animal at the time, except when rat is eated. If rat and predator enter the same room, predator eats the rat and rat must leave the game. Two predators cannot enter the same room and same applies to rats: they can't be in the same room, ever (including initialization). Each animal (i.e. instance of rat or cat) thinks a random period of time before moving to next room (just like in real world they have free will). This means that all animals can, but are not limited to, move randomly (north, nort-east, east,south-east,…) at the same time. If there's too much congestion (no free rooms after checking each point), the animal stays where it is.

    To me this implies that animals must be threads or similar behaviour must be implemented with the help of timers (which means threading again). The maze contains state which must be shared by all animals (threads): for example, available locations. I think it's a little bit hard to use immutable datasturecture as a maze (without locking), since other animals can move while switching the "current" maze state (thus loosing for example movement events). A little bit similar behaviour can be implemented without locking by using message passing, but I think it results in quite clumsy implementation.

    Any comments? I would really appreciate your response.

    BR, Pasi Salminen

  158. Vakuutusmies - March 16, 2012

    Tuosta vakuutusmiehen kysymyksestä puuttuu siis alusta hieman tekstiä johon korvasin tagin sisään (joka siis suodattui pois).

    * some ranting filtered out *

  159. Tuomas - March 26, 2012

    Moi,

    Lukoista vielä, kiinnittäisin huomiota: "agents or mutable state". Agents, message-passing ja mail-box-processor on samalle asialle monta eri nimeä, mutta se on tuotu tässä vaihtoehtona eksplisiittiselle tilalle. (Kuten aiemmin puhuttiin, niin siinä on näennäinen tila, yksi thread kontroloi sitä, mutta se on yksittäisen threadin sisäinen asia.)

    Koitin viikonloppuna ILSpyllä katsella mitä Mailboxprocessorin sisältä löytyy, ja .NET lock:eja sieltä en löytänyt (mikä ei takaa, ettei niitä jossain olisi). Siellä oli wait-retry-wait-retry-tyylinen jonotuskuvio.

    Sen sijaan Rx:ssä oli lockkeja.

  160. Tuomas - April 10, 2012

    Moi taas,

    Kävipäs tuuri, sillä eilen ilmestyi uusi video, jolla itse actor mallin isä vähän avaa ideologiaa actor(/message passing/mailbox/agents)-mallin takaa:

    http://channel9.msdn.com/Shows/Going+Deep/Hewitt-Meijer-and-Szyperski-The-Actor-Model-everything-you-wanted-to-know-but-were-afraid-to-ask

  161. Varastomies - April 24, 2012

    Moi,

    En katsonut tuota videota, mutta varmuudella voin sanoa, että myös message passing vaatii jonkun muistin synkronointimekanismin, eli joko lukon tai volatile muuttujan. En näe mitään syytä miksi se käyttäisi lukkoa, mutta volatile muuttujan siellä todennäköisesti on. Tämä perustuu siihen, että jopa Microsoft ei voi sille mitään miten prosessorit toimivat. Eli taas voi katella sitä muistimalliopusta tai MESI-protokolla. Molemmat linkit löytyvät ylempää. Muistuttaisin kuitenkin, että message passing mekanismi ei mahdollista kunnollista kissat ja hiiret pelin tekoa speksien mukaan.

    t. Varastomies

  162. Tuomas - May 5, 2012

    Yksittäisen prosessorin sijaan voidaan ajatella vaikka pilvi-arkkitehtuuria.

    Toimiihan esim. (hajautetut) versionhallintajärjestelmätkin niin, että synkronointi voidaan hoitaa paikallisesti, eikä jokaisen kehittäjän tarvitse lukita koko tilaa oman päivityksensä ajaksi. Merge-operaatiot tehdään aika-/eventhistorian pohjalta. Ajan ottaminen parametriksi ei ole kovin kummallinen temppu.

    Synkronointimekanismin ei tarvitse olla keskitetty, vaan se voi olla osittainen. Niin kauan kuin hiiret vain kuolevat pois, niin koko synkronointi voidaan vaikka laskea kokonaan jälikäteen. Sitten jos hiiret alkaisivat pariutua uusia hiiriä, niin tarvitaan jonkunlaista synkronointia ennen operaatiota, mutta tästä lisää Animal Planetilla.

  163. Varastomies - May 24, 2012

    Moi,

    No joo, joissain asioissa voi tietenkin aina fuskata, mutta esimerkiksi ydinohjusten ohjausjärjestelmän kanssa näkisin ihan oikean toimivuuden aika tärkeäksi. Tai voi toki olla, että joku jää tänne sitten vielä laskemaan niitä jälkikäteen. Sama pätee vaikkapa sairaalalaitteisiin; voi olla hieman myöhäistä peruuttaa tiettyjä väärin perustein tehtyjä operaatioita jos potilas on jo kuollut. Ei onnaa kun Schrödingeriltä. http://hikipedia.info/wiki/Schr%C3%B6dingerin_kissa

  164. Tuomas - June 6, 2012

    "Oikea toimivuus" riskeerataan aika monella muullakin tapaa kuin synkronoinnilla. Noin ylipäätään IT-toimittajien puitesopimukset ovat toimittajille edullisia ja sopimussakot ovat pieniä. Asiakkaat ne mokat maksavat, eivät toimittajat.

    Mutta mitä jälkikäteen laskemiseen tulee, niin se voidaan kyllä tehdä, kunhan homma mietitään oikein. (Ja säästetään servereiden hinnoissa aika huomattavasti.) Esim. Amazon ei voisi käsitellä varastoaan reaaliajassa. Tästä lisää viime vuoden techdays-esityksissä:
    http://video.fi.msn.com/watch/video/kolmikerrosarkkitehtuurin-evoluutio-cqrs-mikko-hytti-fujitsu-services/15db8zqmr
    http://video.fi.msn.com/watch/video/cqrs-kaytannossa-pasi-taive-cybercom/15dl3ey0i
    (Taas vaaditaan Silverlightia. Pasi T ja Mikko pitivät aiheesta myös SANKO-tapahtuman.)

    CQRS+EventSourcing on itse asiassa hyvin lähellä Agents-henkistä mallia ja funktionaalista reaktiivista ohjelmointia. Sanoisin jopa, että CQRS+EventSourcing on saatu, kun funktionaaliset ajatusmallit on sovellettu (oliopohjaisiin enterprise-)arkkitehtuurimalleihin.

  165. Varastomies - June 21, 2012

    Päivää taas,

    Ihan tiedotuksen omaisesti vaan kerron, että F# on tippunut Tioben listalla sijalle 50-100. Lieneekö F#-koodarit lomalla jo vai mistä on kyse?

    t. Tietohallintomies

  166. Christen - June 27, 2014

    Olen on surfing verkossa yli kolme tuntia tänään, mutta en koskaan löytänyt mitään mielenkiintoinen artikkeli kuten sinun. On melko arvoinen riittää
    minulle. Mielestäni, jos kaikki sivuston omistajat ja bloggaajat
    teki hyvää sisältöä kuten teit, internet
    on paljon enemmän hyötyä kuin koskaan ennen.
    I voinut pidättäytymään kommentoi. Täydellisesti kirjoitettu!

    Tulen heti tarttua teidän rss koska en voi löytämisessä teidän email tilaus linkkiä tai uutiskirjeen palvelu.

    Onko sinulla mitään? Hyvä salli minut ymmärtää jotta I voi tilata.
    Kiitos.
    On täydellinen aika tehdä tulevaisuuden suunnitelmia ja on aika olla
    onnellinen. Minulla on lue tämä viesti ja jos voisin halua ehdottaa
    sinulle muutama mielenkiintoisia asioita tai vinkkejä. Ehkä
    voit voi kirjoittaa seuraavaksi artiklat tämän artikkelin. I halua lukea
    lisää asioita siitä!
    On asianmukaiset aika tehdä muutama suunnitelmia pitkällä aikavälillä ja on aika olla
    onnellinen. Minulla on lukenut Tässä julkaista ja jos en voi I halua neuvon et muutama huomiota herättäviä kysymyksiä
    tai neuvonta. Ehkä voit voisi kirjoittaa seuraava artikkelit liittyvät tämän artikkelin.
    I halua lukea vieläkin asiat Tietoa se!
    Olen on surfing verkossa suurempi kuin 3 tuntia tänään, mutta I koskaan ei suinkaan löysi tahansa kiehtovaa
    artikkeli kuin sinun. On kaunis arvoinen tarpeeksi riittävä minulle.

    Mielestäni, jos kaikki sivuston omistajat ja bloggaajat
    teki juuri oikea content kuin teit, internet on paljon hyötyä kuin koskaan ennen.
    Ahaa, sen nirso vuoropuhelu koskee Tämän Edellä tässä paikassa Tämän verkkosivu, olen lukenut
    kaikki, niin tällä hetkellä minulle myös kommentoimalla täällä.

    Olen varma, että tämä article on koskettanut kaikkia internetin ihmiset,
    sen todella todella mukavaa viesti rakentamaan uusia weblog.

    Vau, tämä Edellä on nirso, minun pikkusisko analysoi tällaisia
    asioita, näin Aion ilmoittaa hänet.
    kirjanmerkiksi!!, Rakastan Web-sivuston!
    Way cool! Jotkut äärimmäisen päteviä! Minä arvostan teitä kirjoitan tätä viesti ja loput verkkosivun hyvin hyvä.

    Hei, Uskon tämä on erinomainen kotisivuilta.

    Olen stumbledupon se ;) aion palata jälleen koska olen kirja-merkityt se.

    Raha ja vapaus on paras tapa muuttaa, voi sinun olla rikas ja edelleen Apua toiset.

    Woah! Olen todella loving malli / teemana verkkosivusto. Se on yksinkertainen, mutta
    tehokas. Monta kertaa se on kova saada, että "täydellinen tasapaino" käyttäjäystävällisyyttä ja ulkonäköä.
    Täytyy sanoa, olet tehnyt hienoa työtä tässä. Lisäksi, blogi kuormat Super
    nopea minua varten Safari. Maksamatta blogi!

    Nämä ovat todella valtavat ideoita Tietoa bloggaaminen. Olet koskettanut joitakin miellyttävä asiat
    täällä. Mitenkään pysyä wrinting.
    Kaikki rakastavat mitä te yleensä liian. Tällainen taitava työn ja raportointi!
    Jatkakaa Superb toimii kaverit Olen sisällytetty te kaverit blogroll.

    Moi! Joku minun Facebook ryhmä jakoi tämän sivustosta meille, niin tulin antaa sille näyttää.
    Olen ehdottomasti rakastava tietoja. Olen bookmarking ja se tweeting tämä minun seuraajia!
    Maksamatta blogin ja erinomainen suunnittelu.

    Kaikki rakastavat mitä te yleensä liian. Tällaiset taitava työn ja raportointi!
    Jatkakaa hyvä toimii guys Minulla sisälly te kaverit blogroll.

    Hei voisitko jakamiseen joka blogi-alustalla olet käyttäen?
    Olen näköinen aloittaa oman blogin lähitulevaisuudessa mutta minulla on kova aika valitsevat välillä
    BlogEngine / WordPress/B2evolution ja Drupal. Syy Kysyn koska layout näyttää eri sitten useimmat blogeja
    ja etsin jotain ainutlaatuinen. PS Anteeksi varten saada off-topic, mutta minun piti kysyä!

    Hei Voisitko saan tietää mikä hosting-yritys
    olet hyödyntämällä? Olen ladannut blogiisi 3 täysin eri
    internetselaimella ja täytyy sanoa tämän blogin lataa paljon nopeampi sitten suurin. Voitteko ehdottaa hyvä hosting tarjoajan rehellinen hinta?

    Kiitos, arvostan sitä!
    Kaikki rakastavat se kun yksilöt niskasta kiinni ja jakaa ajatuksia.

    Suuri verkkosivuilla, pysy siinä!
    Kiitos hyvä kirjailla. Se itse asiassa oli huvi huomioon se.
    Katsokaa eteni pitkälle lisätään miellyttävä teiltä!
    Muuten, kuinka voi me kommunikoida?
    Hei Halusin vain antaa sinulle nopean heads up. Text teidän sisältöön näyttävät pakoilu näytön IE.
    En ole varma, onko tämä muotoilut myöntämisen tai
    jotain tekemistä web-selain yhteensopivuutta mutta en ajattelin olisin lähettää kertoa.

    layout näyttää hyvältä vaikka! Toivottavasti saat kysymys
    ratkaistu pian. Kiitos
    T√§m√§ on aihe , joka on l√§hell√§ syd√§nt√§ni …

    Kippis! Tarkalleen missä ovat yhteystietosi vaikka?

    Se on hyvin helppoa selvittää mahdolliset viestiketju on net verrattuna oppikirjoja,
    koska löysin tämän article Tämän site.
    Onko blog on yhteyttä sivun? Minulla on ongelmia paikallistamiseen sitä,
    mutta haluaisin lähettää olet e-mail. Minulla on ideoita blogiisi saatat
    olla kiinnostunut kuulemaan. Joko niin, hyvä sivusto ja odotan näkeväni sen kasvaa ajan.
    Hei! Olen seuraavat teidän blog kohteelle kun jonkin aikaa nyt ja
    vihdoin rohkeutta mennä eteenpäin ja antaa sinulle huutaa pois
    Atascocita Tx! Halusin vain mainita pysyä fantastinen työtä!

    Terveisiä Los Angeles! Olen kyllästynyt töissä joten päätin tarkistaa teidän verkkosivusto minun iPhone aikana lounastauko.
    I nauttia tietoa et nykyinen täällä ei voi odottaa katsomaan kun pääsen kotiin. Olen järkyttynyt kuinka nopeasti
    blogiisi ladattu minun mobiili .. En edes käyttää WiFi, vain 3G ..
    Anyways, erittäin hyvä blog!
    Sen kuten sinä oppia Minun mielessä! Olet näytä ymmärtää
    paljon noin tästä, kuten sinulla kirjoitti kirja siinä tai jotain. Luulen että olet voi tehdä muutaman pc ja ajomatkan viesti koti
    hieman, kuitenkin muuta kuin, että tämä
    on loistava blog. erinomainen lukea. Minä varmasti takaisin.
    Kävin eri sivustoja mutta äänen ominaisuus audio kappaleita nykyisten tässä kotisivuilta on itse asiassa fabulous.

    Moi, luin blogisi ajoittain ja minä omistan samanlaisen ja olin juuri utelias jos saat paljon roskapostia kommenttia?
    Jos niin miten voit sen, kaikki plugin tai jotain voi suositella?
    Saan niin paljon viime aikoina se tekee minut hullu joten kaikki tuki on erittäin tervetullutta.

    Tervehdys! Erittäin hyödyllinen neuvoja tämän post! On pikku muutoksia , jotka tekevät merkittävimmät muutoksia.

    Kiitokset jakamisesta!
    olen vakavasti rakkautta blogiisi .. Erinomainen värit ja teeman. Oletko rakentaa
    näiltä sivuilta itsesi? Ole hyvä vastata takaisin, koska olen haluavat luoda omat henkilökohtaiset
    sivuston ja haluaa tietää missä olet saanut tämän tai mitä
    teeman on nimetty. Kiitokset!
    Hei! Tämä blogikirjoitus ei kirjoittaa paremman! Läpi Tässä article mieleeni edellinen kämppis!
    Hän jatkuvasti pidettävä saarnaaminen tästä. minä eteenpäin viestistä hänelle.
    Melko varmasti hän on erittäin hyvä lukea. Arvostan teitä jakamisesta!

    Incredible! Tämä blogi näyttää tarkalleen kuin minun vanha!
    Se on kokonaan erilainen subject mutta se
    on melko sama sivun ulkoasun ja suunnittelu.
    Maksamatta värivalikoima!
    On varmasti paljon oppia Tämän Uutta. Pidän todella kaikki pisteiden olet tehnyt.

    Olet tehnyt joitakin ihmisarvoisen kohtia siellä.
    I Katsoin web lisätietoja tietoa asiasta ja totesi useimmat ihmiset menee yhdessä teidän mielipiteenne tällä sivustolla.

    Moi En tarkistaa teidän blogit päivittäin. Sinun tarinankerronta tyyli
    on nokkela, pitää se!
    I vain ei katoa teidän sivusto ennen viittaa siihen, että olen oikeastaan rakasti tavallista tiedot yksittäisen tarjonnan oman Vierailijat?
    On menossa olla takaisin säännöllisesti to tutustu uudet viestit
    haluan kiittää teitä tästä fantastinen lukea! I ehdottomasti rakastanut välein hieman se.
    Minulla olet kirjanmerkiksi katsomaan uutta mit√§ post …

    Miten menee, halusi vain en En nauttinut Tässä article.

    Se oli innostava. Pidä lähettämistä!
    Hei Nautin käsittelyssä kaikki teidän viesti. I kuin halusi kirjoittaa pienen kommentin tukea teitä.

    I jatkuvasti vietin puoli tuntia lukea tämä weblog 's
    artikkelit koko ajan sekä cup kahvia.
    I joka kerta lähetetään tämän verkkosivusto post sivu all my yhteystiedot,
    siitä syystä, että jos haluat lukea sitä sitten minun linkit myös.

    Oma kehittäjä yrittää vakuuttaa minun siirtyä.
    Netto PHP. Olen aina pitänyt ajatusta koska kulut.
    Mutta hän tryiong kuitenkin. Olen käyttänyt WordPress on useita verkkosivustoja noin vuoden ja olen huolestunut vaihtamaan toiselle alustalle.
    Olen kuullut suuri asioita blogengine.net. Onko niin voin tuonti kaikki
    minun wordpress virkaa siihen? Kaikki apu olisi suuresti arvostaa!

    Hei! Olisin voinut vannoa Olen vieraili näiltä sivuilta ennen mutta sen jälkeen katsomalla jotkut artikkelit tajusin se
    on uutta minulle. Anyways Olen ehdottomasti onnellinen huomasin sen ja
    otan kirjanmerkit se ja tarkkailun takaisin säännöllisesti!

    Ihana article! Eli tyyppi info jotka on tarkoitus jaettava ympärillä internet.

    Shame on Google kohteelle ei paikannus Tämän sietää ylä!
    Tule tänne ja kuulla minun sivusto. Kiitos =)
    Heya Olen ensimmäistä kertaa täällä. I törmäsin tämän hallituksen ja pidän todella hyödyllinen ja se auttoi minua paljon. Toivon antaa
    jotain takaisin ja Apua toiset kuin sinä auttanut minut.

    Moi, Luulen Web-sivusto ehkä ottaa verkkoselaimen yhteensopivuus ongelmia.
    Aina tutustumaan Sivusto Safarissa, se näyttää
    hyvältä mutta jos aukko in IE, on joitakin päällekkäisiä asioita.
    en yksinkertaisesti Halusin antaa sinulle nopean heads up!

    Muuten, erinomaisia blogi!
    Henkilö välttämättä lainata käsi tehdä vakavasti
    virkaa olisin valtion . Eli ensin kerta kun suosimissa teidän sivuston sivulle ja tähän pisteeseen? I yllättynyt kanssa tutkimus teit tekevät tässä viesti uskomaton. Erinomainen tehtävä!

    Heya Olen on ensimmäistä aikaa täällä.

    I löytänyt tämän hallituksen enkä löytää Se
    todella avulias & se auttoi minua paljon. Toivottavasti olen toivoen antamaan tarjoamaan jotain uudestaan ja Tuen toiset
    kuten voit auttoi minut.
    Hi! Minä vain haluaisi antaa sinulle valtava peukkua oman erinomaisia tietoa sinulla tänne tähän tehtävään. Aion olla palaan blogiisi lisää pian.
    I aina kaiken aikaa käytetään lukea pala kirjallisesti lehtiin, mutta nyt olen käyttäjä
    verkkomarkkinointi ollen nyt olen käyttäen netin artikkelit, kiitos web.

    Sinun tapa kuvaavia kaikki Tässä article on itse asiassa miellyttävä, jokainen kyettävä
    vaivattomasti ymmärtää se , Kiitos paljon.
    Hi siellä, löysin teidän kotisivuilta Poiketen Google
    samaan aikaan kuin etsivät samanlainen subject, sinun sivusto tänne tuli, se näyttää olevan kuin hyvä.

    Olen kirjanmerkiksi se minun google kirjanmerkit.
    Hei siellä, vain muuttui varuillaan teidän blogi kautta Google, ja
    sijaitsevat että se todella informatiivinen. Olen menossa varoa Brysselissä.

    Aion kiitollinen kun edetä Tässä in tulevaisuuden. Lukuisat ihmiset ehkä hyötyneet ulos teidän kirjallisesti.
    Kippis!
    Olen utelias kuulemaan, mitä blogi järjestelmä olet käyttäen? Olen ottaa jotkut pienet
    turvallisuuteen ongelmia minun uusin sivustosta ja olisin haluavat löytää jotain turvallinen. Onko teillä ehdotuksia?

    Olen äärimmäisen todella vaikuttunut kirjoittamista sekä kanssa layout teidän blogi.

    Onko tämä maksettu teeman tai ette muokata itse? Anyway pysyä kiva laatu kirjallisesti,
    on harvinaista nähdä suuri blogi kuten tämä näinä päivinä.

    Olen todella innoittamana yhdessä kirjallisesti kykyjä ja kanssa layout
    teidän blogi. Onko tämä maksettu teema tai ette muokata se oman itsensä?
    Anyway majoittuvat up kiva korkealaatuinen kirjallisesti, se harvinainen nähdä suuri blogi kuten tämä tänään ..

    Hi, Siisti postitse. On ongelma yhdessä teidän sivusto in netti tutkimusmatkailija, voi testi tämän? IE kuitenkin on markkina päällikkö
    ja iso osa muut ihmiset tuottaa Miss teidän erinomaisia kirjallisesti
    takia tämän ongelman.
    Olen ole varma missä olet saada info, mutta loistava aihe.
    Olen tarvitsee viettää aikaa oppimiseen enemmän tai ymmärrystä enemmän.
    Kiitos ihana tiedot Etsin tätä info lähetystyöhön.
    Hei, luulen, että olen nähnyt olet käynyt minun weblog niin tulin "vastapalveluksen".
    Olen yrittää löytää asioita tehostaa minun verkkosivuilla!
    Oletan sen ok käyttää muutamia ideasi!!
    Hi, tunnen että i saha vierailitte weblog näin i tänne tuli to tuotto valitse?.
    olen yrittää löytää kysymyksiä to parantamiseksi minun site Oletan sen ok käyttää joidenkin teidän ideoita!!

    Hei siellä, vain tuli varuillaan blogiisi Googlen kautta, ja totesi, että se todella informatiivinen.
    Olen menossa varoa Brysselissä. Aion kiitollinen jos jatkat tätä
    tulevaisuudessa. Lukuisat ihmistä on hyötynyt kirjoittamista.

    Kippis!
    Olen enää tietyt jolloin olet saada info, mutta loistava aihe.
    I on viettää jonkin aikaa selvittämällä paljon tai mietitään enemmän. Kiitos varten erinomaisia tiedot Olin hakevat tätä info lähetystyöhön.
    Hi minun kaverille! I halua sanoa, että tämä post on mahtava,
    mukava kirjoitettu ja sisällyttää melkein kaikki merkittäviä tietoja .
    Olisin kuin nähdä extra virkaa näin.
    Hi! Rakastan kirjoituksesi hyvin paljon! osuus me kommunikoida extra Tietoa teidän article AOL?
    I vaativat asiantuntija tällä alue ratkaista minun ongelmani.

    Voi olla se sinua! Kun tarkastellaan eteenpäin katsomaan sinulle.

    Olen todella rakastava teema / suunnittelu teidän weblog.
    Oletteko koskaan joutunut mitään internet-selain yhteensopivuus
    kysymyksiä? pari blogissani Vierailijat ovat valittaneet minun verkkosivuilla
    Ei toimivat oikein Explorerissa, mutta näyttää hyvältä in Firefox.
    Onko teillä neuvonta avulla korjata tämän ongelma?

    Hyvä info. Lucky minulle Löysin äskettäin sivustosi vahingossa (stumbleupon).
    Minulla on tallentanut sen myöhempää!
    Se on ihana että saat ideoita tältä viesti sekä meidän vuoropuhelu
    valmistettu tässä paikassa.
    Jos haluat ja parantamiseksi kasvavat teidän tietotaitoa
    vain jatkuvasti käydä tätä sivun ja päivitetään Uusimmat uutispäivityksen lähetetty tänne.

    Mitä Going down Olen uusi tässä, olen luiskahtanut tämän Olen löysi Se ehdottomasti avulias ja se on auttoi
    minua kuormia. ja edistää & tuki muut asiakkaat kuten sen auttoi minut.
    Hyvä työtä.
    Wow, että mitä olin etsien varten, mitä Tietoa!
    nykyisten täällä tähän weblog, kiitos admin Tämän site.

    Jos toiveen ja saada paljon tämän Edellä niin sinun täytyy hakea tällaiset strategiat sinun wonia verkkosivu.

    Se on merkillistä article varten kaikki web katsojia;
    ne kestää etuuden siitä olen varma.
    Olen lukenut jotkut hyvä tavaraa täällä. Varmasti arvo
    kirjanmerkillä uudelleenarvioimista. I ihme kuinka paljon vaivaa asetat ja tekevät yksi näistä suurta informatiivinen sivuston.
    Eli suuri tip varsinkin kuin uusia blogosphere. Lyhyt mutta eritt√§in t√§sm√§llisi√§ info …

    Kiitos jakaa tämän yhden. Täytyy lukea article!

    Olen tutkineet varten hieman mistään laadukkaan artikkeleita tai weblog viestejä tässä
    tällaista talon. Exploring Yahoon I luiskahtanut
    tämän kotisivuilta. Opiskelu Tässä info Joten Olen iloinen ja
    näytä että olen hyvin hyvä outo fiilis löysi tarkalleen mitä tarvitsin. I niin paljon varmasti tekee
    varmasti ja don? T piittaamattomuutta Tässä sivuston ja tarjoaa se
    silmäyksellä säännöllisesti.
    Luettuani tämän uskoin se oli pikemminkin valaiseva.

  167. diver watch - September 8, 2014

    I blog often and I seriously appreciate your information. This article has truly peaked my interest.
    I'm going to take a note of your site and keep checking for new details about once a week.
    I opted in for your RSS feed too.

Leave a Reply