agentsclimarketplace

Refactor

Skill tbc-servicos/dataagile-agent-kit/protheus/skills/refactor

Plugin Claude Code para Protheus e ADVPL/TLPP — base 155k+ registros, Agent Teams, compilação TDS-CLI, testes TIR e MCP PO-UI

Install
npx -y skills add tbc-servicos/dataagile-agent-kit --skill refactor

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Surgical code refactoring to improve maintainability without changing behavior. Covers extracting functions, renaming variables, breaking down god functions, improving type safety, eliminating code smells, and applying design patterns. Less drastic than repo-rebuilder; use for gradual improvements. Use when user says 'refactor this code', 'extract function', 'reduce complexity', 'code smells'.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

15.1 KB, as published. Nobody here has run it

Refactor

Overview

Improve code structure and readability without changing external behavior. Refactoring is gradual evolution, not revolution. Use this for improving existing code, not rewriting from scratch.

When to Use

Use this skill when:

  • Code is hard to understand or maintain
  • Functions/classes are too large
  • Code smells need addressing
  • Adding features is difficult due to code structure
  • User asks "clean up this code", "refactor this", "improve this"

Refactoring Principles

The Golden Rules

  1. Behavior is preserved - Refactoring doesn't change what the code does, only how
  2. Small steps - Make tiny changes, test after each
  3. Version control is your friend - Commit before and after each safe state
  4. Tests are essential - Without tests, you're not refactoring, you're editing
  5. One thing at a time - Don't mix refactoring with feature changes

When NOT to Refactor

- Code that works and won't change again (if it ain't broke...)
- Critical production code without tests (add tests first)
- When you're under a tight deadline
- "Just because" - need a clear purpose

Common Code Smells

Identify and fix these common code smells. See references/code-smells-and-patterns.md for detailed before/after examples.

#SmellFix
1Long Method/FunctionBreak into focused functions
2Duplicated CodeExtract common logic
3Large Class/ModuleSingle responsibility per class
4Long Parameter ListGroup into parameter objects or use builder
5Feature EnvyMove logic to the object that owns the data
6Primitive ObsessionUse domain types
7Magic Numbers/StringsNamed constants
8Nested ConditionalsGuard clauses / early returns
9Dead CodeRemove it (git has history)
10Inappropriate IntimacyAsk, don't tell — use encapsulation
11IIF UsageReplace IIF() / IF() with If/Else/EndIf for clarity and testability
12API Calls in LoopsMove GetMV(), ExistBlock(), Type() out of loops — cache before loop
13UI in TransactionsNever call MsgAlert, MsgYesNo, Aviso, Help inside transaction scope
14SQL Injection via ConcatenationReplace string concatenation in queries with FWExecStatement
15ISAM Driver UsageMigrate MSCREATE, DBCREATE, CRIATRAB to FWTemporaryTable

Refactoring Techniques

Detailed examples in references/code-smells-and-patterns.md:

  • Extract Method — Turn code fragments into focused methods
  • Introduce Type Safety — Add types to parameters, returns, and variables
  • Strategy Pattern — Replace conditional logic with polymorphism
  • Chain of Responsibility — Replace nested validation with composable validators

Refactoring Steps

Safe Refactoring Process

1. PREPARE
   - Ensure tests exist (write them if missing)
   - Commit current state
   - Create feature branch

2. IDENTIFY
   - Find the code smell to address
   - Understand what the code does
   - Plan the refactoring

3. REFACTOR (small steps)
   - Make one small change
   - Run tests
   - Commit if tests pass
   - Repeat

4. VERIFY
   - All tests pass
   - Manual testing if needed
   - Performance unchanged or improved

5. CLEAN UP
   - Update comments
   - Update documentation
   - Final commit

Refactoring Checklist

Code Quality

  • Functions are small (< 50 lines)
  • Functions do one thing
  • No duplicated code
  • Descriptive names (variables, functions, classes)
  • No magic numbers/strings
  • Dead code removed

Structure

  • Related code is together
  • Clear module boundaries
  • Dependencies flow in one direction
  • No circular dependencies

Type Safety

  • Types defined for all public APIs
  • No any types without justification
  • Nullable types explicitly marked

Testing

  • Refactored code is tested
  • Tests cover edge cases
  • All tests pass

Common Refactoring Operations

OperationDescription
Extract MethodTurn code fragment into method
Extract ClassMove behavior to new class
Extract InterfaceCreate interface from implementation
Inline MethodMove method body back to caller
Inline ClassMove class behavior to caller
Pull Up MethodMove method to superclass
Push Down MethodMove method to subclass
Rename Method/VariableImprove clarity
Introduce Parameter ObjectGroup related parameters
Replace Conditional with PolymorphismUse polymorphism instead of switch/if
Replace Magic Number with ConstantNamed constants
Decompose ConditionalBreak complex conditions
Consolidate ConditionalCombine duplicate conditions
Replace Nested Conditional with Guard ClausesEarly returns
Introduce Null ObjectEliminate null checks
Replace Type Code with Class/EnumStrong typing
Replace Inheritance with DelegationComposition over inheritance

AdvPL/TLPP Refactoring Patterns

When refactoring AdvPL or TLPP source files (.prw, .tlpp, .prx, .th), apply the general principles above plus these ecosystem-specific patterns.

File Extension Rule: If a refactoring introduces #include "tlpp-core.th" or any TLPP-exclusive feature (typing, Try-Catch, Namespace, etc.), the file must be renamed from .prw/.prx to .tlpp. TLPP directives are silently ignored in non-.tlpp files.

Variable Scope Tightening

Replace Private variables with Local wherever the variable is not intentionally shared with called functions. Private leaks into every function on the call stack; Local does not.

// BAD: Private leaks into every called function
- User Function ProcessOrder()
-   Private cOrder := ""
-   Private nTotal := 0
-   Private lOk    := .T.
-   // ... business logic ...
- Return

// GOOD: Local variables stay in scope
+ User Function ProcessOrder()
+   Local cOrder := "" as Character
+   Local nTotal := 0  as Numeric
+   Local lOk    := .T. as Logical
+   // ... business logic ...
+ Return

Extract Static Functions from Monolithic User Functions

Protheus legacy routines commonly pack hundreds of lines into a single User Function. Extract cohesive blocks into Static Function helpers.

// BAD: Monolithic Function (300+ lines)
- User Function FINA010()
-   // 60 lines: header validation
-   // 80 lines: item processing
-   // 50 lines: tax calculation
-   // 40 lines: ledger posting
-   // 70 lines: notification
- Return

// GOOD: Decomposed into focused Static Functions
+ User Function FINA010()
+   Local lOk as Logical
+   lOk := ValidateHeader()
+   If lOk
+     lOk := ProcessItems()
+   EndIf
+   If lOk
+     lOk := CalculateTaxes()
+   EndIf
+   If lOk
+     lOk := PostToLedger()
+   EndIf
+   If lOk
+     SendNotifications()
+   EndIf
+ Return
+
+ Static Function ValidateHeader() as Logical
+   // focused header validation
+ Return lRet
+
+ Static Function ProcessItems() as Logical
+   // focused item processing
+ Return lRet

Add TLPP Type Annotations

TLPP supports compile-time type checking. Add type annotations to variables, parameters, and return values to catch mismatches early.

// BAD: Untyped parameters and return (AdvPL legacy style)
- Static Function CalcTotal(cClient, aItems)
-   Local nTotal := 0
-   // ...
- Return nTotal

// GOOD: Fully typed (TLPP)
+ Static Function CalcTotal(cClient as Character, aItems as Array) as Numeric
+   Local nTotal := 0 as Numeric
+   Local nI     := 0 as Numeric
+   For nI := 1 To Len(aItems)
+     nTotal += aItems[nI][2] * aItems[nI][3]  // qty * price
+   Next nI
+ Return nTotal

Replace ErrorBlock with Try-Catch (TLPP)

TLPP provides structured exception handling. Replace legacy ErrorBlock / BEGIN SEQUENCE patterns.

// BAD: AdvPL error handling with ErrorBlock
- Local bError := ErrorBlock({|e| DefError(e)})
- BEGIN SEQUENCE
-   // risky operation
- END SEQUENCE
- ErrorBlock(bError)

// GOOD: TLPP Try-Catch
+ Try
+   // risky operation
+ Catch oError
+   FWLogMsg("ERROR", , "APP", "MyFunction", , "01", oError:Description, 0, 0, {})
+   // handle or re-throw
+ EndTry

Eliminate Macro-Execution Where Possible

Macro-execution (&cExpr) is a common source of injection risk and hard-to-debug behavior. Replace with safer alternatives.

// BAD: Macro-execution for dynamic field access
- cField := "SA1->A1_NOME"
- xValue := &(cField)

// GOOD: FieldGet / indirect access
+ cAlias := "SA1"
+ cField := "A1_NOME"
+ xValue := (cAlias)->(FieldGet(FieldPos(cField)))

Replace StaticCall with Direct Method Calls (TLPP)

StaticCall is prohibited in TLPP. Convert to direct static method invocation.

// BAD: AdvPL StaticCall (not allowed in TLPP)
- xResult := StaticCall(TMyClass, MyMethod, cParam)

// GOOD: TLPP direct static method call
+ xResult := TMyClass():MyMethod(cParam)

Workarea / Database Access Safety

Ensure every database write is wrapped in proper lock/unlock, and workareas are selected before use.

// BAD: Missing DbSelectArea and RecLock
- DbSetOrder(1)
- DbSeek(cKey)
- SA1->A1_NOME := cNewName
- MsUnlock()

// GOOD: Proper workarea selection and locking
+ DbSelectArea("SA1")
+ DbSetOrder(1)
+ If DbSeek(cKey)
+   If RecLock("SA1", .F.)
+     SA1->A1_NOME := cNewName
+     MsUnlock()
+   EndIf
+ EndIf

Replace Obsolete Includes with totvs.ch

Legacy include files are obsolete and must be replaced with totvs.ch. The old includes are consolidated into totvs.ch, which provides all definitions.

// BAD: Legacy obsolete includes
- #include "protheus.ch"
- #include "Ap5Mail.ch"
- #include "ApWizard.ch"
- #include "FileIO.ch"
- #include "Font.ch"
- #include "ParmType.ch"
- #include "RWMake.ch"

// GOOD: Single modern include
+ #include "totvs.ch"
Obsolete IncludeModern Class/API
Ap5Mail.chTMailMessage()
ApWizard.chFWWizardControl()
FileIO.chFWFileWriter() / FWFileReader()
Font.chTFont()
ParmType.chDefault prefix for parameter handling
protheus.ch— (general Protheus definitions)
RWMake.ch— (legacy compatibility)

Add Namespace Declarations (TLPP)

TLPP supports namespaces for modular code organization. Add them to new or migrated code.

// BAD: TLPP source without namespace (global scope pollution)
- #include "tlpp-core.th"
- Static Function Helper()
-   // ...
- Return

// GOOD: Namespaced TLPP source
+ #include "tlpp-core.th"
+ Namespace finance.receivable
+
+ Static Function Helper() as Logical
+   // ...
+ Return .T.

AdvPL/TLPP Refactoring Checklist

CheckDescription
ScopeAll Private variables reviewed — changed to Local unless intentionally shared
TypingTLPP sources have type annotations on variables, parameters, and returns
Function sizeNo User Function exceeds ~80 lines; excess extracted to Static Function
Error handlingTLPP code uses Try-Catch instead of ErrorBlock
Macro-execution&(cExpr) eliminated or justified with a comment
StaticCallConverted to direct static method calls in TLPP
Workarea safetyDatabase operations use DbSelectArea, RecLock, MsUnlock
NamespacesTLPP sources declare a Namespace
IncludesCorrect headers: totvs.ch (AdvPL) or tlpp-core.th (TLPP)
File extensionFiles using #include "tlpp-core.th" or TLPP features must have .tlpp extension — rename .prw/.prx accordingly
LoggingFWLogMsg() used instead of ConOut() / OutErr() / ?
IIFAll IIF() / IF() inline replaced with If/Else/EndIf blocks
SQL SafetyDynamic SQL values use FWExecStatement, not string concatenation
ISAMMSCREATE / DBCREATE / CRIATRAB migrated to FWTemporaryTable

Refer to references/sonarqube-rules-reference.md for the complete SonarQube rules reference.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.