Eräänä päivänä 3 vuotta sitten The Codest-tiimi valmisteli hienoa Cody-peliä Ruby-ohjelmoijille. Tämänpäiväisessä artikkelissa haluan kuvata, miltä tämän projektin työstäminen näytti ja ennen kaikkea näyttää teille projektin koodin, joka on tästä lähtien julkisesti saatavilla githubissamme.
Pelisuunnittelu
Kun suunnittelimme peliä, päätavoitteemme oli valmistella hauskaa viihdettä ohjelmoijille sekä tehdä jotain mielenkiintoista osana työtämme yrityksessämme. Tähän mennessä meillä ei ollut minkäänlaista osaamista pelien luomisessa, minkä vuoksi se oli meille merkittävä haaste. Ensiksi keskityimme siihen, mitä tämä peli oikeastaan oli. Alkuperäisen suunnitelman keksimisen jälkeen tartuimme toimeen.
Osana pelin työstämistä päätimme järjestää hackathonin ja jakaantua ryhmiin, jotka suorittavat tiettyjä tehtäviä. Tällaisella 8 tunnin työnjaolla pystyimme toteuttamaan vastustajien ulkonäön pelissä, koko ulkoasun sekä koko järjestelmän tehtävien ja API:iden perustan. Seuraavassa vaiheessa kokoonnuimme 4 tunnin kokouksiin kerran kuukaudessa, minkä ansiosta saimme pelin valmiiksi kolmessa kokouksessa.
Täytäntöönpano
Koska olemme erikoistuneet RubyOnRails-teknologiaan, valitsimme sen johtavaksi teknologiaksi. Pelin ei kuitenkaan ollut tarkoitus olla tekstimuotoinen, ja siksi lähestymistapa siihen heijastui SPA-tyyppiseen sovellukseen. Työskentelimme osana tehtävää tunnetun putkiston avulla railsista (vuonna 2016 ei periaatteessa ollut mitään parempaa) ja koko javascript perustuu omaan koodi TypeScript:n avulla. Hakemuksessa oli tavanomainen vastuunjako: Rails hyödykkeenä ja API-lähteenä, javascript ja siihen liittyvät vuorovaikutuksessa käyttäjän kanssa. Tässä kuitenkin toimittiin hybridinä ja osa näkymistä renderöitiin yksinkertaisesti Railsista ja osa muista - JS:stä.
Kirjoituskäsikirjoitus
Se oli ensimmäinen kokeilumme tällä alalla. Nämä olivat aikoja, jolloin ihmiset uskoivat CoffeScriptin menestykseen. TypeScript:n käyttäminen vaati typescript-rails-helmen käyttöönottoa. Valitettavasti tämä ei ollut lopullinen, sillä typescript, joka on staattisesti tyypitetty kieli, vaati tätä myös railsin oletusarvoisesti liitetyiltä kirjastoista.
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/jquery.d.ts (erityisesti käytettäessä sulautettua omaisuudenhallintajärjestelmää kiskojen kanssa).
Cody pelinä vaati paljon dynamiikkaa selaimen puolella, samoin kuin DOM:n puun muokkaamista. TypeScript:n käyttäminen vaniljajavascriptin sijasta oli valtava harppaus koodin laadussa, ja luokkien ja kapseloinnin läsnäolo oli meille hyvin houkuttelevaa.
API ja SPA
Vuonna 2019 SPA-sovelluksia hallitaan käyttämällä upeaa React- tai Vue kirjastot. Vuonna 2015 teimme sen kuitenkin eri tavalla. Aiemmin mainittu typescript auttoi toteutuksessa, kun taas jQuery perui kaiken xml-http-pyyntöön liittyvän työn. Nyt voimme käyttää fetchiä, kun taas tuolloin `$ .ajax` oli kaikki, mitä työhön tarvittiin. Tutustu asiakasapiimme!
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/services/api_client.js.ts
Jos se oli api, teidän piti ratkaista todennusongelma jotenkin, eikö niin? Aivan oikein. Mutta siinä tapauksessa menimme (voiko tänne kirjoittaa - käytimme bändiä?!) bändin perässä ja rails-istunnossa loimme cookie_key:n ja sen jälkeen tallensimme sen tietokantaan. Näin ollen tiesimme, että kaikki oli enemmän kuin hyvin.
https://github.com/codesthq/cody_the_game/search?q=cookie_key&unscoped_q=cookie_key
Pelin tila tallennettiin tietokantaan, ja tieto siitä, kuinka monella käyttäjällä oli pisteitä, tuli tietokannasta (onko se sama tietokanta? Voimmeko vain vaihtaa sen pronominiin?). ACID on aina kätevä, kun järjestelmän puolella ei ole välimuistia;)
Kylpylän tapauksessa se on paras ilman sivun uudelleenlatausta. Olemme ratkaisseet sen klassisesti ja html-ankkuri oli paras ratkaisu ilman turhien riippuvuuksien laajentamista. Koska kuka käyttäisi turbolinksia?
SnapSVG
Jos suunnittelemme pelin, se on julkaistava vain upeilla grafiikoilla ja animaatioilla. Silloin vietimme monta tuntia miettien, miten voisimme täyttää nämä vaatimukset sovelluksessamme. Toisaalta canvas voi tehdä ihmeitä, toisaalta puhtaassa html:ssä on paljon helpompi päästä kiinni ja kaikki tietävät sen. Parhaan ratkaisun vaivalloisen etsimisen jälkeen tajusimme, että näiden kahden ratkaisun yhdistelmä on svg. Sen avulla voit helposti esittää grafiikkaa vektorimuotoisena, se on kirjoitettu merkintäkielellä ja mikä tärkeintä, sitä voi muokata lennossa. Tärkeää on, että svg-tiedostoille on olemassa kirjasto, joka toimii samalla tavalla kuin jQuery ja mahdollistaa kuvaan kohdistuvat operaatiot yhtenäisellä tavalla. Tämä on: http://snapsvg.io, meillä on erittäin mukavia muistoja tuosta ratkaisun käytöstä.
Esimerkin snap.svg:n käytöstä löydät alta:
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/intro.js.ts
Itse haml-tiedosto, jossa on graafinen luuranko:
https://github.com/codesthq/cody_the_game/blob/master/app/views/game/show.html.haml
Kuten näet, se on melkein kuin normaali DOM-puu ja tavallinen rails-sovellus!
TrustedSandbox
No, lopulta meillä oli API, Graphics, SPA. Mutta entä käyttäjien lähettämien ratkaisujen toteuttaminen?
Ensimmäisenä tulee mieleen eval-menetelmä, mutta emme ole hulluja;) Vuonna 2016 telakka oli nousussa, joten se tuntui luonnolliselta valinnalta. Kontit itsessään eivät taanneet täydellistä eristystä ja suojausta, minkä vuoksi käytimme Rubyssä valmista ratkaisua nimeltä https://github.com/vaharoni/trusted-sandbox. Sen avulla voitiin suojata koodi paremmin ennen hiekkalaatikosta poistumista ja määrittää käyttöjärjestelmävaatimukset standardoidusti. Oli erittäin tärkeää rajoittaa asianmukaisesti koodin suoritusaikaa, toimintaan tarvittavaa muistia ja suorittimen syklejä. Kokoonpanomme on saatavilla jäljempänä.
https://github.com/codesthq/cody_the_game/blob/master/config/trusted_sandbox.yml.example
Sama luotettu hiekkalaatikko ei tietenkään taannut mitään, minkä vuoksi kehitimme erityisen verkkosivuston koodin ajamista varten.
https://github.com/codesthq/cody_the_game/blob/master/app/services/task_runner/base_task.rb
Jokaisella tehtävällä oli oma testitapauksensa, jonka avulla voitiin tarkistaa toteutetun ratkaisun oikeellisuus. Tämä tehtiin lisäämällä käyttäjäkoodi testitapaukseen niin, että kaikki suoritettiin eristyksissä.
https://github.com/codesthq/cody_the_game/blob/master/app/challenges/challenge/case.rb
Tämä toiminta maksoi tietysti melko paljon aikaa, ja vastausten keräämisen aikana meillä ei ollut varaa käyttää hiekkalaatikkoa, joten tallennimme koodin vain tietokantaan, loimme lähetyksen ja pyysimme sitten pitkää yhdistämistä käyttäen päätepistettä saamaan koodin tilan. Näin pystyimme vapauttamaan sovelluspalvelimen ja tarkistamaan tiedot asianmukaisesti. Meidän oli tietenkin myös suojauduttava "skriptin kaatumiselta", ja siksi rajoitimme palvelinkyselyjen määrää ttl-muuttujan avulla, mikä näkyy alla.
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/level_controller.js.ts#L92
Yhteenveto kilpailusta
Syyskuuhun 2011 asti pelitilastot olivat seuraavat:
- istuntojen lukumäärä: 1945 - lähetetyt tehtävät: 4476 - lähettänyt oikeita vastauksia: 1624 - päätti pelin: 31
Kuten näet, suurimmat portaat alkoivat tehtävässä # 2, koska se ei ollut enää tavallinen hello world -esimerkki.
Lue myös:
Nopea sukellus Ruby 2.6:een. Mitä uutta?
Dokumentaation kirjoittaminen on tullut helpoksi VuePressin ansiosta.
Vue.js:n perusteet. Miten aloittaa tämän kehyksen kanssa?