Lesson 9 of 54

The Art of Naming

Naming Classes, Types, and Interfaces

A class name reveals what it's responsible for. When a class is named OrderManager, I worry. Managers tend to do everything. When a class is named OrderValidator, I know exactly what it does.

Class names are nouns. They represent things. But not all nouns are created equal.

Nouns That Represent Responsibilities

A good class name describes a single, clear responsibility.

Typescript
// Clear, focused responsibilities
class PaymentProcessor { }     // Processes payments
class EmailSender { }          // Sends emails
class PasswordHasher { }       // Hashes passwords
class OrderValidator { }       // Validates orders
class InvoiceGenerator { }     // Generates invoices
class SessionManager { }       // Manages sessions (scope is clear)

Each name tells you:

  1. What domain it belongs to
  2. What operation it performs
  3. Implicitly, what it doesn't do

Words to Avoid (Usually)

Manager

What does a manager do? Everything. That's the problem.

Typescript
// Suspicious: What doesn't this do?
class UserManager {
  createUser() { }
  validateUser() { }
  authenticateUser() { }
  sendWelcomeEmail() { }
  trackAnalytics() { }
  updatePreferences() { }
}

This class probably violates single responsibility. Split it:

Typescript
class UserRepository { }      // CRUD operations
class UserValidator { }       // Validation logic
class AuthenticationService { } // Login/logout
class UserNotifier { }        // Emails and notifications
class UserAnalytics { }       // Tracking
class PreferencesService { }  // User settings

Handler

Handler implies "deals with" but doesn't say how.

Typescript
// Vague
class ErrorHandler { }

// Specific
class ErrorLogger { }         // Logs errors
class ErrorNotifier { }       // Sends alerts
class ErrorRecovery { }       // Attempts recovery

Processor

Same problem. What kind of processing?

Typescript
// Vague
class DataProcessor { }

// Specific
class CsvParser { }           // Parses CSV
class DataNormalizer { }      // Normalizes format
class DataValidator { }       // Validates content
class DataExporter { }        // Exports data

When These Words Are Okay

Sometimes Manager or Handler is genuinely the right name:

Typescript
// These are actually about managing
class ConnectionPoolManager { }  // Manages a pool of connections
class CacheManager { }           // Manages cache lifecycle
class TransactionManager { }     // Manages transaction boundaries

// This is actually about handling
class WebhookHandler { }         // Handles incoming webhooks (entry point)
class ExceptionHandler { }       // Framework-level exception handling

The test: can you explain what the class manages or handles in one sentence? If yes, the name might be fine. If no, split it.

Entity vs. Service Naming

Entities: Pure Nouns

Entities represent domain objects:

Typescript
class User { }
class Order { }
class Product { }
class Invoice { }
class ShoppingCart { }

They hold data and domain logic related to that data.

Services: Noun + Action Hint

Services perform operations, often on entities:

Typescript
class OrderService { }        // Operations on orders
class PaymentGateway { }      // Interface to payment provider
class ShippingCalculator { }  // Calculates shipping costs
class TaxCalculator { }       // Calculates taxes

Repository: Data Access

Repositories handle persistence:

Typescript
class UserRepository { }      // CRUD for users
class OrderRepository { }     // CRUD for orders

Interface Naming Conventions

Different languages have different conventions. Pick one and be consistent.

Prefix with I (C#, some TypeScript)

Typescript
interface IUserRepository { }
interface IPaymentProcessor { }
class UserRepository implements IUserRepository { }

No prefix, implementations are "Impl" (Java-style)

Typescript
interface UserRepository { }
class UserRepositoryImpl implements UserRepository { }

No prefix, implementations are specific (preferred in modern TypeScript)

Typescript
interface PaymentProcessor { }
class StripePaymentProcessor implements PaymentProcessor { }
class PayPalPaymentProcessor implements PaymentProcessor { }

Suffix with "Interface" (explicit)

Typescript
interface UserRepositoryInterface { }

My Recommendation

Use implementation-specific names when you have multiple implementations:

Typescript
interface Cache { }
class RedisCache implements Cache { }
class InMemoryCache implements Cache { }

Use simple names when there's only one implementation:

Typescript
// No need for interface complexity if there's only one
class EmailService { }

Don't create interfaces for the sake of interfaces.

Type Aliases and Domain Types

Type aliases can encode domain rules:

Typescript
// Weak: string could be anything
function sendEmail(to: string, from: string, subject: string) { }

// Strong: types encode meaning
type EmailAddress = string;
type Subject = string;
type Body = string;

function sendEmail(to: EmailAddress, from: EmailAddress, subject: Subject) { }

Even better with branded types:

Typescript
type UserId = string & { readonly brand: unique symbol };
type OrderId = string & { readonly brand: unique symbol };

// Now these can't be mixed up
function getOrdersForUser(userId: UserId): Order[] { }

Avoid Redundant Suffixes

In a folder called models/, you don't need:

Text
models/
  UserModel.ts      // "Model" is redundant
  OrderModel.ts

Just use:

Text
models/
  User.ts
  Order.ts

The context (folder) provides the information.

Consistency Across the Codebase

Whatever conventions you choose, apply them everywhere:

  • If you use UserService, use OrderService, not OrderHelper
  • If you use UserRepository, use OrderRepository, not OrderDao
  • If you suffix interfaces with Interface, do it everywhere

Inconsistency creates cognitive load. Every time someone encounters a new convention, they have to figure out if it means something different.


Key insight: Class names should describe a single responsibility. Avoid vague names like Manager, Handler, Processor unless the class genuinely manages/handles/processes exactly one well-defined thing. When you can't name a class simply, it's probably doing too much.