Ühel päeval 3 aastat tagasi valmistasime The Codest meeskonnas ette suure Cody mängu Ruby programmeerijatele. Tänases artiklis soovin kirjeldada, kuidas töö selle projekti kallal välja nägi ja ennekõike näidata teile projekti koodi, mis on nüüdsest alates avalikult kättesaadav meie githubis.
Mängu disain
Mängu kavandamisel oli meie peamine eesmärk valmistada lõbus meelelahutus programmeerijatele ning teha midagi huvitavat osana meie ettevõtte tööst. Seni polnud meil mängude loomisel pädevust, mistõttu see tabas meid märkimisväärse väljakutse. Esmalt keskendusime sellele, mis see mäng tegelikult on. Pärast esialgse plaani välja töötamist astusime teele.
Mängu kallal tehtava töö raames otsustasime korraldada häkatonid ja jaguneda rühmadesse, kes täidavad konkreetseid ülesandeid. Sellise 8-tunnise tööjaotusega suutsime realiseerida vastaste välimuse mängus, kogu kujunduse ning kogu süsteemi nii ülesannete kui ka APIde aluse. Järgmises etapis kogunesime kord kuus 4-tunnistele koosolekutele, tänu millele suutsime mängu valmis saada 3 koosolekuga.
Rakendamine
Kuna me oleme spetsialiseerunud RubyOnRailsile, siis valisime selle tehnoloogia juhtiva tehnoloogia. Siiski ei olnud mäng mõeldud tekstipõhiseks ja seetõttu kajastus lähenemine sellele SPA-tüüpi rakenduses. Ülesande raames töötasime railsist tuntud varade torujuhtme kallal (2016. aastal ei olnud põhimõtteliselt midagi paremat) ja kogu javascript mis põhineb meie patenteeritud kood TypeScript abil. Taotluses oli standardne vastutuse jagunemine: Rails kui vara ja API allikas, javascript ja sellega seotud kui suhtlemine kasutajaga. Siin aga toimis see hübriidina ja mõned vaated renderdati lihtsalt railsist, mõned teised aga - JS-st.
Tüüptekst
See oli meie esimene eksperiment selles valdkonnas. Need olid ajad, mil inimesed uskusid CoffeScripti edusse. TypeScript kasutamine nõudis typescript-rails pärli kasutuselevõttu. Kahjuks ei olnud see lõplik, sest typescript, olles staatiliselt tüpiseeritud keel, nõudis seda ka vaikimisi rails'ile lisatud raamatukogudest.
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/jquery.d.ts (eriti kui kasutate varade haldamise süsteemi koos rööbastega).
Cody kui mäng nõudis palju dünaamikat brauseri poolel, samuti DOMi puu muutmist. TypeScript kasutamine vanilla javascript'i asemel oli suur hüpe koodi kvaliteedis, just klasside ja kapseldamise olemasolu oli meie jaoks väga ahvatlev.
API ja SPA
2019. aastal hallatakse SPA-rakendusi, kasutades suurepärast React või Vue raamatukogud. Kuid 2015. aastal tegime seda teistmoodi. Eelnevalt mainitud typescript oli abiks mängu rakendamisel, samas kui jQuery võttis ära kogu xml http päringuga seotud töö. Nüüd saame kasutada fetch'i, samas kui tol ajal oli selleks tööks vaja vaid `$ .ajax`. Vaadake meie kliendi api!
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/services/api_client.js.ts
Kui see oli api, siis pidite ju kuidagi autentimisprobleemi lahendama, eks ole? Noh, nii ongi. Aga sel juhul läksime pärast (kas siin on võimalik kirjutada - kasutasime bändi?!) bändi ja rails'i sessioonis lõime cookie_key ja pärast salvestasime selle andmebaasi. Seega teadsime, et kõik on enam kui korras.
https://github.com/codesthq/cody_the_game/search?q=cookie_key&unscoped_q=cookie_key
Mängu staatus oli salvestatud andmebaasi ja teave selle kohta, kui palju kasutajatel oli punkte, tuli andmebaasist (kas see on seesama andmebaas? Kas me saame seda lihtsalt pronoomeniga muuta?). ACID tuleb alati kasuks, kui süsteemi poolel ei ole vahemälu;)
Spa puhul on see parim ilma lehekülge uuesti laadimata. Oleme selle lahendanud klassikaliselt ja html-anker oli parim lahendus ilma ebavajalike sõltuvuste laiendamiseta. Sest kes kasutaks turbolinke?
SnapSVG
Kui me kujundame mängu, tuleb see välja anda ainult suure graafika ja animatsioonidega. Toona veetsime palju tunde, et mõelda, kuidas neid nõudeid oma rakenduses täita. Ühelt poolt suudab canvas imet teha, teiselt poolt on puhtas html-is palju lihtsam järele jõuda ja kõik teavad seda. Pärast vaevarikkaima lahenduse otsimist jõudsime järeldusele, et nende kahe lahenduse kombinatsioon on svg. See võimaldab hõlpsasti esitada graafikat vektorina, see on kirjutatud märgendikeeles ja mis kõige tähtsam, seda saab muuta jooksvalt. Oluline on see, et svg-failide jaoks on olemas raamatukogu, mis töötab sarnaselt jQuery'ga ja võimaldab pildiga tehtavaid toiminguid ühtselt. See on: http://snapsvg.io, meil on väga toredad mälestused selle konkreetse lahenduse kasutamisest.
Näite, kuidas me kasutasime snap.svg, leiad allpool:
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/intro.js.ts
Haml-fail ise koos graafilise skeletiga:
https://github.com/codesthq/cody_the_game/blob/master/app/views/game/show.html.haml
Nagu näete, on see peaaegu nagu tavaline DOM-puu ja tavaline rails-rakendus!
TrustedSandbox
Noh, lõpuks oli meil API, graafika, SPA. Aga kuidas on kasutajate poolt saadetud lahenduste rakendamine?
Esimene asi, mis pähe tuleb, on eval meetod, aga me ei ole hullud;) 2016. aastal oli dokker tõusuteel, nii et see tundus loomulik valik. Konteinerid ise ei taganud täielikku isolatsiooni ja kaitset, mistõttu kasutasime Ruby's valmis lahendust nimega https://github.com/vaharoni/trusted-sandbox. See võimaldas koodi enne liivakastist väljumist paremini kaitsta ja standardiseeritud viisil seadistada operatsioonisüsteemi nõudeid. Väga oluline oli korralikult piirata koodi täitmise aega, tööks vajalikku mälu ja protsessoritsükleid. Meie konfiguratsioon on kättesaadav allpool
https://github.com/codesthq/cody_the_game/blob/master/config/trusted_sandbox.yml.example
Loomulikult ei taganud sama usaldusväärne liivakast midagi, mistõttu tulime välja spetsiaalse veebilehega, et koodi käivitada.
https://github.com/codesthq/cody_the_game/blob/master/app/services/task_runner/base_task.rb
Igal ülesandel oli oma testjuhtum, mis võimaldas meil kontrollida rakendatud lahenduse korrektsust. Seda tehti kasutaja koodi süstimise teel testjuhtumi sisse, nii et kõik käis isoleeritult.
https://github.com/codesthq/cody_the_game/blob/master/app/challenges/challenge/case.rb
Loomulikult maksis see tegevus üsna palju aega ja vastuste kogumise ajal ei saanud me endale lubada liivakasti käivitamist, seega salvestasime koodi ainult andmebaasi, lõime esitamise ja seejärel, kasutades pikka koondamist, küsisime lõpp-punkti, et saada koodi staatus. See võimaldas meil rakendusserverit vabastada ja andmeid asjakohaselt kontrollida. Loomulikult pidime end kaitsma ka "skripti kokkuvarisemise" eest ja seetõttu piirasime serveri päringute arvu ttl-muutuja abil, mis on näha allpool.
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/level_controller.js.ts#L92
Konkurentsi kokkuvõte
Kuni 2011. aasta septembrini oli mängustatistika järgmine:
- seansside arv: 1945 - saadetud ülesanded: 4476 - saatis õiged vastused: 1624 - lõpetas mängu: 31
Nagu näete, algas suurim trepp ülesandega # 2, sest see ei olnud enam tavaline hello world'i näide.
Loe ka:
Kiire sukeldumine Ruby 2.6. Mis on uus?
Dokumentatsiooni kirjutamine on muutunud lihtsaks tänu VuePressile
Vue.js põhitõed. Kuidas selle raamistikuga alustada?