రియల్-టైమ్ కొలాబరేషన్ (Real-time collaboration) అనేది తెర వెనుక ఏం జరుగుతుందో చూసే వరకు చాలా సులభంగా అనిపిస్తుంది. ఒకరు టైప్ చేస్తారు. మరొకరు మూడు పేరాగ్రాఫ్ల పైన ఉన్న ఒక లైన్ను డిలీట్ చేస్తారు. మూడవ వ్యక్తి Stack Overflow నుండి ఒక స్నిప్పెట్ను పేస్ట్ చేస్తారు. ఏదోలా ఆ డాక్యుమెంట్ ఒకే, స్పష్టమైన స్థితికి చేరుకుంటుంది. WebSockets లేదా డిస్ట్రిబ్యూటెడ్ స్టేట్ (distributed state) గురించి ముందస్తు అనుభవం లేకుండా, మొదటి నుండి ఆ ఫ్లూయిడిటీని నిర్మించడం సాహసంగా అనిపించవచ్చు. కానీ నిజంగా నేర్చుకోవడానికి ఇదే సరైన మార్గమని కూడా అనిపిస్తుంది.
ఈ ప్రాజెక్ట్ సున్నా నుండి ప్రారంభమవుతుంది. ఎక్కడి నుంచో తెచ్చుకున్న బాయిలర్ప్లేట్ (boilerplate) లేదు. కష్టమైన భాగాలను ముప్పై సెకన్ల మాంటేజ్లో దాచిపెట్టే మెరుగుపరచబడిన YouTube వాక్త్రూస్ (walkthroughs) లేవు. దీని లక్ష్యం ఏమిటంటే, బహుళ వినియోగదారులు ఒకే ఫైల్ను ఒకేసారి ఎడిట్ చేయగలిగేలా, ఒకరి మార్పులను మరియు ఒకరి కర్సర్లను (cursors) ప్రత్యక్షంగా చూస్తూ పనిచేయగలిగే ఒక కొలాబరేటివ్ కోడ్ ఎడిటర్ను తయారు చేయడం. అక్కడికి చేరుకోవాలంటే ట్రాన్స్పోర్ట్ లేయర్లు (transport layers), కన్సిస్టెన్సీ మోడల్స్ (consistency models), మరియు డాక్యుమెంట్ను దెబ్బతీయకుండా ఒకే సమయంలో జరిగే ఎడిట్లను (concurrent edits) ఎలా విలీనం చేయాలనే క్లిష్టమైన సమస్యను పరిష్కరించాల్సి ఉంటుంది.
"రియల్-టైమ్" అంటే నిజంగా ఏమిటి
చాలా వెబ్ అప్లికేషన్లు రిక్వెస్ట్-రెస్పాన్స్ సైకిల్స్తో (request-response cycles) సౌకర్యవంతంగా పనిచేస్తాయి. మీరు ఒక ఫారమ్ను సబ్మిట్ చేస్తారు, సర్వర్ దానిని సేవ్ చేస్తుంది, మీరు పేజీని రిఫ్రెష్ చేస్తారు. రియల్-టైమ్ కొలాబరేషన్ ఈ పద్ధతిని పూర్తిగా మారుస్తుంది. ప్రతి కీస్ట్రోక్ (keystroke) అనేది ఒక ఈవెంట్, అది మిగిలిన అన్ని కనెక్ట్ చేయబడిన క్లయింట్లకు సాధారణంగా మిల్లీసెకన్లలో చేరాలి మరియు అర్థం మారకుండా సరైన క్రమంలో ఉండాలి.
క్లయింట్ మరియు సర్వర్ మధ్య నిరంతరమైన, ఫుల్-డ్యూప్లెక్స్ కనెక్షన్ను (full-duplex connection) నిర్వహిస్తాయి కాబట్టి, ఇక్కడ WebSockets స్పష్టమైన ట్రాన్స్పోర్ట్ ఎంపిక. ప్రతి కొన్ని సెకన్లకు "ఏదైనా కొత్తది ఉందా?" అని అడుగుతూ బ్యాండ్విడ్త్ను వృథా చేసే HTTP polling లా కాకుండా, WebSocket ఎప్పుడూ ఓపెన్గానే ఉంటుంది. యూజర్ A ఒక సెమీకోలన్ టైప్ చేసినప్పుడు, ఆ క్యారెక్టర్ ఒక మెసేజ్గా మారి సాకెట్ ద్వారా సెంట్రల్ సర్వర్కు చేరుతుంది, ఆపై యూజర్లు B మరియు Cలకు చేరుతుంది. ఈ భాగం సాపేక్షంగా సులభం.
కష్టమైన భాగం ఏమిటంటే, B మరియు C సరిగ్గా ఒకే సమయంలో టైప్ చేసినప్పుడు ఏం జరుగుతుంది అనేది. రెండు మార్పులు దాదాపు ఒకేసారి సర్వర్కు చేరితే, ఏది గెలుస్తుంది? మీరు కేవలం మెసేజ్లను అవి వచ్చిన క్రమంలోనే పంపిస్తే, అక్షరాలు మిస్ అయ్యే లేదా టెక్స్ట్ గందరగోళంగా మారే ప్రమాదం ఉంది. "చివరిగా రాసినదే గెలుస్తుంది" (last-write-wins) అనే సాధారణ వ్యూహాలు విఫలమవుతాయి, ఎందుకంటే అవి వినియోగదారుడి ఉద్దేశాన్ని (intent) పరిగణనలోకి తీసుకోవు. నేను మొదటి లైన్ ప్రారంభంలో "hello" అని టైప్ చేస్తున్నప్పుడు, మీరు కూడా అదే లైన్ ప్రారంభంలో "world" అని టైప్ చేస్తే, ఫలితం ఒకరిని ఒకరు తుడిచివేసేలా ఉండకూడదు. అది "helloworld" లేదా "worldhello" అని ఖచ్చితంగా (deterministically) నిర్ణయించబడాలి. అలా సాధించాలంటే డాక్యుమెంట్ యొక్క నిర్మాణాన్ని అర్థం చేసుకునే ఒక సింక్రొనైజేషన్ వ్యూహం (synchronization strategy) అవసరం.
సున్నా నుండి ప్రారంభించడం ఎందుకు ముఖ్యం
ఈ సంక్లిష్టతను దాచిపెట్టే అద్భుతమైన ఫ్రేమ్వర్క్లు ఉన్నాయి. Yjs, Automerge మరియు Socket.IO వంటివి ఈ కష్టాన్ని తగ్గించి, ఒక మధ్యాహ్నంలోనే పనిచేసే ప్రోటోటైప్ను సిద్ధం చేయగలవు. కానీ వాటి వెనుక ఉన్న ప్రాథమిక అంశాలను (primitives) అర్థం చేసుకోకుండా వాటిని ఉపయోగించడం అనేది, ఇన్స్ట్రుమెంట్లను ఎలా చదవాలో తెలియకుండా ఆటోపైలట్పై విమానాన్ని నడపడం వంటిది. టర్బులెన్స్ (అస్థిరత) ఎదురైనప్పుడు—మరియు డిస్ట్రిబ్యూటెడ్ సిస్టమ్స్లో అది ఎప్పుడూ ఎదురవుతుంది—సమస్య మీ నెట్వర్క్ లేయర్లో ఉందా, మీ కాన్ఫ్లిక్ట్ రిజల్యూషన్లో ఉందా లేదా మీ డేటా మోడల్లో ఉందా అనేది మీరు తెలుసుకోవాలి.
ఇక్కడ లక్ష్యం లైబ్రరీలపై ఆధారపడకముందే ఆ కాన్సెప్ట్లను నేర్చుకోవడం. అంటే, ఈ క్రింది సందర్భాల్లో ఏం జరుగుతుందో స్వయంగా విశ్లేషించడం:
- ఒక క్లయింట్ టైప్ చేస్తున్న మధ్యలో డిస్కనెక్ట్ అయ్యి, పది సెకన్ల తర్వాత మళ్ళీ కనెక్ట్ అయితే
- ఇద్దరు వినియోగదారులు ఒకే కర్సర్ పొజిషన్లో ఒకేసారి టెక్స్ట్ను ఇన్సర్ట్ చేస్తే
- ఒక వినియోగదారుడు మరొకరు ఎడిట్ చేస్తున్న బ్లాక్ను డిలీట్ చేస్తే
- సర్వర్ క్రాష్ అయ్యి, కొత్త నోడ్ డాక్యుమెంట్ స్టేట్ను మొదటి నుండి నిర్మించాల్సి వస్తే
ఈ సమస్యలకు Operational Transformation (OT) మరియు Conflict-free Replicated Data Types (CRDTs) అనేవి రెండు ప్రధాన పరిష్కార మార్గాలు. Google Docs తన ప్రారంభ ఆర్కిటెక్చర్ను OT పై నిర్మించిందని ప్రసిద్ధి చెందింది, ఇది ఆపరేషన్లను అమలు చేసే ముందు వాటిని ఒకదానితో ఒకటి మార్చడానికి (transform) ఒక సెంట్రల్ సర్వర్ను అవసరముగా చేస్తుంది. దీనికి విరుద్ధంగా, CRDTలు సమకాలీన అప్డేట్లను (concurrent updates) ఎటువంటి సమన్వయం లేకుండా స్థానికంగానే విలీనం చేసేలా రూపొందించబడ్డాయి, ఇది వాటిని peer-to-peer లేదా edge-based సెటప్లకు అనుకూలంగా మారుస్తుంది. వీటి మధ్య లేదా హైబ్రిడ్ పద్ధతుల మధ్య ఎంపిక చేసుకోవాలంటే మెమరీ వినియోగం, కన్వర్జెన్స్ గ్యారెంటీలు (convergence guarantees) మరియు ఇంప్లిమెంటేషన్ సంక్లిష్టత వంటి వాటి మధ్య ఉన్న తేడాలను (trade-offs) అర్థం చేసుకోవాలి. ఆ తేడాల గురించి చదవడం మాత్రమే సరిపోదు; అవి ఎక్కడ విఫలమవుతాయో చూడటానికి సాధారణ (naive) మరియు మెరుగుపరచబడిన (refined) వెర్షన్లు రెండింటినీ అమలు చేయడమే ఈ ప్రణాళిక.
పునర్నిర్మాణాలు, తప్పులు మరియు నిష్ఫల ప్రయత్నాలు
అంచనాలను నిజాయితీగా నిర్ణయించుకోవాలి. ఏదీ పని చేయని సమయాలు కూడా ఉంటాయి. మొదటి ప్రయత్నంలో టెక్స్ట్ మార్పులను సూచించడానికి సాధారణ JSON patches ఉపయోగించవచ్చు, కానీ JSONలో "ఒక పేరాలో ఇండెక్స్ 5" అనే భావన లేదని తర్వాత తెలుస్తుంది, దీనివల్ల ఒకే ఇండెక్స్లో జరిగే రెండు ఏకకాలపు (concurrent) ఇన్సర్షన్లు విలీనం (merge) అవ్వడానికి బదులుగా ఒకదానికొకటి ఓవర్రైట్ అవుతాయి. రెండవ ప్రయత్నంలో ఒక కస్టమ్ లీనియర్ హిస్టరీ లాగ్ను నిర్మించవచ్చు, కానీ డాక్యుమెంట్ పెరిగే కొద్దీ ఆ లాగ్ను రీప్లే చేయడం Big O నైట్మేర్గా మారుతుందని గ్రహించవచ్చు. మూడవ ప్రయత్నంలో WebSockets స్థానికంగా (locally) పనిచేయవచ్చు, కానీ ప్యాకెట్ లాస్ మరియు వేరియబుల్ లేటెన్సీ (variable latency) వంటి అంశాల వల్ల నిజమైన నెట్వర్క్లో అవి విఫలమవుతాయి.
ఆ ఘర్షణే (friction) అసలు ఉద్దేశ్యం. ఒక పని చేసే రిపోజిటరీని కాపీ చేయడం వల్ల, క్యూ (queue) ఎందుకు ఆ నిర్దిష్ట క్రమంలో ఫ్లష్ అవుతుంది లేదా సర్వర్ ఎందుకు వెర్షన్ వెక్టార్ను (version vector) నిర్వహిస్తుంది అనే అంశాలపై పరిశోధన చేయకుండానే దాటవేయవచ్చు. ఒకే కాంపోనెంట్ను మూడుసార్లు మళ్ళీ నిర్మించడం నెమ్మదిగా అనిపించవచ్చు, కానీ ఫ్రేమ్వర్క్ ఏమి చేస్తుంది మరియు మీ స్వంత లాజిక్ దేనిని హ్యాండిల్ చేయాలి అనే దాని మధ్య ఉన్న సరిహద్దును అర్థం చేసుకోవడానికి ఇది మిమ్మల్ని ప్రేరేపిస్తుంది.
ఈ ప్రక్రియ యొక్క డాక్యుమెంటేషన్ కేవలం విజయాల సమాహారం (highlight reel) మాత్రమే కాదు. ఇందులో తప్పు దారులు కూడా ఉంటాయి. ఉదాహరణకు, ప్రెజెన్స్ అవేర్నెస్ (presence awareness) నిర్మించడం—ఎవరు ఆన్లైన్లో ఉన్నారు మరియు వారి కర్సర్ ఎక్కడ ఉంది అని తెలుసుకోవడం—ఇది కేవలం ఒక సౌందర్య ఫీచర్ (cosmetic feature) అనిపిస్తుంది, కానీ అది టెక్స్ట్తో పాటు అదే కన్సిస్టెన్సీ మోడల్పై ఆధారపడి ఉంటుందని మీరు గ్రహించే వరకు. ఒకవేళ యూజర్ A, యూజర్ B యొక్క కర్సర్ను కాలమ్ 10 వద్ద చూస్తే, ఆ తర్వాత యూజర్ B నాలుగు అక్షరాలను ఇన్సర్ట్ చేస్తే, ఆ కర్సర్ ఎక్కడికి మారుతుంది? డాక్యుమెంట్ టోపాలజీ (document topology) గురించి ఉమ్మడి అవగాహన లేకపోతే, ప్రెజెన్స్ డేటా వాస్తవానికి దూరంగా వెళ్ళిపోతుంది. దీనిని పరిష్కరించడానికి కర్సర్ పొజిషన్ను కేవలం దాని సంఖ్యాపరమైన ఇండెక్స్కు మాత్రమే కాకుండా, అంతర్లీన డేటా స్ట్రక్చర్ యొక్క ఐడెంటిటీకి (identity) అనుసంధానించాల్సి ఉంటుంది. ట్యుటోరియల్స్ ఇటువంటి వివరాలను క్లుప్తంగా మాత్రమే చెబుతాయి, అవి విసుగు పుట్టించేవి కాబట్టి తప్ప, అవి ముఖ్యమైనవి కానందున కాదు.
తదుపరి ఏమిటి
తక్షణ రోడ్మ్యాప్ కావాలనే తక్కువ వివరాలతో రూపొందించబడింది. మొదటి మైలురాళ్లు ఇవి:
- లేటెన్సీ మరియు కనెక్షన్ లైఫ్సైకిల్ను ప్రత్యక్షంగా అనుభవించడానికి, క్యారెక్టర్ ఈవెంట్లను ఎకో (echo) చేసే ఒక రా వెబ్సాకెట్ (raw WebSocket) సర్వర్
- కన్కరెన్సీ (concurrency) ఉన్నప్పుడు సాధారణ ఇన్సర్షన్ ఆర్డరింగ్ ఎందుకు విఫలమవుతుందో అర్థం చేసుకోవడానికి క్లయింట్పై ఒక సాధారణ స్ట్రింగ్ బఫర్
- కమ్యూటేటివ్ ప్రాపర్టీని (commutative property) ప్రత్యక్షంగా చూడటానికి, ఎంత అసమర్థంగా ఉన్నప్పటికీ, ఆర్డర్డ్ సీక్వెన్స్ల కోసం మొదటి నుండి నిర్మించిన CRDT
- ఎడిటర్ యొక్క ఇంపరేటివ్ API మరియు ఆపరేషనల్ హిస్టరీ యొక్క ఫంక్షనల్ స్వభావం మధ్య ఉన్న తేడాను అర్థం చేసుకోవడానికి, CodeMirror లేదా Monaco వంటి అసలైన కోడ్ ఎడిటర్ ఉపరితలంపై క్రమంగా ఇంటిగ్రేషన్ చేయడం
ప్రతి దశతో పాటు ఒక వివరణాత్మక కారణం (rationale) ఉంటుంది. ఈ విధానమే ఎందుకు, వేరేది ఎందుకు కాదు? ఏ ఊహలు తప్పు అని తేలింది? ఏ అబ్స్ట్రాక్షన్ లీక్ అయింది?
ఒక నిజమైన పాఠం
WebSockets లేదా CRDTs లో అనుభవం లేకుండా ఇటువంటి ప్రాజెక్ట్ను ప్రారంభించడం భయంకరంగా అనిపించవచ్చు, కానీ నైపుణ్యం (expertise) అంటే తరచుగా మెరుగైన పేర్లతో పిలవబడే పదేపదే జరిగే గందరగోళం మాత్రమే. దీని లక్ష్యం వేగంగా పూర్తి చేయడం కాదు. ప్రతి పొరను (layer) కేవలం ఆశతో కాకుండా, స్పష్టమైన ఉద్దేశ్యంతో నిర్మించడం వల్ల ప్రవర్తనను అంచనా వేయగలిగే వ్యవస్థను రూపొందించడం.
మీరు ఇంతకుముందు కొలాబరేటివ్ సాఫ్ట్వేర్ను (collaborative software)—టెక్స్ట్ ఎడిటర్, డిజైన్ టూల్ లేదా గేమ్ స్టేట్ సింక్ ఇంజిన్ ఏదైనా—నిర్మించి ఉంటే, మిమ్మల్ని ఆశ్చర్యపరిచిన వైఫల్యాల గురించి పంచుకోండి. మీరు కూడా ఈ వ్యవస్థలను నేర్చుకుంటుంటే, నాతో పాటు కొనసాగండి. కోడ్ నెమ్మదిగా వస్తుంది మరియు అది తరచుగా తిరిగి వ్రాయబడుతుంది. Day 0 ఇప్పుడే ప్రారంభమవుతుంది.
