परिचय: लीगेसी कोड का रिफैक्टरिंग क्यों आवश्यक है
हर डेवलपर को देर-सबेर लीगेसी कोड का सामना करना पड़ता है — पुराना, खराब दस्तावेज़ीकरण वाला और अक्सर अपठनीय। JavaScript और Node.js की दुनिया में यह विशेष रूप से प्रासंगिक है: प्रोजेक्ट तेज़ी से बढ़ते हैं, तकनीकें बदलती हैं, और कोड के पुराने हिस्से 'दलदल' में बदल जाते हैं, जो डेवलपमेंट को धीमा कर देते हैं। लीगेसी कोड का रिफैक्टरिंग सिर्फ एक सनक नहीं, बल्कि एप्लिकेशन की परफॉरमेंस, सुरक्षा और स्केलेबिलिटी बनाए रखने के लिए एक आवश्यकता है।
इस लेख में, हम जानेंगे कि JavaScript (Node.js) पर लीगेसी कोड के रिफैक्टरिंग को सुरक्षित और प्रभावी ढंग से कैसे किया जाए। आप मुख्य चरणों के बारे में जानेंगे: विश्लेषण, मॉड्यूल में विभाजन, पुरानी संरचनाओं को बदलना और परीक्षण। सभी उदाहरण आधुनिक JavaScript (ES6+) में लिखे गए हैं और Node.js वातावरण पर केंद्रित हैं।
चरण 1: लीगेसी कोड का विश्लेषण और समझ
कोड बदलने से पहले, उसे समझना ज़रूरी है। लीगेसी कोड अक्सर 'स्पेगेटी' शैली में लिखा होता है: सैकड़ों पंक्तियों वाले फंक्शन, ग्लोबल वेरिएबल और लॉजिक का मिश्रण। ऑडिट से शुरुआत करें।
1.1. डिपेंडेंसी मैप बनाएं
मॉड्यूल के बीच संबंधों को विज़ुअलाइज़ करने के लिए madge या dependency-cruiser जैसे टूल का उपयोग करें। इससे साइक्लिक डिपेंडेंसी और 'गॉड ऑब्जेक्ट्स' का पता लगाने में मदद मिलेगी।
// उदाहरण: madge इंस्टॉल करना
npm install -g madge
madge --image graph.svg src/
1.2. 'जोखिम क्षेत्रों' की पहचान करें
कोड के उन हिस्सों को खोजें जो सबसे अधिक बार बदलते हैं या एरर का कारण बनते हैं। Git में कमिट हिस्ट्री का उपयोग करें:
git log --oneline --follow src/legacyModule.js
इसके अलावा, इन पर ध्यान दें:
- 50 पंक्तियों से लंबे फंक्शन
- ग्लोबल वेरिएबल (जैसे,
let/constके बिनाvar) - Callback hell (नेस्टेड एसिंक्रोनस कॉल)
1.3. मौजूदा व्यवहार के लिए टेस्ट लिखें
टेस्ट के बिना रिफैक्टरिंग एक टाइम बम है। मुख्य फंक्शन को कवर करने के लिए jest या mocha का उपयोग करें। टेस्ट को मौजूदा व्यवहार की जांच करनी चाहिए, न कि 'आदर्श' व्यवहार की।
// लीगेसी फंक्शन के लिए टेस्ट का उदाहरण
const sum = require('./legacyModule').sum;
test('sum दो संख्याओं को जोड़ता है', () => {
expect(sum(1, 2)).toBe(3);
});
चरण 2: संरचना में क्रमिक सुधार
सब कुछ एक साथ फिर से लिखने की कोशिश न करें। 'Strangler Fig' रणनीति का उपयोग करें — कोड के हिस्सों को धीरे-धीरे बदलें, बैकवर्ड कम्पैटिबिलिटी बनाए रखें।
2.1. मोनोलिथ को मॉड्यूल में विभाजित करें
तार्किक रूप से संबंधित ब्लॉक को अलग-अलग फ़ाइलों में निकालें। उदाहरण के लिए, डेटाबेस कार्य को db.js में और रिक्वेस्ट प्रोसेसिंग को handlers.js में डालें।
// पहले: 500 पंक्तियों वाली एक फ़ाइल
function handleRequest(req, res) {
// 100 पंक्तियाँ लॉजिक
// 50 पंक्तियाँ DB कार्य
// 30 पंक्तियाँ रिस्पॉन्स फ़ॉर्मेटिंग
}
// बाद में: मॉड्यूल में विभाजन
// db.js
exports.getUser = (id) => { /* ... */ };
// handlers.js
const db = require('./db');
exports.handleRequest = (req, res) => {
const user = db.getUser(req.params.id);
// रिस्पॉन्स फ़ॉर्मेटिंग
};
2.2. var को let/const से बदलें
यह एक सरल लेकिन महत्वपूर्ण कदम है। var का फंक्शन-स्कोप होता है, जो अक्सर बग का कारण बनता है। वेरिएबल के लिए let और कॉन्स्टेंट के लिए const का उपयोग करें।
// पहले था
var x = 10;
if (true) {
var x = 20; // बाहरी वेरिएबल को ओवरराइड करता है
}
// अब है
let x = 10;
if (true) {
let x = 20; // लोकल वेरिएबल
}
चरण 3: एसिंक्रोनस कोड का आधुनिकीकरण
Node.js पर लीगेसी कोड अक्सर 'callback hell' से ग्रस्त होता है। नेस्टेड कॉलबैक को प्रॉमिस या async/await से बदलें।
3.1. callback को प्रॉमिस में बदलना
Node.js शैली (पहला आर्गुमेंट एरर) का पालन करने वाले फंक्शन के लिए util.promisify का उपयोग करें।
const fs = require('fs');
const { promisify } = require('util');
const readFile = promisify(fs.readFile);
// उपयोग
async function readConfig() {
try {
const data = await readFile('config.json', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
}
```