Dynamics 365 Business Central: แนวทางการ Refactor ใน AL Programming

ในการพัฒนา Extension ด้วยภาษา AL (Application Language) บนแพลตฟอร์ม Dynamics 365 Business Central (D365BC) นักพัฒนาจำเป็นต้องให้ความสำคัญกับคุณภาพของโค้ดในระยะยาว หนึ่งในแนวทางที่ช่วยให้โค้ดมีคุณภาพสูงคือการทำ Refactor หรือการปรับปรุงโครงสร้างของโค้ดเดิมให้ดีขึ้น

⚙️ Refactoring is essential to improving code readability, maintainability, and extensibility—without changing its output.

การ Refactor ไม่ได้หมายถึงการเปลี่ยนผลลัพธ์หรือหน้าที่การทำงานของโปรแกรม แต่เป็นการปรับโครงสร้างภายในของโค้ดให้มีความชัดเจนมากขึ้น ช่วยให้โค้ดอ่านง่าย แก้ไขได้สะดวก และพร้อมรองรับการต่อยอดในอนาคต โดยเฉพาะในภาษา AL ที่มักเกี่ยวข้องกับ Business Logic ที่ซับซ้อนและเปลี่ยนแปลงอยู่เสมอ

แนวคิดนี้มีบทบาทสำคัญต่อคุณภาพซอฟต์แวร์ ไม่ว่าจะเป็นในมุมของผู้พัฒนาใหม่ที่ต้องเข้าใจโค้ด หรือการดูแลระบบในระยะยาวโดยทีมเทคนิค

รูปแบบการใช้งาน Refactor ในภาษา AL

Refactor ใน AL มีหลายเทคนิคที่สามารถนำมาใช้ได้กับ Codeunit, Page, Report หรือแม้แต่ Enum/Interface โดยเฉพาะในโครงสร้างที่ต้องพัฒนาแบบ Extension

เทคนิคยอดนิยมที่ควรรู้

เทคนิค Refactorแนวคิดหลักเหมาะกับสถานการณ์
Extract Procedureแยกโค้ดย่อยออกมาเป็นฟังก์ชันใหม่ เพื่อเพิ่มความชัดเจนและลดขนาดโค้ดเมื่อ Procedure ยาวเกินไปหรือทำหลายหน้าที่
Rename Symbolเปลี่ยนชื่อฟังก์ชัน ตัวแปร หรือ Record ให้สื่อความหมายชัดเจนปรับปรุงความเข้าใจของทีมพัฒนา ลดข้อผิดพลาดจากการตีความผิด
Replace Magic Numberแทนค่าตัวเลข/ข้อความที่ไม่สื่อความหมาย ด้วย Constant หรือ Enumเช่น จาก if Status = 3if Status = Status::Released
Simplify Conditionalsลดความซับซ้อนของเงื่อนไข if-else ด้วยการใช้ exit, case, หรือย้ายเงื่อนไขเมื่อโค้ดมีหลายระดับของเงื่อนไขซ้อนกัน
Move Method to Codeunitแยก Business Logic ออกจาก UI เช่น Page หรือ Report ไปไว้ใน Codeunitลดภาระของ UI object และเพิ่มความสามารถในการทดสอบ
Split Large Methodแบ่งฟังก์ชันใหญ่ให้เป็นหลายส่วนย่อยที่ชัดเจนช่วยให้โค้ดอ่านง่าย และรองรับ Unit Test ได้ดีขึ้น

ตัวอย่างการ Refactor

การ Refactor ควรเริ่มจากปัญหาที่พบในโค้ดจริง ตัวอย่างนี้มาจากฟังก์ชันที่ใช้สร้างหรืออัปเดตข้อมูลในตาราง "Item Unit of Measure" ซึ่งถูกใช้กันอย่างแพร่หลายในการจัดการหน่วยสินค้าใน Business Central

โค้ดต้นฉบับ (Before Refactor)

procedure InsertItemUnitOfMeasure(pCode: Code[20]; pItemNo: Code[20]; QtyPerUOM: Decimal)
var
    ItemUOM, InsertItemUOM: Record "Item Unit of Measure";
    Item: Record Item;
    UnitofMeasure: Record "Unit of Measure";
begin
    if pCode = '' then
        Error('Unit of Measure Code cannot be empty.');

    if pItemNo = '' then
        Error('Item No. cannot be empty.');

    ItemUOM.Reset();
    ItemUOM.SetRange("Item No.", pItemNo);
    ItemUOM.SetRange(Code, pCode);
    if ItemUOM.FindFirst() then begin
        ItemUOM.Validate("Qty. per Unit of Measure", QtyPerUOM);
        ItemUOM.Modify();
    end else begin
        InsertItemUOM.Init();
        InsertItemUOM.Validate("Code", pCode);
        InsertItemUOM.Validate("Item No.", pItemNo);
        InsertItemUOM.Insert(true);
        InsertItemUOM.Validate("Qty. per Unit of Measure", QtyPerUOM);
        InsertItemUOM.Modify();
    end;
end;

โค้ดที่ผ่านการ Refactor (After Refactor)

 procedure InsertItemUnitOfMeasure(pCode: Code[20]; pItemNo: Code[20]; QtyPerUOM: Decimal)
    begin
        ValidateInput(pCode, pItemNo);

        if TryUpdateExistingUOM(pCode, pItemNo, QtyPerUOM) then
            exit;

        InsertNewItemUOM(pCode, pItemNo, QtyPerUOM);
    end;

    local procedure ValidateInput(pCode: Code[20]; pItemNo: Code[20])
    var
        Item: Record Item;
        UOM: Record "Unit of Measure";
    begin
        if pCode = '' then
            Error('Unit of Measure Code cannot be empty.');

        if pItemNo = '' then
            Error('Item No. cannot be empty.');
    end;

    local procedure TryUpdateExistingUOM(pCode: Code[20]; pItemNo: Code[20]; QtyPerUOM: Decimal): Boolean
    var
        ExistingUOM: Record "Item Unit of Measure";
    begin
        ExistingUOM.SetRange("Item No.", pItemNo);
        ExistingUOM.SetRange(Code, pCode);
        if ExistingUOM.FindFirst() then begin
            ExistingUOM.Validate("Qty. per Unit of Measure", QtyPerUOM);
            ExistingUOM.Modify();
            exit(true);
        end;

        exit(false);
    end;

    local procedure InsertNewItemUOM(pCode: Code[20]; pItemNo: Code[20]; QtyPerUOM: Decimal)
    var
        NewUOM: Record "Item Unit of Measure";
    begin
        NewUOM.Init();
        NewUOM.Validate("Item No.", pItemNo);
        NewUOM.Validate(Code, pCode);
        NewUOM.Validate("Qty. per Unit of Measure", QtyPerUOM);
        NewUOM.Insert(true);
    end;

สรุป (Summary)

การทำ Refactor ในภาษา AL Programming ไม่ใช่เพียงการจัดระเบียบโค้ดให้ดูดีขึ้นเท่านั้น แต่คือกระบวนการที่มีเป้าหมายเพื่อ

  • เพิ่มความชัดเจน (Readability) ให้โค้ดอ่านง่าย เข้าใจไว
  • ลดความซับซ้อน (Maintainability) แก้ไขและดูแลในระยะยาวได้ง่ายขึ้น
  • รองรับการขยายฟีเจอร์ (Extensibility) ในอนาคตโดยไม่กระทบโค้ดเดิม
  • ช่วยในการทดสอบ (Testability) โดยแยก Logic ออกเป็นฟังก์ชันย่อยได้

เมื่อโค้ดมีโครงสร้างที่ดีจากการ Refactor แล้ว จะช่วยให้สามารถพัฒนา ปรับปรุง และตรวจสอบคุณภาพได้อย่างมีประสิทธิภาพมากยิ่งขึ้น โดยเฉพาะในระบบ Business Central ที่ต้องการความแม่นยำ เสถียร และสามารถต่อยอดได้ในทุกเวอร์ชันของ Extension.