W
WisyLink
उत्पादमूल्य निर्धारणAPIब्लॉगसंपर्क
सभी पोस्ट

WisyLink ब्लॉग

spec-driven-developmentexecutable-specificationssource-of-truthcode-generationintent-versioning

स्पेक-निर्देशित विकास: जब स्पेक उत्पाद बन जाता है

स्पेक-निर्देशित विकास में निष्पाद्य स्पेक स्रोत-सत्य बन जाता है और कोड उसे पुनरुत्पादित की जा सकने वाली प्रस्तुति बन जाता है—जब टीमें लाइनों की बजाय इरादे की मालिक होती हैं तो क्या बदलता है।

16 जून 20268 मिनट पढ़ें
स्पेक-निर्देशित विकास: जब स्पेक उत्पाद बन जाता है

स्पेक-निर्देशित विकास वह अनुशासन है जिसमें निष्पाद्य स्पेक को एक प्राथमिक आर्टिफैक्ट के रूप में माना जाता है जिसे टीम अपने पास रखती है, और कोड उस इरादे की निचली परत के रूप में जेनरेट किया जाता है। जब स्पेक में इतना परिशुद्ध विवरण होता है कि वह कार्यान्वयन को पुनरुत्पादित कर सके, तो स्पेक स्रोत-सत्य बन जाता है — वही चीज़ जिसे मनुष्यों द्वारा संस्करणित, समीक्षा और बहस किया जाता है — जबकि कोड उससे नीचे एक व्युत्पन्न, बदली जा सकने वाली परत बन जाता है।

  • स्पेसिफिकेशन दीर्घकालिक आर्टिफैक्ट बन जाती है; कोड उसका पुनरुत्पाद्य प्रोजेक्शन बन जाता है।
  • समीक्षा ऊपर की ओर सरकती है, कार्यान्वयन के डिफ्स से लेकर इरादे के डिफ्स तक।
  • पुनरुत्पादन की निर्धार्यता किसी भी एक आउटपुट की सुंदरता से अधिक महत्वपूर्ण हो जाती है।
  • जब इरादा उस चल रही चीज़ से अलग हो जाता है जिसे चलाना है, तो स्पेसिफिकेशन अपना खुद का ऋण जमा कर लेती है।
  • स्पेक का संस्करण बदलने से सिस्टम के अंदर "एक बदलाव" का मतलब भी बदल जाता है।
  • जैसे-जैसे सिस्टम बढ़ते हैं, स्पेसिफिकेशनों के बीच की सीमाएँ कोड के टूटने से पहले खिंचती हैं।

क्यों स्पेसिफिकेशन, न कि कोड, स्रोत-सत्य बन जाता है

एक निष्पाद्य स्पेसिफिकेशन उस व्यवहार का वर्णन होता है जो इतना सटीक होता है कि एक जेनरेटर उससे बिना अतिरिक्त मानवीय लेखन के एक कार्यशील कार्यान्वयन उत्पन्न कर सके। यह बदलाव शांत लेकिन संरचनात्मक होता है। दशकों तक कोड वह आर्टिफैक्ट रहा जो बना रहता था; टिप्पणियाँ, डिजाइन डाक्यूमेंट और टिकट उसके आसपास सड़ते गए, और चल रहा प्रोग्राम ही इस बात का ईमानदार रिकॉर्ड रहा कि सिस्टम ने क्या किया। स्पेक-फर्स्ट उस रिश्ते को उल्टा कर देता है।

जब इरादा किसी ऐसी चीज़ के रूप में कब्जा हो जाता है जिसे मशीन भी चलाकर जाँच सके, तो स्पेसिफिकेशन दस्तावेज़ीकरण रहना बंद कर देती है और संपत्ति बन जाती है। कोड उससे जेनरेट होता है, और किसी भी पल मौजूद कार्यान्वयन कई वैध प्रोजेक्शनों में से एक होता है। जो चीज़ पुनरुत्पादन के पार बनी रहती है वह स्पेक है। यही बदलाव का सार है: रिपॉज़िटरी में सबसे टिकाऊ चीज़ अब सबसे विस्तृत चीज़ नहीं रहती।

यह अक्सर मालिकाना ढांचे को पुनर्गठित करता है। समीक्षा में जिस आर्टिफैक्ट की कोई व्यक्ति रक्षा करता है वह व्यवहार का बयान होता है, न कि उसे संतुष्ट करने वाली लाइन्स। जो टीम यह आत्मसात कर लेती है वह जेनरेटेड कोड को कीमती मानना बंद कर देती है और उसे मौसम की तरह मानना शुरू कर देती है — मौजूद, प्रभावशाली और बदलने की उम्मीद के साथ। किसी फ़ंक्शन को हाथ से पॉलिश करने की प्रवृत्ति फीकी पड़ जाती है, क्योंकि वह पॉलिश अगले पुनरुत्पादन में मिट सकती है।

जब समीक्षा कोड से इरादे की ओर जाती है तो क्या बदलता है

एक बार स्पेक स्रोत-सत्य बन जाने पर, समीक्षा का गुरुत्वाकर्षण भी उसके साथ चलता है। समीक्षक अब कार्यान्वयन डिफ्स को लाइन-बाय-लाइन पढ़ना बंद कर देते हैं और स्पेसिफिकेशन में हुए परिवर्तनों को पढ़ना शुरू कर देते हैं — व्यवहार में जोड़, कड़े किए गए प्रतिबंध, हटाए गए धारणाएँ। कार्यान्वयन डिफ आउटपुट बन जाता है जिसे स्पॉट-चेक किया जाता है न कि उसे विस्तार से जाँचा जाता है।

यह उतना आसान नहीं है जितना लगता है। एक स्पेसिफिकेशन डिफ अक्सर छोटा दिखता है जबकि उसके नीचे पुनरुत्पादित कोड काफी बदल जाता है। व्यवहारिक खंड में जो एक वाक्य जोड़ा गया हो, वह सैकड़ों जेनरेटेड लाइनों में लहरें पैदा कर सकता है। समीक्षक बिना हर प्रोजेक्टेड लाइन पढ़े ही एक इरादे बदलाव के ब्लास्ट रेडियस के बारे में तर्क करना सीखते हैं, जो कि कोड पढ़ने से अलग कौशल है और इसे विकसित करने में समय लगता है।

एक ट्रेडऑफ़ जो सामने आता है वह है ट्रेसबिलिटी। जब जेनरेटेड कोड में कोई दोष आता है, तो सवाल अब यह नहीं रहता कि "इस लाइन को किसने लिखा" बल्कि यह होता है कि "किस स्पेसिफिकेशन क्लॉज़ ने इसे उत्पादित किया।" स्पेक-फर्स्ट अभ्यास करने वाली टीमें दोषों को वापस इरादे तक ट्रेस करने की आदत बनाती हैं, फिर तय करती हैं कि स्पेक गलत था या जेनरेटर ने सही स्पेक को गलत तरह से पढ़ा। दूसरी स्थिति अपनी तरह की बग है — फिडेलिटी फेलियर — और इसका हाथ-लिखे कोड में कोई समतुल्य नहीं होता।

पुनरुत्पादन की निर्धार्यता कैसे तय करती है कि स्पेक पर भरोसा किया जा सकता है या नहीं

एक स्पेसिफिकेशन के स्रोत-सत्य के रूप में काम करने के लिए, पुनरुत्पादन इतना पूर्वानुमेय होना चाहिए कि उस पर भरोसा किया जा सके। यदि वही स्पेक हर बार भिन्न-भिन्न कार्यान्वयन देता है, तो स्पेक वास्तव में स्रोत-सत्य नहीं है — बल्कि जेनरेटर की मूड हो जाती है। इसलिए यह अनुशासन निर्धार्यता पर भारी जोर देता है: स्थिर आउटपुट, पिन किए गए जेनरेशन व्यवहार, और ऐसे टेस्ट जो प्रोजेक्शन को इरादे के साथ बांध दें।

यहाँ एक स्पेक्ट्रम है। उत्साही (eager) पुनरुत्पादन हर महत्वपूर्ण स्पेक परिवर्तन पर कार्यान्वयन को फिर से बनाता है और कोड को पूरी तरह नष्ट होने योग्य मानता है। आलसी (lazy) पुनरुत्पादन एक जेनरेटेड बेसलाइन रखता है और केवल उन हिस्सों को फिर से प्रोजेक्ट करता है जिन्हें बदलाव छूता है। दोनों के अपने खर्च होते हैं, और विकल्प आम तौर पर टीम की पसंद से अधिक सिस्टम के आकार से प्रकट होता है।

गुणतात्कालिक पुनरुत्पादनआलसी पुनरुत्पादन
कोड की स्थायित्वपूरी तरह नष्ट-योग्य; संपूर्ण पुनर्निर्माणपरिवर्तनों के बीच आंशिक रूप से संरक्षित
ड्रिफ्ट का जोखिमकम; आउटपुट हमेशा स्पेक के साथ रहता हैउच्च; पुराने हिस्से लटके रह सकते हैं
प्रति बदलाव लागतउच्च कंप्यूटेशन, कम तर्क-वितर्ककम कंप्यूटेशन, अधिक तर्क-वितर्क
विफलता का तरीकापूरे-सिस्टम के आश्चर्यस्थानीय असंगतियाँ

किसी भी छोर को सैद्धान्तिक रूप से सही कहना ठीक नहीं है। छोटे सिस्टम उत्साही पुनरुत्पादन को सस्ते में सहन कर लेते हैं और उसके आश्वासन से लाभ उठाते हैं कि आउटपुट हमेशा स्पेक के अनुरूप रहेगा। बड़े सिस्टम अक्सर सब कुछ फिर से प्रोजेक्ट करने की सुविधा नहीं रखते और आलसी रणनीतियों की ओर झुकते हैं, जो स्पेक-फर्स्ट से हटने वाली कुछ अलगाव दुहराव फिर से लाती हैं जिसे हटाना था।

स्पेसिफिकेशन अपने तरह का ऋण कहाँ जमा करती है

स्पेसिफिकेशन ऋण वह गैप है जो तब खुलता है जब लिखित इरादा उस व्यवहार से मेल नहीं खाता जिसकी वास्तव में सिस्टम को आवश्यकता होती है। यह स्पेक-फर्स्ट का विरासत-कोड का समकक्ष है, और यह परिचित तरीकों से जमा होता है। क्लॉज़ एक-दूसरे के विरोधी बन जाते हैं। एज केस अपवाद के रूप में जोड़े जाते हैं बजाय मॉडल में समाहित किए जाने के। स्पेसिफिकेशन जमा होकर इतनी बढ़ जाती है कि उसका पूरा आकार किसी एक व्यक्ति के लिए रख पाना मुश्किल हो जाता है।

यह विफलता उलझे हुए कोड से भी अधिक सूक्ष्म होती है क्योंकि एक स्पेसिफिकेशन साफ़-सुथरी दिख सकती है जबकि वह असंगत इरादे को एन्कोड कर रही होती है। अच्छा स्वरूपित स्पेक मौन विरोधाभासों के पीछे छिप सकता है और फिर भी आत्मविश्वास से गलत आउटपुट जेनरेट कर सकता है। समीक्षक उस गद्य से मोहक हो सकते हैं जो जानबूझकर लगती है, और जेनरेटर किसी विरोधाभास पर कंपाइलर की तरह आपत्ति नहीं उठाता जैसा कि वह टाइप एरर पर करता है।

स्पेसिफिकेशन ड्रिफ्ट
लिखित इरादे और व्यवहार के बीच धीरे-धीरे बढ़ती हुई विचलन जो सिस्टम को वास्तव में चाहिए।
प्रोजेक्शन फिडेलिटी
इस बात की डिग्री कि जेनरेटेड कोड कितनी सच्चाई से स्पेसिफिकेशन को साकार करता है बिना व्यवहार जोड़ने या छोड़ने के।
इरादे सतह
उन क्लॉज़ और प्रतिबंधों का समुच्चय जिन्हें सिस्टम व्यवहार को जानबूझकर बदलने के लिए छुआ जाना चाहिए।

इस ऋण का प्रबंधन करने का अर्थ है स्पेसिफिकेशनों को उसी तरह रिफैक्टर करना जैसे टीमें कभी कोड को रिफैक्टर करती थीं: क्लॉज़ को समेकित करना, मृत प्रतिबंध हटाना, और मॉडल को नाम देना ताकि उसका आकार बढ़ते समय पठनीय बना रहे। यह काम आकर्षक नहीं है और आसान से टाला जा सकता है, और इसे टालना ही वह तरीका है जिससे एक साफ़ स्पेक अपारदर्शी बन जाती है।

एक जानबूझकर स्पेक-फर्स्ट बदलाव आम तौर पर कैसे आगे बढ़ता है

एक परिपक्व स्पेक-फर्स्ट वर्कफ़्लो में ऑपरेशनों का क्रम अक्सर एक सुसंगत आकार का अनुसरण करता है, क्षेत्र चाहे जैसा भी हो। अनुक्रम स्पेसिफिकेशन को अधिकृत रखता है और जेनरेटेड कोड को चुपचाप स्पेक से प्रतिस्पर्धा करने वाले दूसरे स्रोत-सत्य बनने से रोकता है। मायने यह नहीं रखता कि कदम बिल्कुल कैसे हों बल्कि यह कि हर कदम किस दिशा में इशारा करता है: परिवर्तन इरादे के माध्यम से अंदर आते हैं और कभी भी उल्टा नहीं।

  1. व्यवहारिक बदलाव को कोड संपादन के रूप में नहीं बल्कि स्पेसिफिकेशन में संशोधन के रूप में बताइए।
  2. नए इरादे को ऐसे प्रतिबंधों और उदाहरणों के रूप में एन्कोड कीजिए जिन्हें जेनरेटर और टेस्ट सूट दोनों पढ़ सकें।
  3. प्रभावित प्रोजेक्शन को पुनरुत्पादित कीजिए और बाइंडिंग टेस्ट से फिडेलिटी की पुष्टि होने दीजिए।
  4. लाइन-डिफ की बजाय व्यवहार के डिफ का निरीक्षण कीजिए, और उसे बताए गए इरादे के खिलाफ मिलाइए।
  5. किसी भी आश्चर्य को वापस स्पेक में मोड़ दीजिए ताकि अगली बार पुनरुत्पादन वह सबक ले कर आए।

अनुशासन कदम पाँच में रहता है। जब पुनरुत्पादन आपको चौंकाता है, तो प्रलोभन होता है कि आउटपुट को हाथ से पैच कर दिया जाए। हर वह हैंड-पैच जो स्पेसिफिकेशन पर लौट कर नहीं आता, वह स्पेक-फर्स्ट द्वारा बंद किए गए गैप को फिर से खोल देता है, और स्पेक चुपचाप सत्य होना बंद कर देता है। पैच की हुई लाइन आज काम कर सकती है और कल झूठ बोलेगी, जैसे ही कुछ ताज़ा पुनरुत्पादन ट्रिगर हो। जो टीमें अनुशासन बनाए रखती हैं वे एक आश्चर्यजनक प्रोजेक्शन को इशारा समझती हैं कि इरादा अपर्याप्त रूप से निर्दिष्ट था, और वे आउटपुट को डाउनस्ट्रीम ओवरराइड करने के बजाय यह कहने का श्रम उठाती हैं कि उन्होंने क्या मतलब रखा था—अधिक स्पष्टता के साथ।

मॉडल कहाँ खिंचता है जब सिस्टम बड़े होते हैं

छोटे पैमाने पर, एक ही स्पेसिफिकेशन पूरे सिस्टम को आराम से रख सकती है और पुनरुत्पादन सस्ता होता है। खिंचाव सीमाओं पर प्रकट होता है। बड़े सिस्टम एक स्पेसिफिकेशन नहीं होते बल्कि कई स्पेसिफिकेशनों का संग्रह होते हैं, और स्पेसिफिकेशनों के बीच के अनुबंध नाजुक सतह बन जाते हैं — वही जगह जहाँ सामान्य आर्किटेक्चर भी विफल होते हैं, पर अब एक स्तर ऊपर, इरादे की भाषा में न कि इंटरफेसेस में।

सीमित संयोजन (bounded composition), जहाँ प्रत्येक स्पेसिफिकेशन का एक स्पष्ट इंटरफ़ेस होता है और वह स्वतंत्र रूप से पुनरुत्पादित होती है, सामान्यतः स्केल करती है। असीमित संयोजन (unbounded composition), जहाँ स्पेसिफिकेशन एक-दूसरे की धारणाओं तक पहुँचते हैं, ऐसे पुनरुत्पादन पैदा करता है जो व्यक्तिगत रूप से वैध होते हैं पर सामूहिक रूप से असंगत। कपलिंग कोड से इरादे में चली जाती है, और इरादे की कपलिंग देखना कठिन होता है क्योंकि किसी एक स्पेक में कुछ भी गलत नहीं दिखता।

दूसरा खिंचाव मानव है। ऐसी स्पेसिफिकेशन जो किसी एक पाठक से बड़ी हो जाएँ, अपने आप में एक प्रकार की अपारदर्शी विरासत बन जाती हैं, और स्पेक पठनीय, मालिकाना आर्टिफैक्ट होने का वादा कमजोर पड़ जाता है। स्पेसिफिकेशनों को पर्याप्त छोटा रखना ताकि उन पर तर्क किया जा सके, यह पहला-स्तरीय चिंता बन जाती है, न कि केवल एक शैलीगत पसंद, और जो टीमें इसे नजरअंदाज़ करती हैं वे उसी धुंध को फिर से पैदा करती हैं जिसे उन्होंने छोड़ दिया था। वही विघटन का अनुशासन जो कभी कोड पर लागू होता था अब इरादे पर लागू होता है, और चेतावनी वही रहती है: गलत सीमा बनाना उसे न बनाने से भी अधिक महंगा साबित होता है।

जैसा कि स्पेक उत्पाद बन कर कठोर होती है, यह क्षेत्र किस तरफ बढ़ रहा है

दिशा इस ओर इशारा करती है कि स्पेसिफिकेशन को शिप किए गए उत्पाद की तरह माना जाएगा और कोड बिल आउटपुट की तरह — जैसे दशकों पहले कंपाइल किए बाइनरीज़ को नीचे कर दिया गया था। जैसे-जैसे यह बैठता है, कठिन समस्याएँ ऊपर की ओर सरक जाती हैं। इरादे का संस्करणन, व्यवहार का डिफिंग, और प्रतिबंधों की समीक्षा रोज़ का शिल्प बन जाते हैं, जबकि जेनरेटेड कार्यान्वयन पढ़ना एक आवधिक, डायग्नोस्टिक कृति बनकर रह जाता है जब फिडेलिटी टूटती है। टूलिंग भी गुरुत्वाकर्षण के केंद्र के साथ जाएगा, और जिन आर्टिफैक्ट्स पर एक टीम गर्व करेगी वे साफ़, पठनीय स्पेसिफिकेशन होंगे न कि उनके नीचे का चतुर कोड।

जो चीज़ कठिन हो जाएगी वह अर्थ की शासन-व्यवस्था है। जब स्पेक उत्पाद हो, तो यह प्रश्न कि किसको किस क्लॉज़ को बदलने की अनुमति है, और किसी इरादे बदलाव का मान्यकरण कैसे होता है इससे पहले कि वह पुनरुत्पादित हो, केंद्रीय अनुशासन बन जाता है। स्पेसिफिकेशन पर अधिकार उस शक्ति को धारण करता है जो कभी रिलीज़ ब्रांच के अधिकार के पास था, क्योंकि एक ही संपादन कहीं भी स्पेक के प्रोजेक्शन में व्यवहार को बदल सकता है।

जो सिस्टम टिके रहेंगे वे वे होंगे जो अपनी स्पेसिफिकेशनों के साथ उसी कठोरता से पेश आएँगे जो कभी प्रोडक्शन कोड के लिए आरक्षित थी — सावधानी से वर्जन्ड, गंभीरता से समीक्षा की हुई, और ईमानदार बने रहने के लिए छोटे रखी हुई। विपरीत दिशा में खिंचाव असल में वास्तविक है, क्योंकि एक स्पेक जो कार्यशील सॉफ़्टवेयर जेनरेट करती है वह यह मानने का प्रलोभन देती है कि वह सही होगी। वही धारणा वह जगह है जहाँ अगले दशक के कठिन-सीखे गए पाठ उतरेंगे, और जो टीमें इसे सबसे पहले नकारेंगी वे इन्हें सीखने में सबसे कम खर्च करेंगी।

F.A.Q.

अक्सर पूछे जाने वाले प्रश्न

स्पेक-निर्देशित विकास क्या है?
स्पेक-निर्देशित विकास एक ऐसा अनुशासन है जिसमें निष्पाद्य स्पेसिफिकेशन प्राथमिक आर्टिफैक्ट होता है जिसे टीम रखती है, और कार्यान्वयन उससे उत्पन्न किया जाता है। स्पेसिफिकेशन स्रोत-सत्य बन जाती है, जबकि कोड एक डाउनस्ट्रीम प्रोजेक्शन माना जाता है जिसे इरादे बदलने पर पुनरुत्पादित किया जा सकता है।
निष्पाद्य स्पेसिफिकेशन दस्तावेज़ीकरण से कैसे अलग है?
दस्तावेज़ीकरण सिस्टम का वर्णन उसके बनने के बाद करती है और जैसे-जैसे कोड बदलता है वह पुरानी पड़ जाती है। एक निष्पाद्य स्पेसिफिकेशन इतनी सटीक होती है कि जेनरेटर सीधे उससे एक कार्यशील कार्यान्वयन उत्पन्न कर सकता है, इसलिए स्पेसिफिकेशन अधिकृत बनी रहती है न कि एक पुराना रिकॉर्ड।
स्पेसिफिकेशन ऋण क्या है?
स्पेसिफिकेशन ऋण वह अंतर है जो तब खुलता है जब लिखित इरादा उस व्यवहार से मेल नहीं खाता जिसकी चल रही प्रणाली को वास्तव में आवश्यकता होती है। यह विरोधाभासी क्लॉज़ और जोड़-तोड़ अपवादों के रूप में जमा होता है, और उलझे हुए कोड के विपरीत यह स्वच्छ गद्य के पीछे छिपकर भी आत्मविश्वास से गलत व्यवहार जेनरेट कर सकता है।
क्या स्पेक-फर्स्ट विकास बड़े सिस्टम पर लागू होता है?
यह तब स्केल करता है जब हर स्पेसिफिकेशन का एक स्पष्ट इंटरफ़ेस हो और वह स्वतंत्र रूप से पुनरुत्पादित हो, जिससे कपलिंग दिखाई दे। यह तब तनाव में आता है जब स्पेसिफिकेशन्स एक-दूसरे की धारणाओं में घुसती हैं, क्योंकि परिणामस्वरूप पुनरुत्पादन व्यक्तिगत रूप से वैध लेकिन सामूहिक रूप से असंगत हो सकते हैं, और कपलिंग कोड से इरादे में चली जाती है।
पुनरुत्पादन की निर्धार्यता इतनी महत्वपूर्ण क्यों है?
यदि वही स्पेसिफिकेशन हर बार भिन्न-भिन्न कार्यान्वयन देता है तो जेनरेटर ही स्रोत-सत्य बन जाता है न कि स्पेक। स्थिर, पूर्वानुमेय पुनरुत्पादन और ऐसे टेस्ट जो प्रोजेक्शन को बांधते हैं, टीम को स्पेसिफिकेशन पर भरोसा करने लायक बनाते हैं कि वह सिस्टम का टिकाऊ आर्टिफैक्ट है।
शेयर करें
XLinkedInFacebook
इस पन्ने पर
  1. स्पेसिफिकेशन स्रोत-सत्य के रूप में
  2. समीक्षा इरादे की ओर चली जाती है
  3. पुनरुत्पादन निर्धार्यता और भरोसा
  4. जब स्पेसिफिकेशन ऋण जमा करती हैं
  5. एक स्पेक-फर्स्ट बदलाव का क्रम
  6. स्केल पर मॉडल कहाँ खिंचता है
  7. स्पेक का उत्पाद में कठोर होना

दस्तावेज़

  • अवलोकन
  • API
  • CLI
  • GitHub
  • npm

ब्लॉग

  • ब्लॉग देखें
  • एक ही प्रॉम्प्ट, अलग परिणाम: उत्पादन में पुनरुत्पादकता
  • मशीन-जनित मीडिया की उत्पत्ति का प्रमाण
  • संदर्भ इंजीनियरिंग: प्रॉम्प्ट पॉलिशिंग से सूचना वास्तुकला की ओर संक्रमण
  • टूल उपयोग करने वाले एजेंट: उत्तर से कार्रवाई तक की कृत्रिम बुद्धिमत्ता

कानूनी

  • गोपनीयता
  • शर्तें
  • कंपनी

उत्पाद

  • क्षमताएं
  • मूल्य निर्धारण
  • संपर्क
  • इंजीनियरिंग
WisyLink © 2026·
हमारी टीम द्वारा ❤️ के साथ बनाया गया।