Defactoring is a refactoring technique where you deliberately inline code to understand it better before extracting it in a more meaningful way.
Core Concept
When code is poorly factored or abstracted in confusing ways, inline it first (defactor), understand the full behavior, then extract it properly with better names and structure.
The Inline-Then-Extract Pattern
Step 1: Inline the Abstraction
// Before - unclear service method
public class OrderService
{
public void ProcessOrder(Order order)
{
ValidateOrder(order);
ApplyBusinessRules(order);
SaveOrder(order);
}
}
// Step 1: Inline everything to see what's really happening
public class OrderService
{
public void ProcessOrder(Order order)
{
// Inlined ValidateOrder
if (order.Items.Count == 0)
throw new InvalidOperationException();
// Inlined ApplyBusinessRules
if (order.Total > 100)
order.ApplyDiscount(0.1m);
// Inlined SaveOrder
_repository.Save(order);
}
}Step 2: Extract with Better Understanding
Now you can see that this logic belongs on the Order entity itself:
// Step 2: Extract to the right place
public class Order
{
public void Validate()
{
if (Items.Count == 0)
throw new InvalidOperationException("Cannot process empty order");
}
public void ApplyVolumePricing()
{
if (Total > 100)
ApplyDiscount(0.1m);
}
}
// Application layer coordinates the workflow
public class PlaceOrderHandler
{
public void Handle(PlaceOrderCommand command)
{
var order = _repository.GetById(command.OrderId);
order.Validate();
order.ApplyVolumePricing();
_repository.Save(order);
}
}Domain-Driven Defactoring
Pushing Behavior Down: Defactoring often reveals that business logic extracted into services actually belongs in the domain model.
Anti-Pattern: Anemic Domain Model
// BAD: Domain object is just a data container
public class Order
{
public List<OrderLine> Lines { get; set; }
public decimal Total { get; set; }
}
// Service does all the work
public class OrderService
{
public void AddLine(Order order, Product product, int quantity)
{
order.Lines.Add(new OrderLine { Product = product, Quantity = quantity });
order.Total += product.Price * quantity;
}
}After Defactoring: Rich Domain Model
// GOOD: Domain object has behavior
public class Order
{
private List<OrderLine> _lines = new();
public void AddLine(Product product, int quantity)
{
_lines.Add(new OrderLine(product, quantity));
RecalculateTotal();
}
private void RecalculateTotal()
{
Total = _lines.Sum(l => l.Subtotal);
}
public decimal Total { get; private set; }
}When to Defactor
- Code is confusingly abstracted
- Methods have misleading names
- You can’t understand what code does without jumping through multiple files
- Service classes are doing work that belongs in domain entities
- You suspect the wrong abstraction exists
Resources
Related Concepts
- ENOF - Another technique for unclear code
- Refactoring - Broader refactoring techniques
- Anemic Domain Model - Anti-pattern defactoring addresses
- Good Software Practices