SQL इकाई परीक्षण में मेरे प्रयास
हाल ही में मैं एक सहकर्मी के साथ इस बारे में चर्चा कर रहा था कि SQL में इकाई परीक्षण कैसे किया जाए और मुझे एहसास हुआ कि, हालाँकि मैं अभी भी अपने डेटा करियर की शुरुआत में हूँ, मैं पहले ही इस समस्या का सामना कर चुका हूँ और प्रत्येक मोड़ में एक अलग दृष्टिकोण था इसे हल करो। मैंने सोचा कि यह मेरे हैक्स को साझा करने के लिए उपयोगी हो सकता है ताकि मैंने जो कुछ सीखा है उसे समेकित कर सकूं, और यह भी सीख सकूं कि आपने क्या किया है और यह कैसे चला गया। शॉल वे?
लेकिन यूनिट टेस्ट SQL क्यों?
यह स्पष्ट करना महत्वपूर्ण है कि मैं यहां SQL तर्क परीक्षण पर चर्चा कर रहा हूं , डेटा का परीक्षण नहीं कर रहा हूं । परीक्षण डेटा यह सुनिश्चित कर रहा है कि स्कीमा गुणों के अनुमान, जैसे शून्यता और विशिष्टता, वास्तव में मूल्यों के लिए हैं। एक पारंपरिक RDBMS यह सुनिश्चित करेगा कि तालिका की कमी के साथ, लेकिन हमारे पास डेटा वेयरहाउस में यह सुविधा नहीं है, इसलिए हमें वास्तव में डेटासेट पर पूर्व और बाद की स्थिति को पढ़ने और जांचने की आवश्यकता है।
यूनिट टेस्टिंग एसक्यूएल यूनिट टेस्टिंग एप्लिकेशन कोड के समान है: सुनिश्चित करें कि तर्क का एक टुकड़ा इनपुट के दिए गए सेट के लिए अपेक्षित आउटपुट उत्पन्न करता है। जबकि सर्वोत्तम प्रथाएँ यह निर्धारित करती हैं कि हम लगभग सभी एप्लिकेशन कोड का परीक्षण करते हैं, चाहे वह C ++ या पायथन हो, हम शायद ही कभी SQL के साथ इस प्रयास को देखते हैं। क्यों?
मेरे लिए, उत्तर यह है कि SQL लिखना सबसे कठिन हिस्सा नहीं है । अधिकांश समय, डेटा परिवर्तन तुच्छ और दोहराव वाले होते हैं, और कठिनाई ए से बी तक जाने वाले बिट्स की तुलना में उचित रूप से मॉडलिंग डेटा में अधिक होती है। हालांकि, जब परिवर्तनों के भीतर व्यावसायिक तर्क आवश्यक होता है, तो आप आवश्यक जटिलता के साथ समाप्त हो सकते हैं जो कठिन है अलग करने के लिए - एक जटिल CASE-WHEN अभिव्यक्ति की तरह एक कॉलम उत्पन्न करने के लिए, एक चुनौतीपूर्ण सात-तरफ़ा JOIN से आने वाले इनपुट के साथ, और एक बहु-पंक्ति WHERE खंड जो एक सत्य तालिका को समझने के लिए वारंट करता है कि क्या हो रहा है ...
मेरे अनुभव में, यह सुनिश्चित करना कि तर्क केवल मैन्युअल परीक्षण और क्लाइंट साइन-ऑफ पर निर्भर है, जो 1) नाजुक और 2) लगभग आपराधिक है , यह देखते हुए कि यूनिट परीक्षण SQL के लिए कितना उपयुक्त है! जबकि ऐप्स को परिवर्तनीय स्थिति को प्रतिबंधित करने और परीक्षणों में पुनरुत्पादन सुनिश्चित करने के लिए सभी प्रकार के मचान की आवश्यकता होती है, एसक्यूएल शुद्ध और स्पष्ट है। तो क्यों न उसी बुनियादी ढांचे का उपयोग यह सत्यापित करने के लिए किया जाए कि तर्क अपेक्षित रूप से काम करता है?
पहला प्रयास: एनालिटिक्स
SQL स्क्रिप्ट की इकाई परीक्षण में मेरा पहला प्रयास तब था जब मैं Google में काम कर रहा था, आंतरिक तकनीकों जैसे Dremel और Powerdrill का उपयोग कर रहा था (आप देखेंगे कि उनकी परियोजनाओं में लॉग के साथ काम करने से संबंधित नाम थे)।
हम एक नए ऐप के लिए एक एनालिटिक्स पाइपलाइन का निर्माण कर रहे थे, उत्पाद प्रबंधकों को प्रिय मेट्रिक्स उत्पन्न करने के लिए उपयोगकर्ता लॉग को संसाधित कर रहे थे, जैसे सक्रिय उपयोगकर्ता प्रति देश या समूह। एक प्रतिनिधि प्रश्न होगा:
CREATE TABLE _7dau_by_country_platform AS
SELECT
day,
country,
platform,
COUNT(DISTINCT user_id) AS active_users
FROM UNNEST(dates) day
JOIN app_logs ON DATE(ts) BETWEEN DATE_SUB(day, INTERVAL 7 DAY) AND day
GROUP BY 1, 2, 3
एक परीक्षण ढांचे को हैक करना
हम बेहतर करना चाहते थे और यह सुनिश्चित करना चाहते थे कि हमारी स्क्रिप्ट भरोसेमंद हों, इसलिए हमने अपना टेस्ट फ्रेमवर्क बनाया:
- प्रत्येक स्रोत तालिका में एक सिंथेटिक CSV होगा, जिसमें बहुत सारे उपयोगकर्ता और कॉलम भरे होंगे। प्रत्येक नए परीक्षण मामले के लिए, हम उपयुक्त स्रोत तालिकाओं में पंक्तियाँ जोड़ेंगे।
- जब एक परीक्षण निष्पादित किया गया था, तो संपूर्ण डेटासेट डेटा वेयरहाउस में अस्थायी तालिकाओं पर अपलोड किया गया था।
- प्रत्येक स्क्रिप्ट के लिए, स्रोतों को अस्थायी रूप से अस्थायी तालिका से बदल दिया गया था, और स्क्रिप्ट को निष्पादित किया जाएगा।
- प्रत्येक स्क्रिप्ट के लिए, हमने एक अपेक्षित आउटपुट CSV बनाया और किसी भी अंतर की रिपोर्ट करते हुए वास्तविक आउटपुट के साथ इसे अलग किया।
CSV बनाना समय लेने वाला था क्योंकि हम 1-दिन, 7-दिन और 28-दिन की विंडो में सक्रिय उपयोगकर्ताओं की संख्या की गणना करने में रुचि रखते थे, इसलिए हमें केवल एक साधारण स्क्रिप्ट का परीक्षण करने के लिए लॉग इवेंट के साथ कई पंक्तियाँ बनाने की आवश्यकता होगी जो एक नया आयाम जोड़ा। हमने जितना संभव हो उतना पुन: उपयोग किया, जिसमें एक परीक्षण के लिए लिखे गए अपेक्षित आउटपुट को दूसरे के इनपुट के रूप में उपयोग करना शामिल है, अगर यह समझ में आता है।
टूट - फूट
कुछ समय बाद, एक नया टेस्ट केस जोड़ना बहुत भंगुर हो गया , क्योंकि आप संभावित रूप से किसी भी अन्य टेस्ट को प्रभावित कर सकते हैं! यदि परीक्षण A को सापेक्ष आवृत्ति की गणना करने की आवश्यकता है, और उसके लिए COUNT (*) के साथ सभी पंक्तियों की गणना की जाती है, जिस क्षण हमने परीक्षण B के लिए "सुनहरा" डेटासेट में एक नई पंक्ति जोड़ी, परीक्षण A से अपेक्षित आउटपुट टूट जाएगा।
बहुत आह भरने के बाद, हम बुलेट को थोड़ा सा करते हैं और गोल्डन डेटासेट को प्रति स्क्रिप्ट एक डेटासेट में विभाजित करते हैं । यह अभी भी सही नहीं था क्योंकि हमने प्रति स्क्रिप्ट में कई परीक्षण मामले जोड़े, लेकिन अधिक प्रबंधनीय हो गए। इसके साथ हमने सीखा:
- जितना हो सके आइसोलेशन टेस्ट करें । एक इकाई परीक्षण का मूल्य होता है क्योंकि यह टूट जाता है जब एक घटक धारणा अब पकड़ में नहीं आती है। इसे तोड़ना क्योंकि कुछ असंबंधित परीक्षण ने साझा वातावरण को बदल दिया है, उपयोगी नहीं है।
- सीएसवी एक भयानक फ़ाइल स्वरूप है । गंभीरता से। यदि हम यह परीक्षण करना चाहते हैं कि लॉजिक एक खाली स्ट्रिंग बनाम एक NULL स्ट्रिंग के साथ कैसे व्यवहार करता है, तो हमें अपलोड चरण में एक विशेष मूल्य और रूपांतरण तर्क पेश करना होगा। कोई आश्चर्य नहीं कि pandas.read_csv के पास उन सभी मामलों को संभालने के लिए 52 तर्क हैं जिन्हें CSV मानकीकृत करने में विफल रहता है।
- हालांकि परीक्षण सरलता और स्पष्टता से लाभान्वित होते हैं, सिंथेटिक डेटा बहुत अधिक शब्दाडंबरपूर्ण होता है और यह पता लगाना कठिन बनाता है कि एक परीक्षण से दूसरे परीक्षण में क्या भिन्न है। हम यह स्पष्ट करने के लिए टिप्पणियों पर बहुत अधिक निर्भर थे कि प्रत्येक पंक्ति और परीक्षण मामले का इरादा क्या था (फिर से, CSV में कुछ मानकीकृत नहीं)।
दूसरा प्रयास: JSON के साथ क्लाइंट साइन-ऑफ़
अपने दूसरे अनुभव में, मैं ज़ूप इनोवेशन में एक डेटा इंजीनियर सलाहकार के रूप में काम कर रहा था, जो लैटिन अमेरिका के सबसे बड़े बैंक इटाउ में एक टीम को आवंटित किया गया था। हम एक ऑन-प्रिमाइसेस Hadoop परिनियोजन के साथ काम कर रहे थे।
यहां काम का प्रकार एनालिटिक्स से बहुत अलग था, जिसमें ज्यादातर फ्लैटिंग और डिडुप्लिकेटिंग रिकॉर्ड शामिल थे। पिछले एक के आउटपुट के आधार पर दिए गए परिवर्तन के आउटपुट के साथ, स्क्रिप्ट से प्राप्त मुख्य चुनौती वृद्धिशील है। हम आमतौर पर दो चरणों में इसका परीक्षण करते हैं: हमने T0 को बिना किसी पिछली स्थिति के एक रन कहा, और T1 को T0 पर एक रन बिल्डिंग कहा।
पहले की तरह, हम केवल परिनियोजन के बाद ही बग खोजने से पीड़ित थे, और यह सुनिश्चित करना चाहते थे कि विकास के दौरान सभी कोने के मामले कवर किए गए थे। व्यापार विश्लेषक टीम ने उनमें से प्रत्येक के लिए परीक्षण मामलों की एक विस्तृत सूची तैयार की, जिसमें यह निर्दिष्ट किया गया था कि क्या एक कॉलम का मूल्य अच्छा या बुरा होगा, और अपेक्षित आउटपुट क्या था। ध्यान दें कि ये केवल एक टेबल पर विवरण थे, लेकिन फिर भी पैरामीट्रिज्ड टेस्ट के काफी करीब थे ।
मुख्य कठिनाई परीक्षण मामलों की इस सूची का वास्तविक Hadoop इनपुट में अनुवाद करना था! सबसे पहले हमारे पास निम्नलिखित प्रक्रिया थी:
- हमने एक साझा एक्सेल फ़ाइल बनाई जहां प्रत्येक टैब एक टेबल था, या तो पहले (T0) या दूसरे रन (T1) से। प्रत्येक परीक्षण का मामला प्रत्येक तालिका में 0-2 पंक्तियाँ बन जाएगा।
- हम प्रत्येक T0 टेबल को CSV के रूप में आउटपुट करते हैं, कॉस्मेटिक ट्रांसफ़ॉर्म करते हैं, उन्हें Hadoop पर अपलोड करते हैं और SQL स्क्रिप्ट को निष्पादित करते हैं। T0 आउटपुट एकत्र किया जाता है।
- हम प्रत्येक T1 टेबल को CSV के रूप में आउटपुट करते हैं, कॉस्मेटिक ट्रांसफ़ॉर्म करते हैं, उन्हें Hadoop पर अपलोड करते हैं और SQL स्क्रिप्ट को निष्पादित करते हैं। T1 आउटपुट एकत्र किया जाता है।
टेबल जनरेटर को हैक करना
इन त्रुटियों के कारण आगे-पीछे निराश होकर, मैंने एक छोटा सिंथेसाइज़र टूल बनाया, जो एक टेस्ट केस का वर्णन करने वाली JSON फ़ाइलों को इनपुट के रूप में लेगा , और फिर उन सभी तालिकाओं को आउटपुट करेगा जिनकी हमें एक बार में आवश्यकता थी । पहले मुझे आशा थी कि इसका उपयोग eng और QA टीमों द्वारा किया जाएगा, लेकिन व्यापार विश्लेषकों में से एक तकनीकी रूप से जानकार था और JSON को समझता था, और अपने स्वयं के परीक्षण मामलों को इस प्रारूप में बदलने में मदद की! टेस्ट केस वाली फाइल इस तरह दिखती है:
{
"companies_t0": [
{"company_id": "001-3", "company_name": "ACME Inc."},
{"company_id": "002-9", "company_name": "Umbrella LLC"}
],
"companies_t1": [
{"company_id": "001-3", "company_name": "ACME Inc."}
],
"associates_t0": [
{"company_id": "001", "person_id": "p01"},
{"company_id": "001", "person_id": "p02"},
{"company_id": "002", "person_id": "p02"}
],
"associates_t1": [
{"company_id": "001", "person_id": "p01"},
{"company_id": "001", "person_id": "p02"},
{"company_id": "002", "person_id": "p02"}
],
"persons": [...]
}
उपकरण ने प्रत्येक परीक्षण मामले से सभी पंक्तियों को एकत्र किया और कंपनियों_t0.csv, companies_t1.csv, आदि फाइलें बनाईं, जिन्हें तब Hadoop पर अपलोड किया गया था। जब किसी त्रुटि का पता चलता है, तो हम JSON फ़ाइल को छोड़ सकते हैं और जाँच सकते हैं कि क्या यह टेस्ट केस कोड में एक गलती थी, जो कि कई एक्सेल टैब के भीतर विशिष्ट पंक्ति की तलाश करने की तुलना में करना बहुत आसान था जो किसी दिए गए टेस्ट केस को प्रभावित कर सकता था। .
इस टूल की एक अन्य विशेषता प्रत्येक पंक्ति को किसी दिए गए टेम्प्लेट से "इनहेरिट" कॉलम की अनुमति दे रही थी। इसने परीक्षण मामलों को पढ़ने में सुखद बना दिया, क्योंकि उनमें केवल उनके लिए प्रासंगिक कॉलम शामिल थे।
नए पाठ
मैं यह नहीं कह सकता कि यह उपकरण सफल रहा। सबसे पहले, कुछ लोगों ने इसे अपनाया, और मुझे इंजीनियरों और क्यूए के साथ बेहतर संवाद करना चाहिए था कि यह समग्र प्रक्रिया में कैसे फिट हो सकता है। दूसरा, इसने नए मैन्युअल त्रुटि अवसरों की शुरुआत की, जैसे डुप्लिकेट आईडी के साथ मामले बनाना, कॉपी-पेस्ट पर कॉलम अपरिवर्तित छोड़ना, या सीधे उनके JSON पूर्वजों के बजाय CSV फ़ाइलों को संपादित करना।
इससे मुझे निम्नलिखित सीख मिलीं:
- व्यवसाय उन मामलों में सोचता है जो तालिकाओं को फैलाते हैं, और कोड उन तालिकाओं में सोचते हैं जिनमें परीक्षण मामले होते हैं । टेस्ट हार्नेस बनाते समय उनके बीच एक ट्रांसपोज़ किया जाना है।
- क्लाइंट से आपके लिए टेस्ट केस लिखना सोना है । डोमेन विशेषज्ञ से बेहतर कोई नहीं जानता कि प्रासंगिक इनपुट और अपेक्षित आउटपुट क्या हैं! वे हर एज केस के बारे में नहीं सोच सकते हैं जिसे कोड को संभालने की जरूरत है, लेकिन वे मुश्किल परिवर्तनों पर मुट्ठी भर परीक्षण मामलों के साथ अंतर्दृष्टि प्रदान कर सकते हैं। इसके अलावा, उनके साथ इनपुट-आउटपुट की एक साझा भाषा स्थापित करने से आपको बाद में उन एज केसों को संप्रेषित करने में मदद मिलती है!
- सभी परीक्षण मामलों को एक साथ चलाने से जाँच करना और डीबग करना कठिन हो जाता है । हमें परिणामों को वापस परीक्षण मामलों में मैप करने और उन्हें जांचने के लिए यूजर आईडी-टेस्ट केस के बीच मैपिंग रखनी थी। हमने "इन-बैंड" डेटा को टैग करते हुए यूजर आईडी में टेस्ट केस नंबर जोड़ने की कोशिश की, लेकिन यह अमान्य आईडी के साथ और अधिक समस्याएं लेकर आया। यह बेहतर होगा कि या तो प्रत्येक मामले को अलग से चलाया जाए, या यह ट्रैक करने का एक तरीका हो कि दिए गए आउटपुट किस मामले से मेल खाते हैं।
- जेएसओएन इंसानों के लिए एक अच्छा प्रारूप नहीं है। उपरोक्त उदाहरण में, यह स्पष्ट नहीं है कि क्या परीक्षण किया जा रहा है, और JSON टिप्पणियों को इसकी व्याख्या करने की अनुमति नहीं देता है। हां, हम एक
"_comment": "blah"क्षेत्र का उपयोग कर सकते हैं, लेकिन यह एक हैक है जिसे सीएसवी में रूपांतरण में पूर्ववत करने की आवश्यकता है। साथ ही, अल्पविरामों का ट्रैक रखना और ऑब्जेक्ट कुंजियों को उद्धृत करना हल्का रूप से क्रुद्ध करने वाला है । - पंक्ति टेम्पलेट पठनीयता में बहुत सुधार करते हैं। हालाँकि हम चाहते हैं कि परीक्षण बहुत स्पष्ट हों और थोड़े छिपे तर्क के साथ, अबाध स्तंभों को भरने के लिए एक टेम्पलेट का उपयोग करने से उन मानों के बीच के अंतरों को खोजने में बहुत मदद मिलती है जो वास्तव में परीक्षण मामले के लिए महत्वपूर्ण हैं ।
यह तीसरा और अंतिम अनुभव मेरे पिछले नियोक्ता चेर्रे के साथ हुआ, जो रियल एस्टेट कंपनियों के लिए डेटा कनेक्शन प्रदान करता है। हम ज्यादातर डीबीटी का इस्तेमाल ड्रेमेल की व्यावसायिक पेशकश गूगल बिगक्वेरी में बदलाव लिखने के लिए करते हैं। एक ग्राहक ने अनुरोध किया था कि हम तर्क को बहुत संशोधित करें (शुक्र है, इसे आसान बना रहे हैं!), और हम यह सुनिश्चित करना चाहते थे कि हम कोई अनपेक्षित परिवर्तन नहीं करेंगे।
डीबीटी मॉडल का पुन: उपयोग करना
चूंकि मौजूदा तर्क का इकाई परीक्षण नहीं किया गया था, इसलिए मैंने एक स्मोक टेस्ट के साथ शुरुआत की , जो केवल इनपुट बना रहा है और यह सुनिश्चित कर रहा है कि उनके साथ कुछ भी टूट न जाए। परीक्षण के तहत मॉडल का निर्भरता ग्राफ गहरा था, ~ 20 स्रोतों में समाप्त हो रहा था, इसलिए स्रोत द्वारा स्रोत का मजाक उड़ाना सिरदर्द होगा। इसके बजाय, मैंने एक उपयुक्त DAG कटऑफ चुना और केवल ~ 7 रेफरी को सिंथेटिक डेटा के साथ बदल दिया, जिसे SQL के साथ ही बनाया गया था :
WITH
-- Synthetic sources
foo AS (
-- Test case 1, active foo
SELECT "i001" AS foo_id, 200_000 AS foo_value, TRUE AS is_active,
UNION ALL
-- Test case 2, inactive foo without any bar
SELECT "i002" AS foo_id, 240_000 AS foo_value, FALSE AS is_active,
),
bar AS (
-- Test case 1, active foo with two bars
SELECT "b001" AS bar_id, 451.40 AS bar_value, "i001" AS foo_id
UNION ALL
SELECT "b002" AS bar_id, 123.98 AS bar_value, "i001" AS foo_id
),
-- From now on, everything should be left the same as the DBT model.
model_x AS (
SELECT ...
FROM foo
JOIN bar USING (foo_id)
)
इनपुट और आउटपुट को बेहतर ढंग से देखने और साझा करने के लिए, मैंने सीटीई में से प्रत्येक के लिए स्क्रिप्ट की एक प्रति बनाई है (यानी, प्रत्येक इंटरमीडिएट टेबल) और SELECT * FROM <cte>अंत में संलग्न है। मैंने तब प्रत्येक प्रति को निष्पादित किया, प्रत्येक मध्यवर्ती परिवर्तन के लिए एक CSV प्राप्त किया - foo.csv, bar.csv, model_x.csv, आदि। इसने DAG के प्रत्येक चरण को डीबग करने में मदद की, साथ ही गैर-तकनीकी के साथ साझा करने का एक तरीका प्रदान किया। लोग CSV प्रारूप में कुछ सिंथेटिक इनपुट दिए जाने पर तर्क परिवर्तनों के परिणाम क्या होंगे।
सीमित लाभ
अंत में, यह परीक्षण यह सुनिश्चित करने में सफल रहा कि हम तर्क परिवर्तन के साथ कोई त्रुटि नहीं जोड़ेंगे, क्योंकि मौजूदा और नए तर्क के लिए समान इनपुट का उपयोग किया गया था। इसने हमें सिंथेटिक डेटा के साथ इसे पुन: पेश करने की अनुमति देकर बाद में उत्पादन के मुद्दे को डीबग करने में भी मदद की। दुर्भाग्य से, चूंकि इसे एक विशिष्ट उद्देश्य के लिए बनाया गया था, इसलिए हमने इसे अन्य मॉडलों में परीक्षण लिखने के लिए सामान्यीकृत करने का प्रयास नहीं किया।
अब तक के मुख्य सबक ये रहे हैं:
- SQL सिंथेटिक डेटा घोषित करने के लिए कम से कम प्रतिरोध बेमेल विकल्प है। शुद्ध एसक्यूएल में सिंथेटिक डेटा लिखने से हमें कास्टिंग, एनयूएलएल, टिप्पणियां, पठनीयता के बारे में चिंता करने की ज़रूरत नहीं है ... क्योंकि भाषा सिंटैक्स पहले से ही उन्हें प्रदान करता है!
- रेफरी का मज़ाक उड़ाना महत्वपूर्ण है। एसक्यूएल लॉजिक का सबसे जटिल हिस्सा एक बड़े डीएजी के अंत में बैठता है, और प्रत्येक स्रोत का उपहास करना प्रतिकूल होता। नकली स्रोत, हम सभी मध्यवर्ती मॉडलों का परीक्षण करने में सक्षम होंगे ... लेकिन मैं उन सभी का परीक्षण नहीं करना चाहता था , केवल दिलचस्प!
- परीक्षण मामलों द्वारा पंक्तियों को समूहीकृत करना तालिका की तुलना में बेहतर है। मैंने इसे पिछले अनुभव में पहले ही सीख लिया था, लेकिन केवल यह दोहराना चाहूंगा कि SQL में टिप्पणियों के साथ लिखित परीक्षण मामलों में भी, मामलों को पढ़ने और आउटपुट से परीक्षणों तक बैकट्रैकिंग करते समय कुछ संदर्भ अभी भी खो गए हैं।
मुझे नहीं पता कि हम इकाई परीक्षण SQL के लिए एक सही समाधान तक पहुँच सकते हैं या नहीं, लेकिन हम अभी भी इसके बारे में सपना देख सकते हैं:
- टेस्ट केस आइसोलेशन में चलेंगे;
- प्रत्येक आउटपुट इंगित करेगा कि यह किस मामले से आया है;
- अरुचिकर स्तंभों को स्वत: भरा और/या अनदेखा किया जा सकता है;
- सभी तर्कों का पुन: उपयोग किया जाता है, परीक्षण के लिए कोई अनुकूलन आवश्यक नहीं होगा;
- निर्भरता ग्राफ कटऑफ बिंदु मनमाना हो सकता है;
- परीक्षण मामलों और उनके परिणामों को समझा जा सकता है — और लिखने योग्य — डोमेन विशेषज्ञ/व्यवसाय विशेषज्ञ द्वारा;
उपसंहार
बस इतना ही, पढ़ने के लिए धन्यवाद! यदि आप यहां तक पहुंचे हैं, तो कृपया 10 तालियां छोड़ें ताकि इस लेख को आप जैसे अन्य लोगों द्वारा देखा जा सके। सबसे महत्वपूर्ण बात, कृपया डेटा इंजीनियरिंग में इकाई परीक्षण के साथ अपने पिछले अनुभव साझा करें, मैं अभी अभी शुरुआत कर रहा हूँ और किसी भी रिपोर्ट का स्वागत है!
आपकी उपलब्धता और इस पोस्ट के मसौदों की समीक्षा के लिए डेविड बैरर, ब्रूनो सैंटोस और रोड्रिगो डोनिज़ेट्टी का धन्यवाद।

![क्या एक लिंक्ड सूची है, वैसे भी? [भाग 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































