bcquality/custom/knowledge/breaking-changes/cmfrt-never-delete-always-obsolete.md
BeytullahCengiz88 c72c0ad685 Add CMFRT coding standards documentation and examples
- Introduced guidelines for "one codeunit one global function" architecture to enforce single responsibility in AL code.
- Added best practices and anti-patterns for adding parameters via overloads to maintain backward compatibility.
- Documented the importance of never deleting members in AL and always marking them as obsolete.
- Established the requirement for OnBefore and OnAfter integration events for global procedures to enhance extensibility.
- Defined naming conventions for CMFRT objects, including prefixes and object ID ranges to avoid conflicts.
- Implemented patterns for case statements to ensure all cases are handled, including the necessity of an else clause.
- Introduced the interface injection pattern to allow pluggable operations in table-level code.
- Recommended using Confirm Management for user confirmations to improve testability.
- Established a three-permission set pattern for security to ensure proper access control.
- Created a review skill for CMFRT AL standards to automate compliance checks against established guidelines.
2026-07-02 13:12:09 +00:00

1.8 KiB

bc-version domain keywords technologies countries application-area
all
breaking-changes
obsolete
delete
remove
breaking-change
backward-compatibility
obsolete-state
obsolete-reason
al
w1
all

CMFRT never delete — always obsolete

Description

In a CMFRT extension the following AL members must never be physically deleted: global procedures, table fields, page fields, enum values, and entire objects. Removing any of these breaks dependent extensions and upgrade paths without a compiler warning. The required approach is to retain the member, mark it with ObsoleteState = Pending when deprecation begins, and promote to ObsoleteState = Removed in a subsequent release after dependents have migrated. All obsoleted members are placed at the end of their containing object so that active code is never mixed with retired code.

Best Practice

When a member is no longer needed, keep it in place, add ObsoleteState = Pending, ObsoleteReason = '<explanation>', and ObsoleteTag = '<task-id>'. In a later release, promote to ObsoleteState = Removed. For fields, add the replacement field first, then obsolete the original. For procedures, add the replacement first, then obsolete the original. Provide an upgrade codeunit procedure whenever a field rename or type change requires data migration.

See sample: cmfrt-never-delete-always-obsolete.good.al.

Anti Pattern

Deleting a global procedure, table field, page field, enum value, or entire AL object from the extension source. Physical deletion produces compiler errors in every dependent extension that referenced the removed member, and for table fields it causes data loss and upgrade failures in existing customer databases.

See sample: cmfrt-never-delete-always-obsolete.bad.al.