Ushirikiano wa wakati halisi (real-time) unaonekana kuwa rahisi hadi unapoanza kuangalia undani wake. Mtu mmoja anachapa. Mwingine anafuta mstari uliopo madhaa matatu juu. Wa tatu anabandika kipande cha kodi kutoka Stack Overflow. Kwa namna fulani, hati hiyo inajipanga katika hali moja iliyoshikamana. Kujenga mtiririko huo kuanzia mwanzo, bila uzoefu wa awali katika WebSockets au distributed state, kunaonekana kuwa hatari. Pia kunaonekana kuwa njia sahihi ya kujifunza kikamilifu.

Mradi huu unaanza kuanzia sifuri. Hakuna kodi za kuanzia (boilerplate) zilizokopwa. Hakuna video za YouTube zilizopambwa ambapo sehemu ngumu zinapunguzwa katika montaji ya sekunde thirti. Lengo ni kutengeneza kihariri kodi cha ushirikiano ambapo watumiaji wengi wanaweza kuhariri faili moja kwa wakati mmoja, wakiona mabadiliko ya kila mmoja—na cursor za kila mmoja—yanapotokea. Kufikia hatua hiyo kutahitaji kuelewa tabaka za usafirishaji (transport layers), mifumo ya uthabiti (consistency models), na tatizo gumu la kuunganisha marekebisho yanayofanyika kwa wakati mmoja bila kuharibu hati.

Maana Halisi ya “Wakati Halisi”

Programu nyingi za wavuti zimezoea mizunguko ya ombi-na-jibu (request-response). Unatuma fomu, seva inahifadhi, kisha unajirekebisha ukurasa (refresh). Ushirikiano wa wakati halisi unavunja mkataba huo kabisa. Kila mguso wa herufi ni tukio ambalo lazima lisambazwe kwa kila mteja (client) aliyeunganishwa, kwa kawaida ndani ya milisekunde, na ufikie kwa mpangilio unaohifadhi maana.

WebSockets ndicho chaguo dhahiri la usafirishaji hapa kwa sababu zinadumisha muunganisho endelevu wa pande mbili (full-duplex) kati ya mteja na seva. Tofauti na HTTP polling, ambayo inapoteza bandwidth kuuliza “kuna kitu kipya?” kila baada ya sekunde chache, WebSocket inabaki wazi. Mtumiaji A anapochapa nukta mkato, herufi hiyo inakuwa ujumbe unaosafiri kupitia socket hadi kwenye seva kuu, kisha unasambazwa kwa watumiaji B na C. Sehemu hiyo ni rahisi kiasi.

Sehemu ngumu ni kile kinachotokea wakati B na C wanachapa kwa wakati ule ule. Ikiwa mabadiliko yote mawili yatafika kwenye seva karibu kwa wakati mmoja, ni yapi yatashinda? Ikiwa utasambaza ujumbe tu kulingana na mpangilio wa kuwasili, unahatarisha herufi kupotea au maandishi kuchanganyikiwa. Mbinu rahisi za 'last-write-wins' hushindwa kwa sababu zinapuuza nia ya mtumiaji. Ikiwa nitachapa “hello” mwanzoni mwa mstari wa kwanza wakati wewe unachapa “world” mwanzoni mwa mstari wa kwanza, matokeo hayapaswi kuwa mgongano ambapo mmoja wetu anafutwa. Yanapaswa kuwa “helloworld” au “worldhello,” yakichaguliwa kwa njia inayotabirika (deterministically). Kufikia hilo kunahitaji mkakati wa usawazishaji (synchronization strategy) unaoelewa muundo wa hati.

Kwa Nini Kuanza Kuanzia Chini Kabisa ni Muhimu

Kuna mifumo (frameworks) bora inayoficha ugumu huu. Yjs, Automerge, na Socket.IO zinaweza kuficha matatizo hayo na kutengeneza mfano unaofanya kazi ndani ya mchana mmoja. Lakini kuzitumia bila kuelewa misingi iliyo chini yake ni kama kuendesha ndege kwa autopilot bila kujua jinsi ya kusoma vifaa vya uendeshaji. Mtikisiko unapojitokeza—na katika mifumo ya kusambazwa (distributed systems), kila wakati hutokea—unahitaji kujua ikiwa tatizo liko kwenye tabaka lako la mtandao, utatuzi wako wa migongano, au kwenye mfumo wako wa data.

Ahadi hapa ni kujifunza dhana kabla ya kutegemea maktaba (libraries). Hiyo inamaanisha kufikiria kwa kina jinsi inavyofanya kazi wakati:

  • Mteja anakatika katikati ya kuchapa na kuunganishwa tena baada ya sekunde kumi
  • Watumiaji wawili wanaingiza maandishi kwenye nafasi ile ile ya cursor kwa wakati mmoja
  • Mtumiaji mmoja anafuta sehemu ambayo mtumiaji mwingine anafanyia marekebisho kwa wakati huo
  • Seva inafeli na node mpya inapaswa kujenga upya hali ya hati kuanzia mwanzo

Operational Transformation (OT) na Conflict-free Replicated Data Types (CRDTs) ni familia mbili kuu za suluhisho kwa matatizo haya. Google Docs ilijenga usanifu wake wa awali kwa kutumia OT, ambayo inahitaji seva kuu kubadilisha shughuli (operations) dhidi ya nyingine kabla ya kuzitekeleza. CRDTs, kwa upande mwingine, zimeundwa ili mabadiliko yanayofanyika kwa wakati mmoja yaweze kuunganishwa ndani ya kifaa (locally) bila uratibu, jambo linalozifanya kuwa nzuri kwa mifumo ya peer-to-peer au edge-based. Kuchagua kati ya hizo—au mbinu mchanganyiko—kunahitaji kuelewa faida na hasara (trade-offs) zake katika matumizi ya kumbukumbu, ahadi za muungano (convergence guarantees), na ugumu wa utekelezaji. Kusoma kuhusu faida na hasara hizo haitoshi; mpango ni kutekeleza matoleo rahisi na yaliyoboreshwa ili kuona pale yanapofeli.

Ujenzi Upya, Makosa, na Njia Zilizofika Tamati

Matarajio yamepangwa kwa uaminifu. Kutakuwa na vipindi ambapo hakuna kitu kinachofanya kazi. Jaribio la kwanza linaweza kutumia JSON patches rahisi kuwakilisha mabadiliko ya maandishi, kisha ukagundua kuwa JSON haina dhana ya “indeksi 5 katika aya,” hivyo uingizaji mbili wa wakati mmoja kwenye indeksi moja unajifuta badala ya kuunganishwa. Jaribio la pili linaweza kujenga logi ya historia ya mstari (linear history log) iliyoboreshwa, kisha ukagundua kuwa kucheza upya logi hiyo ni jinamizi la Big O wakati hati inapokuwa kubwa. Jaribio la tatu linaweza kufanikisha WebSockets kufanya kazi ndani ya mtandao wa ndani (locally), kisha likashindwa kwenye mtandao halisi ambapo upotevu wa pakiti (packet loss) na ucheleweshaji unaobadilika (variable latency) yanabadilisha sheria.

Msuguano huo ndio lengo. Kunakili sehemu ya msimbo (repository) inayofanya kazi kungezuia uchunguzi wa kwa nini foleni (queue) inasafishwa kwa mpangilio huo maalum, au kwa nini seva inadumisha version vector. Kujenga upya kipengele kilekile mara tatu ni polepole, lakini kunalazimisha uelewa wa mpaka kati ya kile framework inachofanya na kile mantiki yako mwenyewe inapaswa kushughulikia.

Maelezo ya mchakato huu hayatakuwa mkusanyiko wa mafanikio tu. Yatajumuisha na makosa yaliyofanyika. Kwa mfano, kujenga uelewa wa uwepo (presence awareness)—kujua nani yuko mtandaoni na kozi yake (cursor) iko wapi—inaonekana kama kipengele cha urembo mpaka utakapogundua kuwa kinategemea mfumo uleule wa uthabiti (consistency model) kama maandishi yenyewe. Ikiwa mtumiaji A anaona kozi ya mtumiaji B kwenye safu ya 10, kisha mtumiaji B anaingiza herufi nne, kozi hiyo itahamia wapi? Bila uelewa wa pamoja wa topolojia ya hati, data ya uwepo inatengana na ukweli. Kutatua hilo kunahitaji kuunganisha nafasi ya kozi na utambulisho wa muundo wa data wa msingi, si tu indeksi yake ya namba. Haya ni aina ya maelezo ambayo mafunzo (tutorials) huyaacha kwa ufupi kwa sababu ni ya kuchosha, si kwa sababu hayajali.

Kinachofuata

Ramani ya njia ya haraka imepangwa kuwa fupi kwa makusudi. Hatua za kwanza zitakuwa:

  • Seva ya WebSocket mbichi inayorudisha matukio ya herufi (echoes character events), ili uhisi ucheleweshaji (latency) na mzunguko wa muunganisho (connection lifecycle) kwa karibu
  • Buffer rahisi ya maandishi (string buffer) upande wa mteja (client) ili kuelewa kwa nini mpangilio wa uingizaji wa kawaida unashindwa wakati wa ushindani (concurrency)
  • CRDT iliyotengenezwa kuanzia mwanzo kwa mfuatano uliopangwa, hata kama haina ufanisi, ili kuona sifa ya kubadilishana (commutative property) ikiwa kazini
  • Muunganisho wa hatua kwa hatua na sehemu halisi ya kuhariri kodi, pengine kitu kama CodeMirror au Monaco, ili kukabiliana na kutofautiana kati ya API ya amri (imperative API) ya mhariri na asili ya kiutendaji (functional nature) ya historia ya utendaji (operational history)

Kila hatua itakuja na sababu iliyoandikwa. Kwa nini njia hii na si ile nyingine? Ni mawazo gani yaliyopingwa? Ni uabstrakt (abstraction) gani ilivuja?

Funzo Halisi

Kuanza mradi kama huu bila uzoefu katika WebSockets au CRDTs inatisha, lakini utaalamu mara nyingi ni kuchanganyikiwa mara kwa mara kwa kutumia lebo bora zaidi. Lengo si kumaliza haraka. Ni mfumo ambao tabia yake inatabirika kwa sababu kila tabaka lilijengwa kwa nia badala ya kuingizwa kwa matumaini.

Ikiwa umewahi kujenga programu ya ushirikiano hapo awali—iwe mhariri wa maandishi, zana ya usanifu, au injini ya usawazishaji wa hali ya mchezo (game state sync engine)—shiriki aina za makosa yaliyokushangaza. Ikiwa unajifunza mifumo hii pia, fuata hatua hizi. Msimbo utakuja polepole, na utatafitiwa mara kwa mara. Siku ya 0 inaanza sasa.