Oli normaali perjantai-iltapäivä, kun Joni ja Oskari pohtivat, miten voisi tietää, missä kaikkialla Gofore Crew oli kokoontunut sillä hetkellä afterworkille. Vakiopubeja on goforelaisille kertynyt useita toimistojemme läheisyyteen, joten mahdollisia vaihtoehtoja on liian monta käydäkseen kokeilemassa jokaisen ovella. Ohjelmistosuunnittelijoina Joni ja Oskari havaitsivat heti ratkaistavan ongelman. Täytyy olla helpompi tapa kuin kysyä Slackissa tai kiertää toimisto läpi kysellen kulloisenkin afterwork-paikan sijaintia. Näin syntyi idea Goforen maskotin Sorsa Sepon valjastamisesta Kalja S(i)epoksi, joka kertoo Slackiin automaattisesti afterworkien sijainneista.
KaljaSeppo seuraa goforelaisten suosiossa olevan Untappd-sovelluksen avulla, mihin Sepon kaverit, eli muut goforelaiset, ovat kokoontuneet oluen pariin. Untappd-käyttäjä antaa juoman sijainnin ja arvosanan Untappd-kirjaukseen. Koska Seppo on kaikkien goforelaisten kaveri Untappdissa, Seppo voi nähdä omaa Untappd-feediään seuraamalla missä sijainnissa on useampia yhdessä istumassa. Tämän jälkeen Seppo ilmoittaa afterworkista muille goforelaisille Slackiin. Seuraamista varten tarvitaan tietenkin integraatio Untappdin ja Slackin välille!
Afterwork-alert-sovellus
Sovellus on tässä vaiheessa käytännössä integraatio kahden sovelluksen, Untappdin ja Slackin, välille. Untappdin kautta seurataan sovellukseen määritellyn käyttäjän (SorsaSeppo) activity feediä ja jäsennetään tästä feedistä samassa paikassa (venue) olevat kirjaukset eli checkinit, jotka ovat ajallisesti riittävän lähellä toisiaan. Jos kaksi tai useampi checkiniä eri käyttäjiltä on samassa paikassa samoihin aikoihin, ilmoitetaan Slack-kanavalle meneillään olevasta afterworkista KaljaSeppo-botin avulla. Slack-kanavia voi olla useampia, joille ilmoitetaan eri kaupungeissa olevista afterworkeista. Kanavat määritellään afterwork-alertin asetustiedostoon avain-arvo-pareina. Tällä hetkellä Goforen käynnissä olevaan versioon on määritelty, että Tampereella sijaitsevista afterworkeista ilmoitetaan Goforen Slackiin #afterwork-tampere-kanavalle, Helsingin afterworkeista #afterwork-helsinki-kanavalle ja Jyväskylän aftereista #afterwork-jyvaskyla-kanavalle. Muiden kaupunkien afterworkeista ei ilmoiteta tällä hetkellä mihinkään.
Tämän ajoittain tehtävän jäsennyksen lisäksi sovellukseen on tässä vaiheessa tehty myös Untappd-kaveripyyntö-ominaisuus. KaljaSeppo ei itse hyväksy kaveripyyntöjä suoraan, vaan luo niitä. Komentamalla Slackissa KaljaSeppoa se lähettää Untappdissa kaveripyynnön halutulle Untappd-käyttäjälle. Tällä tavalla voidaan varmentaa, että kyseinen Untappd-käyttäjä on goforelainen, tai ainakin kaveripyyntö on generoitu goforelaisen komentamana.
Sovellus pyrittiin kehittämään alusta nopeasti siihen pisteeseen, että sitä voidaan käyttää. Sovellus tuli lähes valmiiksi jo noin viikon satunnaisten ilta- ja viikonloppukoodailujen puitteissa ja tuotantokäyttöön se saatiin kolmessa viikossa. Ensimmäisenä arkipäivänä käyttöönoton jälkeen Sepolle kertyi jo 15 goforelaista kaveriksi, eli kysyntää sovellukselle selvästi oli.
Tekninen rakenne ja haasteet
Emme tässä kirjoituksessa tutustu tarkemmin koodiin, mutta itsenäisesti koodiin voi tutustua Githubissa.
Teknisesti sovellus koostuu kahdesta toisistaan irrallisesta kokonaisuudesta: ajastetusta feedin noudosta ja jäsennyksestä notifikaation luomiseksi sekä kaveripyyntöjen generoinnista. Slackin kautta saatavia komentoja varten sovellus yhdistää WebSocketin avulla Slackiin ja näkyy Slackissa bottina halutuilla kanavilla. WebSocketin kautta seurataan sovellukselle tulevia komentoja luoda uusi kaveripyyntö, jolloin sovellus generoi Untappdin APIn läpi kaveripyynnön halutulle käyttäjälle.
Afterwork-sovellus on toteutettu JavaScriptillä hyödyntäen Untappd-sovelluksen APIa ja Slack-viestisovelluksen APIn tarjoamaa WebSocket-rajapintaa. Toteutuksessa hyödynnetään Lodash-, Slack Node SDK- ja node-untappd-kirjastoja. Afterwork-alert on ajossa tällä hetkellä Gofore Crew:n AWS-tilillä.
Feedin jäsennys
Mahdollisesti mielenkiintoisin algoritminen haaste projektin puitteissa oli muokata Untappdin APIsta saatava feed joukoiksi afterworkeilla olevia ryhmiä. Teknisesti hyödynnettiin Lodashin erilaisia putkitettuja funktioita, joilla muokattiin alkuperäistä Untappdista saatua feediä pala palalta sopivammaksi. Lopullisessa toteutuksessa päädyttiin ensin varmistamaan kirjausten järjestys oikeaksi sortBy() -funktion avulla. Tämä oli välttämätöntä, koska myöhemmissä vaiheissa tukeudutaan kirjausten oikeaan järjestykseen. Järjestämisen jälkeen poistettiin liian vanhat kirjaukset, kirjaukset ilman sijaintia ja jo aiempiin afterworkeihin kuuluneet kirjaukset. Seuraavaksi tehtiin yksi oleellisimmista asioista, eli ryhmiteltiin kirjaukset sijaintien perusteella. Tämän jälkeen data oli muodoltaan lista listoja, joissa oli kirjauksia samoista paikoista.
Seuraavassa vaiheessa data käsiteltiin sisäkkäin map()- ja reduce()-funktioilla. Map() erotteli jokaisen sijainnin listat erilleen ja reduce():lla näitä listoja pienennettiin siten, että tunnistettiin, ovatko peräkkäiset käsiteltävät kirjaukset yhdessä afterworkilla. Muussa tapauksessa tutkitaan seuraava pari siten, että lopuksi jäljelle jäi vain sääntöjen puitteissa afterworkilla olevat kirjaukset. Tämä tapa käsitellä afterworkit kuitenkin tunnistaa vain ensimmäisen afterwork-joukon jokaisesta sijainnista, ei samasta sijainnista useampia eri joukkoja. Kuitenkaan käytännössä tälläiselle ei pitäisi tulla tarvetta, koska tarkastelu tehdään riittävän usein, jolloin samassa paikassa on joko yksi joukko tai ei joukkoja ollenkaan. Map()- ja reduce()-funktioiden tekemät datan muovaukset olisi teknisesti voinut rakentaa pelkästään reduce()-funktion sisälle, mutta koodin rakenteen selkeyden vuoksi ne säilytettiin erillään. Viimeinen vaihe jäsennyksessä oli tunnistaa afterworkjoukot, joissa on kaksi tai useampia kirjauksia. Minimiafterworkin kooksi määriteltiin siis kaksi kirjausta.
Jäsennysvaihetta muodostettiin ja uudelleenkirjoitettiin osittain useamman kerran, ja ongelmia tuli muun muassa aikaa käsittelevän Moment.js-kirjaston ja UTC-aikojen kanssa. Näitä korjattiin vielä ensimmäisen tuotantoonviennin jälkeen.
Varhaisilta käyttäjiltä on tullut hyviä ideoita, jotka muokkaavat jäsennysalgoritmia tulevaisuudessa vielä paremmin vastaamaan todellista afterworkin määritelmää. Lisäksi palautetta on tullut varsin yksinkertaisesta notifikaation formaatista, joka voisi olla parempi muun muassa nimien listaamisen suhteen.
Kaveripyyntö Slackiin
Kaveripyynnön tunnistaminen Slackista seuraamalla Webhookin yli viestejä botin kanavilta oli pääosin suoraviivaista. Botti kutsutaan halutuille kanaville, ja se seuraa niillä viestejä. Jos viestin ensimmäinen sana on botin nimi, oletetaan tämän olevan kaveripyyntö. Viestin toisen sanan oletetaan olevan Untappd-käyttäjän käyttäjätunnus, eli tunnus jolle tehdään kaveripyyntö. Tämä kaveripyyntö lähetetään sen jälkeen Untappdin APIn kautta, jolloin käyttäjä voi hyväksyä sen.
Eräässä vaiheessa kehitystä botti tunnisti virheellisesti jokaisen slack-viestin olevan kaveripyyntö ja lähetti useita pyyntöjä Untappdiin. Tässä vaiheessa lukijalta voitaisiin kysyä, mikä on paras tapa Untappdin selain- tai mobiilikäyttöliittymän kautta löytää lista kaveripyynnöistä, joita itse on tehnyt? No ei mitenkään, vaan pitää mennä kaveripyynnön kohteena olevan käyttäjän sivulle, havaita sieltä teksti ”Friend request pending” ja perua kaveripyyntö. Onneksi Untappdin APIn kautta saa listan lähetetyistä kaveripyynnöistä.
Todellisen käytön aikana kehityskohteeksi on havaittu palaute käyttäjälle Slackiin onnistuneesta kaveripyynnöstä. Lisäksi botin viestiin voisi liittää linkin suoraan kaveripyynnön kohteen Untappd-sivulle.
Afterwork-alert tulevaisuudessa
Tällä hetkellä on etsinnässä Gofore Crew:lle jokin viinien kirjaussovellus, joka mahdollisesti keräisi Untappdin tapaisen suosion ja sisältäisi myös APIn, jota voisi hyödyntää. Untappd hakee baarien sijainnit Foursquare-palvelusta, jota voi käyttää myös yksinään oman sijaintinsa kirjaamiseen muiden käyttäjien nähtäville. Tämän palvelun tukemista suoraan on myös harkittu.
Kuitenkin tärkeimpänä muutoksena on tulossa Amazon Web Services Lambdan hyödyntäminen ystävien lisäämisessä ja ajastetun feedin käsittelyn toteutuksessa. Tällöin on tarkoituksena kutsua AWS Lambdaa, kun Slackin Outgoing Webhook poimii kaveripyynnön Sepolle kanavalta. Eli korvataan Slackin seuraaminen Webhookin avulla siten, että Slack itse seuraa viestejä ja lähettää tarvittaessa HTTP POST -viestin AWS Lambdalle, jolla ajetaan kaveripyynnön luonti Untappdin APIn kautta. Toinen merkittävä muutos on hyödyntää Amazon Web Servicen Cloud Watchia ajastetun Lambdan ajamiseen, jolla tarkkaillaan KaljaSepon activity feediä Untappdissa.
Tekemättä on vielä myös kattava testaus, joka ei ole ollut kovin korkeana prioriteettina tälläisen vapaa-ajan miniprojektin puitteissa. Kuitenkin voisi olla opettavaista tutustua esimerkiksi johonkin itselle uuteen CI-palvelimeen ja toteuttaa hyvä julkaisuputki sen kautta. Koodissa on tällä hetkellä myös jonkin verran asioita, jotka voisivat olla erillisessä konfiguraatiotiedostossa. Esimerkkinä vaikka afterworknotifikaation formaatti ja minimimäärä kirjauksia, jotka lasketaan yhdessä afterworkiksi.
Untappdin activity feedin jäsennysalgoritmi tulee luultavasti tulevaisuudessa myös muuttumaan huomattavasti. Käyttäjiltä on tullut todella paljon hyviä ideoita, joiden avulla jäsennys tulee jalostumaan huomattavasti lähitulevaisuudessa. Myös erilaisia data-analytiikkaan liittyviä ideoita on vielä täysin kehittämättä. KaljaSeppo voisi vaikka analysoida tavallisia GoforeCrew:n afterworkreittejä pitkin kaupunkia, tai vaikka ehdottaa hyviä reittejä historian perusteella. Myös moralisointia arkipäivän illanvieton venymisestä mahdollisena krapula-aamuna on pohdittu.
Vapaa-ajan projektit ja työt
Vaikka afterwork-alert onkin vain harrastusprojekti, jota Joni ja Oskari työstävät pääosin vapaa-ajallaan, Gofore tukee tätäkin toimintaa monin tavoin. Gofore tarjoaa tarvittavan ajoympäristön Gofore-Crew:n AWS-tilin kautta. Lisäksi kehtaamisen puitteissa Joni ja Oskari voivat kirjata oman osaamisen kehittämiseen sen osuuden kulutetusta ajasta, jonka arvioivat kuluneen uuden oppimiseen projektin parissa. Tämän bloginkin tekemiseen kannustetaan vaikuttamisbonuksella. Vaikuttamisbonusta voi saada Goforella määrätynlaisista Open Source -projekteista, blogien kirjoittamisesta ja medianäkyvyydestä goforelaisena valtakunnallisissa medioissa. Osa harrasteprojekteista on suoraan kohdistettu goforelaisten käyttöön, kuten tämäkin afterwork-alert. Esimerkkinä mainittakoon jo vuosia käytössä ollut kikkerikilke eli pöytäjalkapallotulosten kirjaukseen luotu järjestelmä. Kilke on myöhemmin taipunut muihinkin lajeihin, kuten pingikseen. Tästä Teemu kirjoitti syksyllä kaksiosaisessa blogisarjassa (Kikkeritulosten kirjausjärjestelmä ja Kosketuskäyttöinen kirjauslaite kikkeritulosten kirjausjärjestelmälle).
Kuten näistä esimerkeistä tulee ilmi, Goforella arvostetaan suunnattomasti harrastuneisuutta ja oma-aloitteista kehittymistä itselleen mielenkiintoisten asioiden kautta ja niiden parissa. Työajasta ohjeistetaan käyttämään tavalla tai toisella 6 % osaamisen kehittämiseen. Jokainen goforelainen saa itse kehdata ja arvioida oma-aloitteisesti, mikä on sopivin tapa kehittää itseään. Yksin oppimisen pariin ei kuitenkaan jätetä, jos niin ei halua. Gofore tarjoaa työntekijöilleen kehittymispolkuja, jolloin oppimisessa ja sen suunnissa pystyy tukeutumaan myös työkavereihin. Gofore ja asiakkaat menestyvät yhdessä suurelta osin siitä syystä, että goforelaiset tekevät asioita ammattitaidolla ja intohimolla. Tätä sisäistä paloa ruokitaan osaltaan tällä yhteisellä kulttuurilla, joka kannustaa jatkuvaan kehittymiseen, jolloin vältetään paikoilleen pysähtyminen. Arkista innostusta pystyy myös tukemaan ja kasvattamaan juuri tällaisilla kevyillä projekteilla, kuten afterwork-alert. Usein näistä asioista jää vielä Goforen yhteisölle jotain. Tällä kerralla toivottavasti goforelaiset pääsevät nauttimaan jokaviikkoisista, ellei jopa jokapäiväisistä, Sepon tarjoamista automaattisista afterwork-ilmoituksista.
KaljaS(i)eppo ja teksti: Joni Laurila ja Oskari Ruutiainen