17 पॉइंट द्वारा GN⁺ 2024-08-04 | 3 टिप्पणियां | WhatsApp पर शेयर करें

"merchants2 टेबल? हाँ, merchants में columns कम पड़ गए थे, इसलिए हमने merchants2 बना दिया।"

  • जब मैंने पहली बार programming शुरू की, तब मुझे पता ही नहीं था कि लोग programming से पैसे कमाते हैं
  • अपनी पहली software job में मैंने बहुत कुछ सीखा, और वहाँ का codebase एक साथ सबसे खराब भी था और सबसे बेहतरीन भी

Database हमेशा जीवित रहता है

  • Legacy system में database सिर्फ data store नहीं होता। वह पूरे system की constraints तय करता है और वही वह जगह है जहाँ सारा code आकर मिलता है
  • SQL Server में table columns की संख्या की सीमा होती है। तब यह 1024 थी, अब 4096 है। Merchants table में columns कम पड़ गए, तो Merchants2 table बना दी गई थी (जिसमें 500 से ज़्यादा columns थे)
  • Merchants और Merchants2 system का core थे। सब कुछ Merchants से जुड़ा हुआ था। दूसरी normalized tables भी थीं, लेकिन वे भी Merchants के साथ foreign key relationship में थीं

SequenceKey

  • SequenceKey एक बहुत simple table थी जिसमें सिर्फ एक column और एक value थी
  • इसका उपयोग ID बनाने के लिए किया जाता था। शायद यह इसलिए बनाई गई थी क्योंकि SQL Server auto-increment ID support नहीं करता था
  • हर stored procedure, SequenceKey से key लेता, उसे बढ़ाता, और कई tables की ID के रूप में इस्तेमाल करता था। यह implicit join की तरह काम करता था

Calendar

  • Calendar हाथ से भरी गई calendar table थी। अगर Calendar expire हो जाती, तो system में login नहीं किया जा सकता था
  • कुछ साल पहले ऐसा हुआ भी था, और फिर एक intern ने उसमें 5 साल और भर दिए। यह किस system में इस्तेमाल होती थी, किसी को पता नहीं था

Employees

  • हर सुबह 7:15 बजे employees table delete कर दी जाती थी और ADP से मिली CSV से फिर से भरी जाती थी
  • इस काम के दौरान system में login नहीं किया जा सकता था। कभी-कभी यह काम fail भी हो जाता था
  • Data को headquarters तक replicate करना पड़ता था, इसलिए इसे email से एक व्यक्ति को भेजा जाता था, जो रोज़ एक button दबाकर data copy करता था

Replacement database

  • आप सोच सकते हैं कि database को साफ-सुथरा बनाया जा सकता था। कंपनी ने भी ऐसा ही सोचा था
  • Database की एक copy थी, लेकिन उसका data लगभग 10 मिनट पीछे रहता था। Sync सिर्फ one-way था
  • यह database normalized था, इसलिए merchants में phone number ढूँढने के लिए 7 joins करने पड़ते थे

Sales performance

  • हर salesperson का हर महीने एक quota होता था, जिसे "win" कहा जाता था
  • इसे manage करने वाली table बहुत जटिल थी। हर दिन एक job चलती थी जो जोड़ी गई या बदली गई rows ढूँढकर उन्हें headquarters system के साथ sync करती थी
  • समस्या तब शुरू हुई जब एक salesperson ने record को manually बदलने का अनुरोध किया
  • वह salesperson पहले ही अपना win पूरा कर चुका था और उसी महीने एक बड़ी sale और कर चुका था, लेकिन वह चाहता था कि उसे अगले महीने में शिफ्ट कर दिया जाए
  • यह काम एक intern को दे दिया गया, और बात फैलते ही 3 साल में ऐसे requests exponentially बढ़ गए
  • एक समय ऐसा आया कि 3 interns का पूरा काम सिर्फ SQL statements लिखना रह गया था। इसके लिए application बनाना बहुत मुश्किल माना गया

Codebase

  • पहला codebase जिससे मैं मिला, वह Team Foundation Server में था। यह एक centralized version control system था
  • जिस codebase पर मैंने ज़्यादातर काम किया, वह आधा VB और आधा C# था। वह IIS पर चलता था और session state का हर जगह उपयोग करता था
  • इसका मतलब यह था कि अगर आप किसी page तक Path A या Path B से पहुँचते, तो उसी page पर आपको बिल्कुल अलग चीज़ दिखाई दे सकती थी
  • उस समय मौजूद लगभग हर JavaScript framework इस repository में check in किया गया था। ज़्यादातर उनके साथ author द्वारा ज़रूरी समझे गए custom changes भी थे। खास तौर पर knockout, backbone, marionette, और साथ में jquery तथा jquery plugins नज़र आते थे
  • इस codebase के अलावा लगभग 12 SOAP services और कई native Windows applications भी थीं

Gilfoyle की hard drive

  • Gilfoyle को बेहद तेज programmer माना जाता था। मैं उनसे कभी मिला नहीं, लेकिन उनके code और उनकी hard drive में बचे code के ज़रिए मैं उन्हें जानता था
  • Munch ने Gilfoyle के कंपनी छोड़े कई साल बाद तक भी उनकी hard drive को RAID configuration में अपनी desk पर रखा हुआ था
  • क्योंकि Gilfoyle code check in नहीं करता था, और single user के लिए random one-off Windows applications बनाने के लिए मशहूर था
  • ऐसा uncommon नहीं था कि कोई user किसी ऐसे application की bug report लेकर आ जाए जो सिर्फ Gilfoyle की hard drive में ही मौजूद हो

Shipping bug

  • मेरे काम का ज़्यादातर हिस्सा उन bugs का पीछा करना था जिन्हें team किसी को assign नहीं करना चाहती थी
  • हर कुछ महीनों में एक बेहद परेशान करने वाला bug आता था, जहाँ shipment के बाद कुछ orders shipping queue में अटके रहते थे, और वे shipped होने के बावजूद unshipped दिखते थे
  • इसे ठीक करने के लिए हमने कई उपाय आज़माए (SQL scripts, Windows applications वगैरह)। मुझे सलाह दी गई थी कि root cause मत खोजो, लेकिन मैं अपने आपको रोक नहीं पाया
  • इस प्रक्रिया में मैंने Gilfoyle की सोच को समझा। Shipping app पूरे database को खींच लेता था, फिर date से filter करके application की start date के बाद के सारे orders रखता था
  • App SOAP service पर depend करता था, लेकिन service जैसा काम करने के लिए नहीं, बल्कि pure function की तरह। सारे side effects client ही पैदा करता था
  • उसी client में मुझे एक बहुत बड़ी class hierarchy मिली, जिसमें 120 classes थीं, हर एक में अलग-अलग methods थे, और inheritance 10 levels तक नीचे जाता था
  • एक ही समस्या थी: सारे methods खाली थे
  • यह सब एक ऐसी structure बनाने के लिए था जिस पर reflection इस्तेमाल किया जा सके। वह reflection pipe-separated string बनाता था (जिसकी structure database-driven थी, लेकिन पूरी तरह static), और उसे socket पर भेजता था
  • आखिरकार यह Kewill तक जाता था, जो carrier से communicate करने वाली service थी। Bug इसलिए होता था क्योंकि Kewill हर महीने 9-digit number दोबारा इस्तेमाल करता था, और किसी ने पुराने orders delete करने वाली cron job disable कर दी थी

सुंदर अव्यवस्था

  • इस codebase के बारे में कहने के लिए बहुत कुछ है। जैसे senior developers की वह team जिसने 5 साल तक code release किए बिना पूरा system rewrite करने की कोशिश की, या वह Red Hat consultant जो एक ही database बनाना चाहता था जो सब कुछ control करे
  • इस codebase में पागलपन से भरे बहुत से कोने थे, और single feature को scratch से शुरू करने के लिए dedicated team चाहिए हो, ऐसे बहुत से कारण भी थे
  • लेकिन सबसे अहम कहानी यह है कि Justin ने Merchants Search page को बेहतर बनाया। यही page पूरे application का entry point था
  • हर customer service representative, merchant से phone पर बात करते हुए उसका ID या नाम डालकर जानकारी खोजता था। फिर वह एक बहुत बड़े page पर पहुँचता था जिसमें सारी जानकारी होती थी
  • यह page ज़रूरी हर जानकारी और हर उस link से भरा हुआ था जहाँ आप जाना चाहें, इसलिए सबसे अच्छे अर्थ में information-dense था। लेकिन यह बहुत ही slow था
  • Justin मेरे group का इकलौता senior developer था। वह तेज दिमाग वाला, व्यंग्यात्मक, और business में बहुत कम रुचि रखने वाला था
  • वह सीधे सच बोलता था, बिना नरमी बरते, और हमेशा आसपास की teams से तेज़ी से अकेले समस्या हल कर देता था
  • एक दिन Justin इस बात से तंग आ गया कि Merchants Search page कितना slow है, तो उसने जाकर उसे ठीक कर दिया
  • स्क्रीन के हर box को अपना endpoint बना दिया गया। Load होते ही fold के ऊपर की सारी चीज़ें fetch होने लगीं, और जैसे ही एक load होती, और requests चल पड़तीं
  • Page load time कई मिनटों से घटकर 1 सेकंड से भी कम हो गया

Decoupling के दो तरीके

  • Justin यह इसलिए कर पाया क्योंकि इस codebase में कोई master plan था ही नहीं
  • System के लिए कोई मोटा blueprint नहीं था, API के expected shape नहीं थे, कोई documented design system नहीं था, और consistency लागू कराने वाली architecture review board भी नहीं थी
  • App पूरी तरह बिखरा हुआ था। कोई उसे ठीक नहीं कर सकता था, इसलिए किसी ने कोशिश भी नहीं की। उसकी जगह हम सबने अपनी-अपनी छोटी-सी समझदारी की दुनिया बना ली
  • यह monolithic app पूरी तरह मजबूरी में, अपने edges पर अच्छे और छोटे apps के एक microcosm की तरह बढ़ता गया
  • App के किसी हिस्से को बेहतर बनाने का काम जिस किसी को मिलता, वह आख़िरकार उस उलझे जाल को सुलझाने की कोशिश छोड़ देता, फिर कोई अच्छा-सा छोटा कोना ढूँढता जहाँ कुछ नया बनाया जा सके। और धीरे-धीरे links को update कर देता ताकि वे उस नए बेहतर हिस्से की ओर जाएँ और पुरानी चीज़ अनाथ हो जाए
  • यह सब सुनने में messy लग सकता है। लेकिन इस पर काम करना हैरान कर देने वाली तरह से मज़ेदार था। Code duplication की चिंता गायब थी, consistency की चिंता भी, scalability की चिंता भी
  • Code उपयोग के लिए लिखा जाता था, आसपास के हिस्सों को जितना हो सके उतना कम छूते हुए, और इस तरह कि उसे आसानी से replace किया जा सके। हमारा code decoupled था, क्योंकि coupling करना बस उससे ज़्यादा मुश्किल था

उसके बाद

  • उसके बाद अपने career में मुझे कभी इतनी अद्भुत रूप से बदसूरत codebase पर काम करने का सौभाग्य नहीं मिला
  • उसके बाद जो भी बदसूरत codebases मैंने देखीं, वे consistency की ज़रूरत से ऊपर उठ नहीं पाईं
  • शायद इसलिए कि "serious" developers बहुत पहले ही इस codebase को छोड़ चुके थे। पीछे बस बेतरतीब interns और junior developers ही बचे थे
  • या शायद इसलिए कि developers और users के बीच कोई middle layer नहीं थी। न translation, न requirements gathering, न cards। बस आप customer service representative की desk के पास खड़े होकर पूछते थे कि उनकी ज़िंदगी कैसे बेहतर बनाई जा सकती है
  • मुझे वही direct connection याद आता है। तेज feedback, बड़े-बड़े plans बनाने की ज़रूरत न होना, और problems तथा code के बीच का सीधा रिश्ता
  • शायद यह सिर्फ भोली nostalgia है। लेकिन जैसे मैं अपने बचपन के सबसे खराब कुछ सालों में लौट जाना चाहता हूँ, वैसे ही जब भी मैं "enterprise design patterns" का सामना करता हूँ, मेरा मन उसी सुंदर और भयावह codebase में लौट जाता है

GN⁺ की राय

  • यह लेख legacy systems के साथ काम करने वाले developers को अपनापन और तसल्ली दे सकता है। यह दिखाता है कि imperfect codebase भी मूल्यवान हो सकती है और उससे बहुत कुछ सीखा जा सकता है
  • लेकिन इस codebase की समस्याओं को romanticize नहीं किया जाना चाहिए। जब technical debt बढ़ता जाता है, तो development की गति बहुत धीमी हो जाती है और maintenance मुश्किल हो जाता है। लंबे समय में इसकी लागत और बढ़ती है
  • Codebase को सुधारने की कोशिश छोड़कर सिर्फ temporary fixes जोड़ते जाना सही जवाब नहीं है। Legacy system को धीरे-धीरे बेहतर बनाने या migrate करने की strategy ज़रूरी है
  • Development culture और process भी महत्वपूर्ण हैं। Code review, architecture design, documentation जैसी engineering practices का सही पालन बेहतर codebase बनाने में मदद करता है
  • Users के साथ करीबी संवाद और तेज feedback एक अच्छी बात है। Agile जैसी methodologies के ज़रिए इसे बढ़ावा देते हुए code quality को manage करना आदर्श होगा
  • आख़िरकार, सब कुछ संतुलन का मामला है। पूर्णता का पीछा करने के बजाय, sustainable तरीके से users की ज़रूरतें पूरी करना और technical debt को manage करना ज़्यादा महत्वपूर्ण है

3 टिप्पणियां

 
bus710 2024-08-07

मेरी पहली नौकरी में firmware developer के तौर पर जो काम मिला था, वह यह था कि जिन प्रोडक्ट्स के लिए न तो developer थे और न source code, उनके 8051 MCU के hex से निकाले गए assembly code का विश्लेषण करके उसे C में दोबारा implement करना…
कम से कम एक चलने वाला प्रोडक्ट तो था, इसलिए code देखकर और प्रोडक्ट को test करके किसी तरह वह काम कर लिया…
प्रांतीय बिजनेस ट्रिप पर जाकर इसे ठीक करके आओ, नहीं तो अपनी उंगली काटकर लौटो—ऐसी धमकी भी सुनी थी,
और एक बार जो अजीब bug समझ नहीं आ रहा था, वह दरअसल उस दीवार के पीछे लगे elevator की वजह से निकला था जहाँ device install किया गया था।
Busan के Dongbaekseom APEC सम्मेलन स्थल के आधिकारिक उद्घाटन से पहले अंदर जाकर तरह-तरह की चीज़ें install करने की याद भी आती है, हाहा

 
GN⁺ 2024-08-04
Hacker News की राय
  • अपनी पहली कंपनी में एक जटिल VB application मेंटेन किया था

    • हर ग्राहक की ज़रूरतों के हिसाब से बहुत सारे global variables थे
    • bug सिर्फ debug mode में नहीं दिखता था, इसलिए ग्राहक के यहाँ Visual Studio इंस्टॉल करवाकर उसे debug mode में चलाना सिखाया था
    • version control नहीं था, और code कई folders में कॉपी किया हुआ था, जिससे काफ़ी भ्रम होता था
    • ग्राहक की समस्या होने पर साइट पर जाकर code में बदलाव करते थे
    • final version पर कोई सहमति नहीं थी, इसलिए हर ग्राहक अलग version इस्तेमाल कर रहा था
  • अपनी पहली नौकरी में COBOL और Java में लिखे एक legacy product का maintenance किया था

    • source control system से files को अलग-अलग checkout करके काम किया जाता था
    • हर ग्राहक के लिए final compiled product को दिखाने वाली एक 'master' jar file होती थी
    • code बदलने के बाद script चलाकर master jar file को update किया जाता था
    • पूरा codebase compile नहीं होता था और manual patching की जाती थी
    • codebase में बहुत सारी inconsistencies पैदा हो गई थीं
    • git पर migrate करने में 2 साल लग गए
  • 12,000 lines से ज़्यादा की एक Perl script को refactor किया था

    • array क्या होता है यह न जानने वाले लेखक ने strings का इस्तेमाल करके array implement किया था
    • refactor के बाद code 200 lines का रह गया
  • theory और reality के बीच का फ़र्क महसूस किया था

    • बहुत सी companies और projects इसी तरह की प्रक्रिया से गुज़रते हैं
    • ideal methods पर चर्चा होती है, लेकिन असल में काम करने वाले तरीके से ही चीज़ें आगे बढ़ती हैं
  • Telegram Android client का codebase बहुत जटिल था

    • बड़े files की वजह से GitHub ने render करना छोड़ दिया था
    • message rendering और interaction सब कुछ एक ही class में handle किया जाता था
    • refactoring की permission मिली थी, लेकिन उसे कर नहीं पाए
  • अपनी पहली नौकरी में reporting work की memory problem हल की थी

    • team lead और boss हैरान रह गए थे
    • दूसरे developers Linux को नापसंद करते थे और .NET में switch करना चाहते थे
  • ग्राहकों से सीधे बात करके समस्याएँ हल करने का अनुभव अच्छा लगा था

    • prototype जल्दी बनाकर ग्राहकों से test करवाते थे
    • codebase बिखरा हुआ था, लेकिन अच्छी तरह काम करता था
  • कई markets को support करने वाला एक system बनाया था

    • original system को copy करके international version बनाया था
    • 5 साल बाद system अलग नहीं हुए, बल्कि एक-दूसरे में उलझ गए
    • नया system और पुराना system काफ़ी tightly coupled थे
  • अपनी पहली नौकरी में अनुभवहीन लोग बहुत थे

    • अनुभव मिलने के बाद लोग बेहतर नौकरी में चले गए
  • modern SQL Server में समस्या हल करने के तरीकों की व्याख्या की थी

    • customer customization, shared ID, manual calendar tables, table partitioning, delayed reporting replicas आदि
    • VB और C# का mixed codebase आम है
    • automatic conversion tools इस्तेमाल किए जा सकते हैं
 
reddiana 2024-08-05

नंबरिंग टेबल(SequenceKey) और business day टेबल(Calendar)
पुरानी यादें ताज़ा हो गईं। अब यह कैसे किया जाता है, पता नहीं, लेकिन पहले यह आम तौर पर इस्तेमाल होने वाली टेबलें थीं। SI करने पर काम के common part में संबंधित फीचर implement किया जाता था।