Single Level of Abstraction Principle

The Single Level of Abstraction (SLA) principle suggests that each function or method should work at one level of detail. This ensures the function focuses on a specific task, making the code easier to read, understand, and maintain.

SLA violation example

Let’s consider a simple example where we process an order.

async function processOrder(order) {
  if (!order.items || order.items.length === 0) {
    throw new Error('Order must have at least one item.');
  }

  let totalPrice = 0;

  for (const item of order.items) {
    totalPrice += item.price * item.quantity;
  }

  const result = await orders.insertOne({ order, totalPrice });

  return result.insertedId;
}

We can see that it does multiple things:

It’s difficult to understand what the function is doing at a glance and it violates the SLA principle.

Refactoring for Clarity

Now, let’s break this down into smaller functions, each focusing on a single task.

function validateOrder(order) {
  if (!order.items || order.items.length === 0) {
    throw new Error('Order must have at least one item.');
  }
}

function calculateTotalPrice(items) {
  let totalPrice = 0;

  for (const { price, quantity } of items) {
    totalPrice += price * quantity;
  }

  return totalPrice;
}

async function saveOrderToDatabase(order, totalPrice) {
  const result = await orders.insertOne({ order, totalPrice });

  return result.insertedId;
}

async function processOrder(order) {
  validateOrder(order);

  const totalPrice = calculateTotalPrice(order.items);

  const orderId = await saveOrderToDatabase(order, totalPrice);

  return orderId;
}

In this improved example:

The processOrder function now handles these tasks clearly and keeps things at same level of abstraction.

Each function can be tested independently, making the codebase cleaner and easier to manage.


Find this post helpful? Subscribe and get notified when I post something new!