Refactoring Exercises

Refactoring Exercises

Refactoring is the process of restructuring existing code without changing its external behavior to improve its readability, maintainability, and performance. Here are some refactoring exercises that will help you practice and enhance your refactoring skills:

1. Extract Method

  • Before Refactoring
void processOrder(Order order) {
  // Validate order
  if (order.items.isEmpty) {
    throw Exception('Order is empty');
  }
  // Calculate total
  double total = 0;
  for (var item in order.items) {
    total += item.price * item.quantity;
  }
  // Print receipt
  print('Receipt for Order:');
  for (var item in order.items) {
    print('${item.name}: ${item.quantity} x ${item.price}');
  }
  print('Total: $total');
}
  • After Refactoring
void processOrder(Order order) {
  validateOrder(order);
  double total = calculateTotal(order);
  printReceipt(order, total);
}

void validateOrder(Order order) {
  if (order.items.isEmpty) {
    throw Exception('Order is empty');
  }
}

double calculateTotal(Order order) {
  double total = 0;
  for (var item in order.items) {
    total += item.price * item.quantity;
  }
  return total;
}

void printReceipt(Order order, double total) {
  print('Receipt for Order:');
  for (var item in order.items) {
    print('${item.name}: ${item.quantity} x ${item.price}');
  }
  print('Total: $total');
}

2. Inline Method

  • Before Refactoring
void processOrder(Order order) {
  double total = calculateTotal(order);
  print('Total: $total');
}

double calculateTotal(Order order) {
  return order.items.fold(0, (sum, item) => sum + item.price * item.quantity);
}
  • After Refactoring
void processOrder(Order order) {
  double total = order.items.fold(0, (sum, item) => sum + item.price * item.quantity);
  print('Total: $total');
}

3. Rename Variable

  • Before Refactoring
void calculateTotal(List<Item> items) {
  double t = 0;
  for (var item in items) {
    t += item.price * item.quantity;
  }
  print('Total: $t');
}
  • After Refactoring
void calculateTotal(List<Item> items) {
  double total = 0;
  for (var item in items) {
    total += item.price * item.quantity;
  }
  print('Total: $total');
}

3. Replace Magic Number with Named Constant

  • Before Refactoring
double calculateFinalPrice(double price) {
  return price * 0.85;
}
  • After Refactoring
const double discountRate = 0.85;

double calculateFinalPrice(double price) {
  return price * discountRate;
}

5. Encapsulate Field

  • Before Refactoring
class Person {
  String name;
}
  • After Refactoring
class Person {
  String _name;

  String get name => _name;
  set name(String value) {
    if (value.isNotEmpty) {
      _name = value;
    } else {
      throw Exception('Name cannot be empty');
    }
  }
}

6. Introduce Expalining Variable

  • Before Refactoring
void calculateFinalPrice(double price, double discount) {
  print(price - price * discount * 0.01);
}
  • After Refactoring
void calculateFinalPrice(double price, double discount) {
  double discountAmount = price * discount * 0.01;
  double finalPrice = price - discountAmount;
  print(finalPrice);
}

7. Simplify Conditional Expression

  • Before Refactoring
double calculateShippingCost(double weight) {
  if (weight < 5) {
    return 10;
  } else {
    return 20;
  }
}
  • After Refactoring
double calculateShippingCost(double weight) {
  return weight < 5 ? 10 : 20;
}

8. Replace Nested Conditional With Guard Clauses

  • Before Refactoring
double calculateDiscount(double price, bool isMember) {
  if (isMember) {
    if (price > 100) {
      return price * 0.1;
    } else {
      return price * 0.05;
    }
  } else {
    return 0;
  }
}
  • After Refactoring
double calculateDiscount(double price, bool isMember) {
  if (!isMember) {
    return 0;
  }
  if (price > 100) {
    return price * 0.1;
  }
  return price * 0.05;
}

9. Remove Duplicate Code

  • Before Refactoring
void renderAdminPage() {
  print('Header');
  print('Admin Content');
  print('Footer');
}

void renderUserPage() {
  print('Header');
  print('User Content');
  print('Footer');
}
  • After Refactoring
void renderPage(String content) {
  print('Header');
  print(content);
  print('Footer');
}

void renderAdminPage() {
  renderPage('Admin Content');
}

void renderUserPage() {
  renderPage('User Content');
}

10. Replace loop with Collection Operations

  • Before Refactoring
List<int> doubleValues(List<int> values) {
  List<int> result = [];
  for (var value in values) {
    result.add(value * 2);
  }
  return result;
}
  • After Refactoring
List<int> doubleValues(List<int> values) {
  return values.map((value) => value * 2).toList();
}