ریفکتورینگ چیست؟
آموزش فارسی refactoring (بخش سوم)
ریفکتورینگ کدهای مارا مرتب و باز سازی میکند بدون اینکه تغییری در خروجی کد های ما داشته باشد و معنا و قصد اصلی نویسنده کد را حفظ میکند. ما باید به نحوی کدهای خودرا پاکسازی کنیم که دیگر توسعه دهندگان از دیدن کدهای ما راضی باشند و بتوانند به راحتی کدهای مارا توسعه بدهند. ریفکتورینگ باید با دقت انجام شود تا از تغییر معنی وخروجی کدهای ما جلوگیری شود. از مزایای آن میتوان به بهبود قابلیت خواندن کد و کاهش پیچیدگی کدها نام برد و این میتواند قابلیت نگهدراری کد های مارا بهبود بخشد و کدهارا برای توسعه و گسترش مرتب تر و واضح تر نمایش بدهد. اگر ریفکتورینگ به خوبی انجام شود به توسعه دهندگان نرم افزاراین امکان را میدهد تا قسمت های آسیب پذیر پنهان یا خاموش سیستم خود را شناسایی کرده و سطوح پیچیده غیر ضروری را حذف کنند.
مشاهده تمام آموزش های Refactoring
ما در بخش های قبل آموزش ریفکتورینگ به زبان فارسی راجع به refactoring و آشنایی با آن پرداختیم. حال در بخش سوم از آموزش Refactoring بیشتر این مبحث را مورد بررسی قرار می دهیم.
ریفکتورینگ در برنامه نویسی (بخش سوم)
ریفکتورینگ کدهای مارا مرتب و باز سازی میکند بدون اینکه تغییری در خروجی کد های ما داشته باشد و معنا و قصد اصلی نویسنده کد را حفظ میکند. ما باید به نحوی کدهای خودرا پاکسازی کنیم که دیگر توسعه دهندگان از دیدن کدهای ما راضی باشند و بتوانند به راحتی کدهای مارا توسعه بدهند. ریفکتورینگ باید با دقت انجام شود تا از تغییر معنی وخروجی کدهای ما جلوگیری شود. از مزایای آن میتوان به بهبود قابلیت خواندن کد و کاهش پیچیدگی کدها نام برد و این میتواند قابلیت نگهدراری کد های مارا بهبود بخشد و کدهارا برای توسعه و گسترش مرتب تر و واضح تر نمایش بدهد. اگر ریفکتورینگ به خوبی انجام شود به توسعه دهندگان نرم افزاراین امکان را میدهد تا قسمت های آسیب پذیر پنهان یا خاموش سیستم خود را شناسایی کرده و سطوح پیچیده غیر ضروری را حذف کنند.
ما در بخش های قبل آموزش ریفکتورینگ به زبان فارسی راجع به refactoring و آشنایی با آن پرداختیم. حال در بخش سوم از آموزش Refactoring بیشتر این مبحث را مورد بررسی قرار می دهیم.
مشاهده تمام آموزش های ریفکتورینگ
هنگامی که این تغییرات را انجام دادیم، باید بلافاصله کامپایلر را تست کنیم تا ببینیم آیاچیزی را شکسته ایم یا نه و باید بعد از هر بار refactoring این کار را انجام بدهیم و این کار باید جزء عادت های ما بشود هرچند که تابع یا کد ما ساده باشد. تست بعد از هر تغییر به این معنی است که وقتی اشتباه میکنیم، فقط باید تغییر کوچکی در نظر بگیریم تا خطا را ببینیم که باعث می شود تا یافتن و رفع آن آسان تر شود. این ماهیت فرایند بازپرداخت: تغییرات کوچک و آزمایش پس از هر تغییر است. ما باید سعی کنیم زیاد این کار را انجام دهیم، چون اشتباه كردن ما را مجبور می کند به مهارت اشکالزدایی دست یابیم، که قسمت هایی که می تواند مدت زیادی طول بکشد را سریع تر انجام و اشکال زدایی بکنیم. تغییرات کوچک، یک حلقه کلیدی مفید برای اجتناب از این آشفتگی است.
ما استفاده از این کامپایل را برای انجام کارهای مورد نیاز برای اجرای جاوا اسکریپت انجام می دهیم. از آنجا که جاوا اسکریپت به طور مستقیم قابل اجرا است ممکن است هیچ معنی هم نداشته باشد، اما در موارد دیگر ممکن است به معنی انتقال کد به یک دایرکتوری خروجی ویا استفاده از یک پردازنده مانند Babel باشد.
Refactoring برنامه ها را در مرحله های کوچک تغییر می دهد، بنابراین اگر شما اشتباه کنید، پیدا کردن آن اشکال آسان میباشد.
این جاوا اسکریپت است، ما میتوانیم amountFor را به یک تابع تو در تو از Statement استخراج کنیم. این به این معنی است که ما نیاز نداریم که داده های داخل محدوده تابع را به داده های حاوی تابع تازه استخراج منتقل کنیم. اما این کمترین مسئله برای مقابله با آن است.
در این مورد تست ها را گذرانده ایم، بنابراین قدم بعدی ما تغییرات سیستم کنترل نسخه محلی ما میباشد. ما از یک سیستم کنترل نسخه استفاده می کنیم مانند git یا mercurial که به ما اجازه انجام تحریم های خصوصی را میدهد.
استخراج کردن تابع یک refactoring رایج به طور خودکار است. اگر برنامه نویس جاوا بودیم، باید به طور غریزی دنبال کلیدی برای IDE برای انجام این refactoring می بودیم. همانطور که اشاره شد چنین پشتیبانی قوی برای این refactoring در ابزارهای جاوا اسکریپت وجود ندارد، بنابراین ما باید این را به صورت دستی انجام دهیم. این سخت نیست، اگر چه ما باید مواظب آن متغیرهای محدوده محلی باشیم.
هنگامی که از استخراج تابع استفاده می کنیم باید نگاهی به آنچه که استخراج کرده ایم بیندازیم تا ببینم کارهای سریع و آسانتری برای روشن ساختن عملکرد استخراج وجود دارد. اولین کاری که ما انجام می دهیم، برخی از متغیرها را تغییر نام می دهیم تا آنها را واضح تر کنند، مانند thisAmount برای result.
function amountFor(perf, play) {
let result = 0;
switch (play.type) {
case "tragedy":
result = 40000;
if (perf.audience > 30) {
result += 1000 * (perf.audience 30)
;
}
break;
case "comedy":
result = 30000;
if (perf.audience > 20) {
result += 10000 + 500 * (perf.audience 20)
;
}
result += 300 * perf.audience;
break;
default:
throw new Error(`unknown type: ${play.type}`);
}
return result;
}
این استاندارد برنامه نویسی است که ما استفاده میکنیم، همیشه مقدار برگشتی را از تابع " result " می گیریم. به این ترتیب ما همیشه نقش آن را می دانیم. دوباره تست را کامپایل میکنیم. سپس به اولین استدلال حرکت می کنیم.
function amountFor(aPerformance, play) {
let result = 0;
switch (play.type) {
case "tragedy":
result = 40000;
if (aPerformance.audience > 30) {
result += 1000 * (aPerformance.audience 30)
;
}
break;
case "comedy":
result = 30000;
if (aPerformance.audience > 20) {
result += 10000 + 500 * (aPerformance.audience 20)
;
}
result += 300 * aPerformance.audience;
break;
default:
throw new Error(`unknown type: ${play.type}`);
}
return result;
}
هر کسی میتواند کدی را که کامپیوتر میتواند درک کند را بنویسد. اما برنامه نویسان خوب کد را می نویسند که انسان می تواند درک کند.
آیا این تغییر نام ارزش تلاش کردن دارد؟ قطعا این ارزش را دارد. کد خوب باید به طور واضح ارتباط داشته باشد با آنچه انجام می دهد و نام این متغیر، کلیدی برای پاک کردن کد است. هرگز از تغییر نام برای وضوح بیشتر ترسی نداشته باشید. با پیدا کردن و جایگزینی ابزار خوب، معمولا مشکلی وجود نخواهد داشت. تست و تایپ کردن استاتیک به زبانی که آن را پشتیبانی می کند، هر گونه رخدادی را که از دست می دهید را برجسته می کند و با ابزارهای خودکار ریفکتورینگ، به طور نامحدود تغییر نام حتی برای توابع گسترده استفاده می شود.
مورد بعدی برای تغییر نام مد نطر پارامتر play است. اما ما برنامه متفاوتی برای این بخش داریم.
حذف متغیر play
همانطور که پارامترها را برای مقدار amountFor در نظر می گیریم، نگاه میکنیم تا ببینیم از کجا آمده است. aPerformance از متغیر حلقه می آید، بنابراین به طور طبیعی با هربار تکرار حلقه تغییر می کند. اما play با کارایی مقایسه میشود، بنابراین نیازی نیست آن را به عنوان یک پارامتر در نظر بگیرید، ما دوباره آنرا در amountFor مقایسه میکنیم. هنگامی که ما یک عملکرد بلند را میشکنیم، دوست داریم از متغیرهایی مثل play خلاص شویم، چون متغیرهای موقت، تعداد زیادی نام اسامی محلی را ایجاد می کنند که استخراج آنها پیچیده می کنند. ریفکتورینگی که ما اینجا استفاده میکنیم جایگزین Temp با Query میباشد ما با استخراج سمت راست از انتساب به یک تابع شروع می کنیم
function playFor(aPerformance) {
return plays[aPerformance.playID];
}
top level…
function statement (invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `Statement for ${invoice.customer}\n`;
const format = new Intl.NumberFormat("enUS",
{ style: "currency", currency: "USD",
minimumFractionDigits: 2 }).format;
for (let perf of invoice.performances) {
const play = playFor(perf);
let thisAmount = amountFor(perf, play);
// add volume credits
volumeCredits += Math.max(perf.audience 30,
0);
// add extra credit for every ten comedy attendees
if ("comedy" === play.type) volumeCredits += Math.floor(perf.audience / 5);
// print line for this order
result += ` ${play.name}: ${format(thisAmount/100)} (${perf.audience}
totalAmount += thisAmount;
}
result += `Amount owed is ${format(totalAmount/100)}\n`;
result += `You earned ${volumeCredits} credits\n`;
return result;
ما compile-test-commit و سپس از Inline Variable استفاده می کنیم.
top level…
function statement (invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `Statement for ${invoice.customer}\n`;
const format = new Intl.NumberFormat("enUS",
{ style: "currency", currency: "USD",
minimumFractionDigits: 2 }).format;
for (let perf of invoice.performances) {
const play = playFor(perf);
let thisAmount = amountFor(perf, playFor(perf));
// add volume credits
volumeCredits += Math.max(perf.audience 30,
0);
// add extra credit for every ten comedy attendees
if ("comedy" === playFor(perf).type) volumeCredits += Math.floor(perf.audience // print line for this order
result += ` ${playFor(perf).name}: ${format(thisAmount/100)} (${perf.audience} totalAmount += thisAmount;
}
result += `Amount owed is ${format(totalAmount/100)}\n`;
result += `You earned ${volumeCredits} credits\n`;
return result;
منبع مورد استفاده
refactoring.improving.the.design.of.existing.code.2nd.edition
در بخش های بعد "refactoring چیست" به موارد بیشتری خواهیم پرداخت. با تشکر - مجموعه ABLY