Skip to content

فصل ۱۰ — بازآرایی‌های متد (Method Refactorings)

این فصل بازآرایی‌های کدی را که برای stored procedure، stored function و trigger قابل اعمال یافته‌ایم خلاصه می‌کند. برای سادگی، این سه نوع عملکرد را فقط «متد» می‌نامیم — اصطلاحی که Martin Fowler در کتاب Refactoring (Fowler 1999) به کار برد. همان‌طور که از نامش پیداست، بازآرایی متد تغییری در stored procedure است که کیفیت آن را بهبود می‌دهد. هدف ما ارائهٔ نمای کلی این بازآرایی‌هاست. توضیحات مفصل را در Refactoring، اثر بنیادین این موضوع، می‌یابید.

بین دو دستهٔ بازآرایی متد تمایز قائل می‌شویم: آن‌هایی که رابط (interface) پایگاه دادهٔ ارائه‌شده به برنامه‌های بیرونی را تغییر می‌دهند و آن‌هایی که درون متد را تغییر می‌دهند. مثلاً بازآرایی Add Parameter (صفحهٔ ۲۷۸) رابط متد را تغییر می‌دهد، در حالی که Consolidate Conditional Expression (صفحهٔ ۲۸۳) این کار را نمی‌کند — مقایسهٔ پیچیده را با فراخوانی متد جدیدی که فقط مقایسه را پیاده‌سازی می‌کند جایگزین می‌کند. بین دو دسته تمایز قائل می‌شویم چون بازآرایی‌هایی که رابط را تغییر می‌دهند نیاز به بازآرایی برنامه‌های بیرونی دارند، در حالی که آن‌هایی که فقط درون متد را تغییر می‌دهند این‌طور نیستند.

۱۰.۱. بازآرایی‌های تغییردهندهٔ رابط (Interface Changing Refactorings)

هر یک از این بازآرایی‌ها دورهٔ گذاری (transition period) دارد تا به تیم‌های توسعه زمان کافی برای به‌روزرسانی برنامه‌های بیرونی که متدها را فراخوانی می‌کنند بدهد. بخشی از بازآرایی بازکار نسخهٔ اصلی متد(ها) برای فراخوانی مناسب نسخه(های) جدید است و سپس پس از دورهٔ گذار، نسخهٔ قدیمی به‌طور مناسب فراخوانی می‌شود.

۱۰.۱.۱. Add Parameter — افزودن پارامتر

همان‌طور که از نامش پیداست، این بازآرایی پارامتر جدیدی به متد موجود اضافه می‌کند. در شکل ۱۰.۱، مثالی می‌بینید که MiddleName به‌عنوان پارامتر سوم به ReadCustomer اضافه شده است. امن‌ترین راه افزودن پارامتر، افزودن آن به انتهای فهرست پارامترهاست؛ به این ترتیب هنگام بازآرایی فراخوانی‌های متد، خطر مرتب‌سازی نادرست پارامترها را ندارید. اگر بعداً تصمیم گرفتید پارامترها در ترتیب اشتباه هستند، می‌توانید بازآرایی Reorder Parameters (صفحهٔ ۲۸۱) را اعمال کنید.

شکل ۱۰.۱. افزودن پارامتر.

۱۰.۱.۲. Parameterize Method — پارامتردهی متد

گاهی دو یا چند متد اساساً کار یکسانی انجام می‌دهند. مثلاً در شکل ۱۰.۲، stored procedureهای GetAmericanCustomers، GetCanadianCustomers و GetBrazilianCustomers به‌ترتیب فهرستی از مشتریان آمریکایی، کانادایی و برزیلی تولید می‌کنند. اگرچه این procedureهای جداگانه مزیت اختصاصی بودن را دارند و اطمینان می‌دهند پرس‌وجوهای درست روی پایگاه داده فراخوانی می‌شوند، نگهداری آن‌ها سخت‌تر از یک stored procedure واحد است. این stored procedureها با stored procedure GetCustomerByCountry جایگزین می‌شوند که شناسهٔ کشور را به‌عنوان پارامتر می‌گیرد. در نتیجه کد کمتری برای نگهداری وجود دارد و افزودن پشتیبانی برای کشورهای جدید فقط با افزودن کدهای کشور جدید آسان است.

شکل ۱۰.۲. پارامتردهی stored procedure.

۱۰.۱.۳. Remove Parameter — حذف پارامتر

گاهی متدی پارامتر اضافی دارد — شاید چون در ابتدا با این باور اضافه شده که در آینده لازم خواهد بود، یا شاید چون کسب‌وکار تغییر کرده و دیگر لازم نیست، یا شاید مقدار پارامتر را می‌توان از راه دیگری — مانند خواندن از جدول lookup — به دست آورد. در شکل ۱۰.۳، می‌بینید GetAccountList پارامتر اضافی AsOfDate دارد که برای انعکاس استفادهٔ واقعی stored procedure حذف می‌شود.

شکل ۱۰.۳. حذف پارامتر.

۱۰.۱.۴. Rename Method — تغییر نام متد

گاهی متدی نام ضعیفی دارد، یا صرفاً قراردادهای نام‌گذاری سازمانی شما را رعایت نمی‌کند. مثلاً در شکل ۱۰.۴، stored procedure GetAccountList به GetAccountsForCustomer تغییر نام می‌دهد تا قراردادهای نام‌گذاری استاندارد شما را منعکس کند.

شکل ۱۰.۴. تغییر نام stored procedure.

۱۰.۱.۵. Reorder Parameters — مرتب‌سازی مجدد پارامترها

رایج است کشف کنید ترتیب پارامترهای متد منطقی نیست — شاید چون پارامترهای جدید از طریق Add Parameter (صفحهٔ ۲۷۸) در ترتیب اشتباه اضافه شده‌اند یا شاید چون ترتیب نیازهای کسب‌وکار فعلی را منعکس نمی‌کند. در هر صورت، می‌توانید stored procedure را با مرتب‌سازی مناسب پارامترها آسان‌تر برای فهم کنید (شکل ۱۰.۵ را ببینید).

شکل ۱۰.۵. مرتب‌سازی مجدد پارامترهای متد.

همان‌طور که در شکل ۱۰.۶ می‌بینید، پارامترهای GetCustomers برای انعکاس قراردادهای رایج مرتب‌سازی کسب‌وکار مرتب شدند. توجه کنید این مثال بسیار پرخطر است — در این مورد نمی‌توانید دورهٔ گذار داشته باشید چون نوع هر سه پارامتر یکسان است و بنابراین نمی‌توانید ساده متد را override کنید. پیامد این است که می‌توانید پارامترها را مرتب کنید اما فراموش کنید در کد بیرونی که متد را فراخوانی می‌کند آن‌ها را مرتب کنید — متد همچنان اجرا می‌شود، اما با مقادیر اشتباه برای پارامترها؛ نقصی که بدون test caseهای خوب پیدا کردنش دشوار است. اگر پارامترها از انواع مختلف بودند، برنامه‌های بیرونی که برای ارسال پارامترها به ترتیب جدید بازآرایی نشده‌اند می‌شکستند و یافتن کد تأثیرپذیر در نتیجه بسیار آسان می‌شد.

شکل ۱۰.۶. مرتب‌سازی مجدد پارامترهای متد بدون دورهٔ گذار.

۱۰.۱.۶. Replace Parameter with Explicit Methods — جایگزینی پارامتر با متدهای صریح

گاهی یک متد واحد یکی از چند کار را بر اساس مقدار پارامتری که به آن ارسال می‌شود انجام می‌دهد. مثلاً در شکل ۱۰.۷، می‌بینید GetAccountValue — که اساساً getter عمومی است و مقدار ستونی در یک ردیف را برمی‌گرداند — با stored procedureهای مشخص‌تر GetAccountBalance، GetAccountCustomerID و GetAccountOpeningDate جایگزین می‌شود.

شکل ۱۰.۷. جایگزینی پارامتر با stored procedureهای صریح.

۱۰.۲. بازآرایی‌های درونی (Internal Refactorings)

بازآرایی‌های درونی کیفیت پیاده‌سازی متد را بدون تغییر رابط آن بهبود می‌دهند.

۱۰.۲.۱. Consolidate Conditional Expression — ادغام عبارت شرطی

درون منطق متد، اغلب سری‌ای از آزمون‌های شرطی دارید که نتیجهٔ یکسانی تولید می‌کنند. باید کد را بازآرایی کنید تا آن شرط‌ها را ترکیب کنید و کد واضح‌تر شود، همان‌طور که در مثال زیر می‌بینید که سه شرط در یکی ادغام شده‌اند. این بازآرایی شما را برای اعمال Extract Method (صفحهٔ ۲۸۵) برای ایجاد متدی که شرط را پیاده‌سازی می‌کند آماده می‌کند:

sql
-- Before code

CREATE OR REPLACE FUNCTION GetAccountAverageBalance
 ( inAccountID IN NUMBER)
 RETURN NUMBER;
AS
 averageBalance := 0;
BEGIN
 IF inAccountID = 10000 THEN
   RETURN 0;
 END IF;
 IF inAccountID = 123456 THEN
   RETURN 0;
 END IF;
 IF inAccountID = 987654 THEN
   RETURN 0;
 END IF;
   Code to calculate the average balance
 RETURN averageBalance;
END;

-- After code

CREATE OR REPLACE FUNCTION GetAccountAverageBalance
 ( inAccountID IN NUMBER)
 RETURN NUMBER;
AS
 averageBalance := 0;
BEGIN
 IF inAccountID = 10000 || inAccountID = 123456 || inAccountID = 987654 THEN
   RETURN 0;
 END IF;
 Code to calculate the average balance
 RETURN averageBalance;
END;

۱۰.۲.۲. Decompose Conditional — تجزیهٔ شرط

عبارت شرطی IF-THEN-ELSE پیچیده‌ای دارید که در نتیجه فهم آن دشوار است. شرط، بخش then و بخش else را با فراخوانی متدهایی که منطق عبارت را پیاده‌سازی می‌کنند جایگزین کنید. در نسخهٔ اول کد زیر، منطق تعیین نرخ بهرهٔ اعمالی بر اساس اینکه مقدار inBalance زیر، درون یا بالاتر از آستانهٔ مشخص است تعیین می‌شود. در نسخهٔ دوم، کد با افزودن فراخوانی‌های BalanceIsSufficient، CalculateLowInterest و CalculateHighInterest ساده شده است. (این توابع نشان داده نشده‌اند.)

sql
-- Before code

CREATE OR REPLACE FUNCTION CalculateInterest
 ( inBalance IN NUMBER )
 RETURN NUMBER;
AS
 lowBalance NUMBER;
 highBalance NUMBER;
 lowInterestRate NUMBER;
 highInterestRate NUMBER;
BEGIN

 lowBalance := GetLowBalance();
 highBalance := GetHighBalance();
 lowInterestRate := GetLowInterestRate();
 highInterestRate := GetHighInterestRate();

 IF inBalance < lowBalance THEN
  RETURN 0;
 END IF

 IF inBalance >= lowBalance && inBalance <= highBalance THEN
  RETURN inBalance * lowInterestRate;
 ELSE
  RETURN inBalance * highInterestRate;
 END IF;
END;

-- After code

CREATE OR REPLACE FUNCTION CalculateInterest
 ( inBalance IN NUMBER )
 RETURN NUMBER;
AS
BEGIN

 IF BalanceIsInsufficient( inBalance ) THEN
  RETURN 0;
 END IF

 IF IsLowInterestBalance( inBalance ) THEN
  RETURN CalculateLowInterest( inBalance );
 ELSE
  RETURN CalculateHighInterest( inBalance );
 END IF;
END;

۱۰.۲.۳. Extract Method — استخراج متد

درون متد موجود، قطعهٔ کدی دارید که می‌توان آن را گروه‌بندی و به متد خودش استخراج کرد — نامی که توضیح می‌دهد چه می‌کند. قطعهٔ کد معمولاً در جای دیگر تکرار شده و/یا عملکرد معناداری پیاده‌سازی می‌کند؛ بنابراین می‌توانید این بازآرایی را برای ساده‌سازی کد اعمال کنید. عملیات‌های کوتاه و خوش‌نام آسان‌تر برای فهم و در نتیجه نگهداری هستند و احتمال بیشتری برای استفادهٔ مجدد دارند. همان‌طور که در کد زیر می‌بینید، نسخهٔ اول با جایگزینی منطق تعیین موجودی روزانهٔ آغازین با فراخوانی stored function GetDailyBalance ساده شده است. در نسخهٔ نهایی کد، این بازآرایی چند بار دیگر برای ساده‌سازی بیشتر اعمال شده است. اثر جانبی اعمال این بازآرایی این است که stored procedureهای سطح‌بالا و عمومی شما مانند کد خوش‌نویس و بسیار خوانا خوانده می‌شوند:

sql
-- Initial version of the code

CREATE OR REPLACE FUNCTION CalculateAccountInterest
 ( inAccountID IN NUMBER,
 inStart IN DATE,
 inEnd IN DATE )
 RETURN NUMBER;
AS
 medianBalance NUMBER;
 startBalance NUMBER;
 endBalance NUMBER;
 interest := 0;
BEGIN
 BEGIN
    Determine the starting balance
   SELECT Balance INTO startBalance
    FROM DailyEndBalance
    WHERE AccountID = inAccountID && PostingDate = inStart;
    EXCEPTION WHEN NO_DATA_FOUND THEN
     startBalance := 0;

    Determine the ending balance
   SELECT Balance INTO endBalance
    FROM DailyEndBalance
    WHERE AccountID = inAccountID && PostingDate = inEnd;
   EXCEPTION WHEN NO_DATA_FOUND THEN
    endBalance := 0;
   END;
   medianBalance := ( startBalance + endBalance ) / 2;
   IF medianBalance < 0 THEN
    medianBalance := 0;
               END IF;
              IF medianBalance >= 500 THEN
    interest := medianBalance * 0.01;
   END IF;
  RETURN interest;
 END;

-- Intermediate version of the code

 CREATE OR REPLACE Function CalculateAccountInterest
   ( inAccountID IN NUMBER,
   inStart IN DATE,
   inEnd IN DATE )
   RETURN NUMBER;
AS
 medianBalance NUMBER;
 startBalance NUMBER;
 endBalance NUMBER;
 interest := 0;
BEGIN

 startBalance := GetDailyEndBalance ( inAccountID, inStart );

 BEGIN
   Determine the ending balance
 SELECT Balance INTO endBalance
  FROM DailyEndBalance
  WHERE AccountID = inAccountID && PostingDate = inEnd;
 EXCEPTION WHEN NO_DATA_FOUND THEN
  endBalance := 0;
END;
 medianBalance := ( startBalance + endBalance ) / 2;
 IF medianBalance < 0 THEN
  medianBalance := 0;
 END IF;

 IF medianBalance >= 500 THEN
  interest := medianBalance * 0.01;
 END IF;
 RETURN interest;
END;

CREATE OR REPLACE Function GetDailyBalance
 ( inAccountID IN NUMBER,
 inDate IN DATE )
 RETURN NUMBER;
AS
 endbalance NUMBER;
BEGIN
 BEGIN
    SELECT Balance INTO endBalance
    FROM DailyEndBalance
    WHERE AccountID = inAccountID < PostingDate = inDate;
   EXCEPTION WHEN NO_DATA_FOUND THEN
    endBalance := 0;
 END;
 RETURN endBalance;
END;

-- Final version of the code

CREATE OR REPLACE FUNCTION CalculateAccountInterest
( inAccountID IN NUMBER,
 inStart IN DATE,
 inEnd IN DATE )
 RETURN NUMBER;
AS
 medianBalance NUMBER;
 startBalance NUMBER;
 endBalance NUMBER;
BEGIN
 startBalance := GetDailyEndBalance ( inAccountID, inStart );
 endBalance:= GetDailyEndBalance ( inAccountID, inEnd );
 medianBalance := CalculateMedianBalance ( startBalance, endBalance );
 RETURN CalculateInterest ( medianBalance );
END;

-- Code for GetDailyEndBalance, CalculateMedianBalance, & CalculateInterest goes here

۱۰.۲.۴. Introduce Variable — معرفی متغیر

کد متد شما عبارت پیچیده‌ای دارد که خواندنش دشوار است. می‌توانید متغیرهای خوش‌نام در کد معرفی کنید که بخش‌هایی از عبارت را پیاده‌سازی می‌کنند و سپس برای تشکیل عبارت اصلی ترکیب می‌شوند و در نتیجه متد آسان‌تر برای فهم می‌شود. این بازآرایی معادل Introduce Explaining Variable مارتین فاولر (Fowler 1999) است. پس از صحبت با او، پیشنهاد کرد از نام ساده‌تر استفاده کنیم؛ در retrospect، فهمید که در ابتدا باید این بازآرایی را Introduce Variable می‌نامید و بیشتر فروشندگان ابزار هم از نام ساده‌تر استفاده می‌کنند:

sql
-- Before code

CREATE OR REPLACE FUNCTION DetermineAccountStatus
 ( inAccountID IN NUMBER,
   inStart IN DATE,
   inEnd IN DATE )
 RETURN VARCHAR;
AS
       lastAccessedDate DATE;
BEGIN
   Some code to calculate lastAccessDate

 IF ( inDate < lastAccessDate && outdate > lastAccessDate )
  && ( inAccountID > 10000 )
  && ( inAccountID != 123456 && inAcountID != 987654) THEN
   do something
 END IF;
  do another thing
END;

-- After code

CREATE OR REPLACE FUNCTION DetermineAccountStatus
 ( inAccountID IN NUMBER,
   inStart IN DATE,
   inEnd IN DATE )
 RETURN VARCHAR;
AS
 lastAccessedDate DATE;
 isBetweenDates BOOLEAN;
 isValidAccountID BOOLEAN;
 isNotTestAccount BOOLEAN
BEGIN
   Some code to calculate lastAccessDate
 isBetweenDates := inDate < lastAccessDate && outdate > lastAccessDate;
 isValidAccountID := inAccountID > 100000;
 isNotTestAccount := inAccountID != 123456 && inAcountID != 987654;
 IF isBetweenDates && isValidAccountID &&
 isNotTestAccount THEN
    do something
 END IF;
   do another thing
END;

۱۰.۲.۵. Remove Control Flag — حذف پرچم کنترل

متغیری دارید که به‌عنوان پرچم کنترل برای خروج از ساختار کنترلی مانند حلقه عمل می‌کند. می‌توانید کد را با جایگزینی استفاده از پرچم کنترل با بررسی عبارت درون ساختار کنترلی ساده کنید. همان‌طور که در مثال زیر می‌بینید، وقتی منطق controlFlag حذف می‌شود، کد ساده‌تر می‌شود:

sql
-- Before code

DECLARE
 controlFlag := 0;
 anotherVariable := 0;
BEGIN
 WHILE controlFlag = 0 LOOP
   Do something
  IF anotherVariable > 20 THEN
   controlFlag = 1;
  ELSE
     Do something else
  END IF;
 END LOOP;
END;

-- After code

DECLARE
 anotherVariable := 0;
BEGIN
 WHILE anotherVariable <= 20 LOOP
   Do something
   Do something else
 END LOOP;
END;

۱۰.۲.۶. Remove Middle Man — حذف واسطه

گاهی متدی فقط به‌عنوان واسطه (pass through) یا «میانی» برای متدهای دیگر عمل می‌کند. این می‌تواند وقتی رخ دهد که stored procedure تغییر نام داده و سپس stored procedureای با نام اصلی معرفی شده که فقط stored procedure با نام جدید را فراخوانی می‌کند. همچنین می‌تواند وقتی رخ دهد که متوجه شوید دو stored procedure کار یکسانی انجام می‌دهند؛ بنابراین همان‌طور که می‌بینید، یکی از آن‌ها بازنویسی شد تا ساده دیگری را فراخوانی کند. در هر صورت، وقتی کدی مانند مثال زیر می‌بینید، باید هر چیزی که AProcedure را فراخوانی می‌کند بازآرایی کنید تا اکنون AnotherProcedure را فراخوانی کند (و بنابراین AProcedure را حذف کنید):

sql
CREATE OR REPLACE PROCEDURE AProcedure
 parameter1 IN NUMBER;
 ...
 parameterN IN VARCHAR;
AS
BEGIN
 EXECUTE AnotherProcedure ( parameter1, ..., parameterN );
END;

۱۰.۲.۷. Rename Parameter — تغییر نام پارامتر

رایج است کشف کنید نام پارامتر موجود دشوار برای فهم است — یا نام پارامتر در آن زمان منطقی بود و استفاده‌اش در طول زمان تغییر کرده، یا از ابتدا اشتباه نام‌گذاری شده است. این بازآرایی نسبتاً ساده برای پیاده‌سازی است؛ فقط نام پارامتر را در کد منبع اصلی تغییر می‌دهید.

۱۰.۲.۸. Replace Literal with Table Lookup — جایگزینی مقدار ثابت با جستجوی جدول

عدد ثابت سخت‌کدشده‌ای دارید که در کد متد معنای خاصی دارد و نگهداری را دشوار می‌کند. رویکرد بهتر ذخیرهٔ مقدار در جدول و سپس بازیابی آن از جدول در صورت نیاز است. (این جدول را می‌توان برای بهبود عملکرد cache کرد.) در کد زیر، حداقل موجودی ۵۰۰ دلار در نسخهٔ جدید کد از جدول تک‌ردیفی CorporateBusinessConstants که برای ذخیرهٔ چنین مقادیری استفاده می‌شود بازیابی می‌شود. (همچنین می‌توانستیم جدول چندردیفی با تعداد محدود ستون — یکی برای هر نوع — برای ذخیرهٔ داده پیاده‌سازی کنیم.) سپس کد با اعمال دوبارهٔ این بازآرایی برای به‌دست آوردن مقدار نرخ بهره بهبود می‌یابد. همچنین Extract Method (صفحهٔ ۲۸۵) را برای ادغام منطق به‌دست آوردن مقادیر از جدول lookup اعمال می‌کنیم. این بازآرایی نسخهٔ پایگاه‌داده‌ای بازآرایی Replace Magic Number With Symbolic Constant (Fowler 1999) است:

sql
-- Initial version of the code

CREATE OR REPLACE FUNCTION CalculateInterest
 ( inBalance IN NUMBER )
 RETURN NUMBER;
AS
 interest := 0;
BEGIN
 IF inBalance >= 500 THEN
   interest := medianBalance * 0.01;
 END IF;
 RETURN interest;
END;

-- Intermediate version of the code

CREATE OR REPLACE FUNCTION CalculateInterest
 ( inBalance IN NUMBER )
 RETURN NUMBER;
AS
 interest := 0;
 minimumBalance NUMBER;
BEGIN
 BEGIN
   SELECT MinimumBalanceForInterest INTO minimumBalance
    FROM CorporateBusinessConstants
    WHERE RowNumber = 1;
   EXCEPTION WHEN NO_DATA_FOUND THEN
    minimumBalance := 0;
   END;
   IF inBalance >= minimumBalance THEN
    interest := medianBalance * 0.01;
   END IF;
   RETURN interest;
 END;

-- Final version of the code

 CREATE OR REPLACE FUNCTION CalculateInterest
  ( inBalance IN NUMBER )
  RETURN NUMBER;
 AS
  interest := 0;
  minimumBalance NUMBER;
  interestRate NUMBER;
 BEGIN

  minimumBalance := GetMinimumBalance();
  interestRate := GetInterestRate();

  IF inBalance >= minimumBalance THEN
   interest := medianBalance * interestRate;
  END IF;
  RETURN interest;
 END;

۱۰.۲.۹. Replace Nested Conditional with Guard Clauses — جایگزینی شرط تو در تو با بندهای نگهبان

عبارات شرطی تو در تو می‌توانند دشوار برای فهم باشند. در مثال زیر، عبارت‌های IF تو در تو با سری‌ای از عبارت‌های IF جداگانه جایگزین شدند تا خوانایی کد بهبود یابد:

sql
-- Before code

BEGIN
 IF condition1 THEN
   do something 1
 ELSE
  IF condition2 THEN
     do something 2
  ELSE
   IF condition3 THEN
      do something 3
   END IF;
  END IF;
 END IF;
END;

-- After code

BEGIN
 IF condition1 THEN
   do something 1
  RETURN;
 END IF;
 IF condition2 THEN
   do something 2
  RETURN;
 END IF;
 IF condition3 THEN
   do something 3
  RETURN;
 END IF;
END;

۱۰.۲.۱۰. Split Temporary Variable — تقسیم متغیر موقت

متغیر موقتی دارید که برای یک یا چند هدف درون متد استفاده می‌شود. این احتمالاً مانع داده‌ای نام معنادار به آن شده، یا شاید برای یک هدف نام معنادار دارد اما برای دیگری نه. راه‌حل معرفی متغیر موقت برای هر هدف است، همان‌طور که در کد زیر می‌بینید که aTemporaryVariable به‌عنوان مخزن برای تبدیل مقادیر امپریال به متریک استفاده می‌شود:

sql
-- Before code

DECLARE
 aTemporaryVariable := 0;
 farenheitTemperature := 0;
 lengthInInches := 0;
BEGIN
  retrieve farenheitTemperature
 aTemporaryVariable := (farenheitTemperature32 ) * 5 / 9;
  do something
  retrieve lengthInInches
 aTemporaryVariable := lengthInInches * 2.54;
  do something
END;

-- After code

DECLARE
 celciusTemperature := 0;
 farenheitTemperature := 0;
 lenghtInCentimeters := 0;
 lengthInInches := 0;
BEGIN
  retrieve farenheitTemperature
 celciusTemperature := (farenheitTemperature32 ) * 5 / 9;
  do something
  retrieve lengthInInches
 lenghtInCentimeters := lengthInInches * 2.54;
  do something
END;

۱۰.۲.۱۱. Substitute Algorithm — جایگزینی الگوریتم

اگر راه واضح‌تری برای نوشتن منطق الگوریتمی که به‌عنوان متد پیاده‌سازی شده پیدا کردید، باید این کار را انجام دهید. اگر نیاز به تغییر الگوریتم موجود دارید، اغلب ابتدا ساده‌سازی و سپس به‌روزرسانی آسان‌تر است. چون بازنویسی الگوریتم پیچیده سخت است، ابتدا باید آن را از طریق بازآرایی‌های دیگر — مانند Extract Method (صفحهٔ ۲۸۵) — ساده کنید و سپس Substitute Algorithm را اعمال کنید.