Delphi Legacy Projects : Strategies and Survival Guide
Writed by : William Meyer
Published date : 02/06/2022
ISBN-13 : 9798833375693
Language : English
Web site : https://wmeyer.tech/books/
Delphi has been in wide use for over 25 years, and there are many legacy projects which are still in active production. This volume offers approaches to refactoring and modernizing the code base without the need for complete redesign and rewrite. Evolution, not revolution. These are approaches well suited to the incremental revision of production code, as is usually the concern with a commercial product.
A paper book is available from Amazon but you also can buy a PDF from author's website.
Contents
Preface
1 Frame of Reference
1.1 Your Current Practice
1.2 More Thoughtful Coding
2 Introducing the Problem
2.1 Purpose and Perspective
2.2 Areas of Difficulty
2.2.1 Evolution, not Revolution
2.3 We May Be the Enemy
2.3.1 Too Many Components?
2.3.2 Abusing the Search Path
2.3.3 Coding Too Soon?
2.3.4 Inheritance
2.3.5 Excessive Coupling
2.3.6 Unit Dependency Cycles
2.4 The IDE, Again
3 Strategies
3.1 Philosophy and Reality
3.2 Setting Goals
3.2.1 Patience
3.3 Select Your Components
3.4 Pre-convert, if Necessary
3.5 Isolate Your Code
3.6 Achieving a Build
3.7 Module Inclusion
3.8 Separating Projects - How and Why
3.8.1 Multiple Projects in One Delphi Version
3.8.2 Multiple Projects in Multiple Delphi Versions
3.9 Start Small
3.10 Incremental Change
3.11 Strip Deadwood
4 Beginning
4.1 The IDE
4.2 The Build Process
4.2.1 Build Management
4.2.2 Accept Compiler Advice
4.3 Data and Code
4.3.1 Scope of Data
4.3.2 Writeable “Constants”
4.4 Scope in General
4.4.1 Forms vs. Units
4.4.2 Proper to Forms
4.4.3 Proper to Class Units
4.4.4 Proper to Data Modules
4.4.5 Everything Private!
4.4.6 Global not Always Bad
4.4.7 Partitioning
4.5 Exception Handling
4.5.1 A Simple Example
4.5.2 Exceptional Failures
4.5.3 Exceptional Confusion
4.5.4 Scope of Exception Handlers
4.5.5 Default Exception Handlers
4.6 Code Formatting
4.6.1 Formatting Matters
4.6.2 Manageable Formatting
4.6.3 Minor Formatting
Digging Into the Challenges
5 Comments
5.1 Useless Comments
5.2 Annoying Comments
5.3 Thoughtless Comments
5.4 Essential Comments
6 Cleaning Uses Clauses
6.1 Initialization
6.1.1 Independent Factors
6.1.2 Initialization of Units
6.2 Removing Dead and Duplicate Units
6.2.1 ProjectFiles Tool
6.2.2 Other Useful Tools
6.3 Removing and Demoting Unit References
6.4 Using the Tools
6.5 Unit Dependency Cycles
6.6 Collecting the UDCs
7 Simple Things
7.1 Structural Changes in Delphi
7.2 Hints and Warnings
7.3 Types and Constants
7.3.1 No Magic Numbers
7.3.2 Unicode?
7.3.3 Numeric Type Aliases
7.3.4 Global can be OK
7.3.5 Assignment Compatibility
7.3.6 Use Enumerations
7.3.7 Use Sets
7.3.8 Use Defined Ranges
7.4 Variables and Scope
7.4.1 Avoid Global Variables
7.4.2 Using AOwner
7.5 Forms
7.5.1 Form Variables
7.5.2 Form File Format
7.6 Delphi Versions
8 Not so Simple Things
8.1 Persistence in Settings
8.1.1 Persistence with Enumerations
8.2 Dangers in Use of ClassName
8.2.1 Decoupling with a Dictionary
8.3 Reviewing Code
9 Cleaning Legacy Code
9.1 Local Variables
9.1.1 I/O Checking
9.1.2 Overflow Checking
9.1.3 Range Checking
9.1.4 Rename Local Variables
9.1.5 Remove Local Variables
9.2 Remove Wrappers
9.3 Coding Style
9.4 Form State
9.4.1 Form State Components
9.5 Form vs. Code Dependency
9.6 Types & Consts Again
9.6.1 Doppelgangers
9.7 Misplaced Routines
10 Local Components
10.1 Component Basics
10.2 Managing Components
10.3 Component Pitfalls
10.3.1 Components Doing Too Much
10.3.2 Bad Assumptions
10.3.3 Failing to Handle Exceptions
10.3.4 Mixing Component and Application Code
10.4 Cleaning House
10.4.1 Use Library Modules
10.4.2 Keep the interface uses Clause Small
10.4.3 Refactor Utility Units
11 Refactoring
11.1 A Workable Approach to Small Change
11.2 The Value of a Data Module
11.3 Testing in a Data Module
11.3.1 Information Hiding
11.3.2 Minimizing Points of Contact
11.4 The Challenge of Testing
11.4.1 Massive Routines
11.4.2 Massive Coupling
11.4.3 Risk is Unavoidable
11.5 Code for the Maintainer
11.5.1 Resources
11.6 Prefer Library Code
11.7 Use Nested Routines
11.8 Extract Classes
11.9 Prefer Composition
11.9.1 The Public Interface
11.9.2 The Private Behaviors
11.9.3 Notes on Implementation
12 Removing Code from Forms
12.1 Extract Utility Routines
12.1.1 Refactoring Praxis
12.2 Building Utility Units
12.3 Shared Classes
12.4 Use Data Modules
12.4.1 Common Operations
12.5 Separate Business Logic
12.5.1 What is Business Logic?
12.5.2 Organization
12.5.3 Separate Data Handling
13 Fixing Erroneous Coding
13.1 Errors of Function
13.2 Reduce Noise
13.3 Reduce Logic
13.3.1 Using Partial Products
13.3.2 Prefer Positive Logic
13.4 Loop Forms
13.5 Minimize Tests
13.6 Use Arrays
13.6.1 Static Arrays
13.6.2 Dynamic Arrays
13.6.3 Open Arrays
13.6.4 Generic Arrays
13.6.5 Constant Arrays
13.6.6 Arrays vs. Cases
13.7 Summary
14 Class and Record Helpers
14.1 Alternative Approaches
14.2 TStringHelper
14.3 Legacy Cleanup
14.4 More Insights
15 Using Datasets Well
15.1 TField Properties
15.2 Component Differences
15.3 Normalize Data
15.4 Less Specificity
15.5 Think Before Coding
16 Pragmatism
16.1 Assessing the Costs
16.2 Measuring Value
16.2.1 Use EurekaLog
16.2.2 Use Analytics
16.3 Missing Source Code
16.4 Analytical Modules
16.5 Little-Used Modules
17 Interfaces
17.1 History
17.2 Reducing Scope
17.2.1 Constants and Types
17.2.2 Properties
17.3 Managing Memory
17.4 Examples
17.5 Going Deeper
17.5.1 Variations
18 Testability
18.1 Testing Legacy Code
18.2 Layers of Difficulty
18.3 Design Specifications
18.4 Interdependency Issues
18.5 Coupling, Partitioning
18.6 Code on Forms
18.7 Testability Defined
18.8 Ensure Testability
18.9 Unit Test Frameworks
18.10 Testing Practices
19 Performance
19.1 Realities
19.1.1 Profiling
19.1.2 Profiling Legacy Code
19.1.3 Approaching Profiling
19.2 Painful Realities
19.3 You Need Tools
20 Disruptive Forces
20.1 Code Details
20.1.1 Hints and Warnings
20.1.2 Static Analysis
20.2 Component Issues
20.2.1 Orphaned Components
20.2.2 Local Components
20.3 Dependency Cycles
20.3.1 The Gordian Knot
20.3.2 Small Steps
20.3.3 Larger Steps
20.3.4 Cycles in Components
20.4 Compiler Versions
20.5 Issues You must Find
Best Practices
21 Some Simple Principles
21.1 Principle of Least Astonishment
21.2 DRY: Don’t Repeat Yourself
21.2.1 The Rule of Three
21.2.2 Causes of Repetition
21.2.3 Using the Libraries
21.2.4 String Utilities
21.2.5 Date and Time Utilities
21.3 YAGNI: You Ain’t Gonna Need It
21.4 SOC: Separation of Concerns
22 SOLID
22.1 What is SOLID?
22.1.1 Single Responsibility
22.1.2 Open/Closed
22.1.3 Liskov Substitution
22.1.4 Interface Segregation Principle
22.1.5 Dependency Inversion
23 Inheritance, Aggregation, Composition
23.1 Inheritance
23.2 Composition
23.3 Aggregation
24 Design Patterns
24.1 Anti-patterns
24.2 Delphi Idioms
24.2.1 Create/Destroy
24.2.2 If/Else
24.2.3 Helpers
24.2.4 Smart Pointers
24.3 Recommended Practices
24.4 Patterns of Interest
24.4.1 Adapter Pattern
24.4.2 Facade Pattern
24.4.3 Dependency Injection
24.5 Summary
25 Dependency Injection
25.1 Starting Small
25.2 Types of Injection
25.2.1 Constructor Injection
25.2.2 Property Injection
25.2.3 Method Injection
25.3 Summary
26 Unit Testing
26.1 DUnit
26.2 DUnit2
26.3 DUnitX
26.4 TestInsight
26.5 Delphi Mocks
Appendix: Tools
27 Tools Overview
27.1 IDE Plug-ins
27.2 Standalone
27.3 Some Disclaimers
28 CnPack
28.1 Structural Highlighting
28.2 Tab Order
28.3 Uses Cleaner
28.4 CnPack Summary
29 CodeSite
29.1 Details in Your Hands
29.2 Data from the Field
29.3 Simple Example
30 Delphi Mocks
30.1 Delphi Mocks in Use
30.2 Why Mock?
30.3 When to Mock
30.4 Summary
31 Documentation Insight
32 Delphi Unit Dependency Scanner
33 DUNIT
33.1 DUnit in Recent IDEs
33.2 Developing Test Cases
33.3 Start with the Familiar
33.4 Coverage in Legacy Projects
33.5 Test Driven Development
33.6 Unit Test Lifetime
33.7 Summary
34 DUnit2
35 DUnitX
35.1 Looking at Some Code
35.1.1 DUnit vs. DUnitX Features
35.2 DUnit vs. DUnitX
35.3 Summary
36 FixInsight
36.1 Real World Data
37 GExperts
37.1 Configuration
37.2 Editor Experts
37.3 Replace Components
37.4 GREP Search
37.5 GExperts Summary
38 Homebrew Tools
38.1 Cycles Analyzer
38.1.1 Cycles Analyzer Code
38.1.2 Dependency Cycles in Components
38.1.3 Unit Dependencies: A Closer View
38.2 Map Explorer
38.3 Component Collector
38.3.1 Collecting Installed Components
38.3.2 Collecting the DFM Files List
38.3.3 Collect Component Instances
38.3.4 Producing the Aggregate Component Data
38.3.5 Putting Together the Pieces
38.4 Separating Wheat and Chaff
39 MapFileStats
40 MMX
40.1 Add Class
40.2 Add Field
40.3 Add Method
40.4 Sort Class
40.5 Synchronize Signatures
40.6 Swap Scopes
40.7 Unit Dependency Analyzer
40.8 Summary
41 Peganza Products
41.1 Overview
41.2 Pascal Analyzer
41.3 Pascal Expert
41.4 Pascal Browser
42 ProDelphi
42.1 Profiling Some Demo Code
42.1.1 Considering ExportDataSetToCSV
42.2 Profiling, in General
42.2.1 Why Profile, Why Optimize?
43 TestInsight
Bibliography
Alphabetical Index