Skip to main content

Naming conventions 2: functions and classes

This article is Part 2 of the three-part series on naming conventions. Building on the basics covered in Part 1: case conventions, variables, and constants, it covers naming conventions for functions, classes, and methods.

Naming conventions for functions

Start a function name with a verb that clearly expresses "what it does."

Basic patterns

Function name patterns

PatternExample
get + noungetUserById, getCurrentTime
set + nounsetUserName, setTheme
calculate + nouncalculateTotal, calculateAge
fetch + nounfetchUserData, fetchPosts
create + nouncreateUser, createElement
update + nounupdateProfile, updateSettings
delete + noundeleteUser, removeItem
validate + nounvalidateEmail, validateInput
convert + A + to + BconvertMinsToHours

Concrete examples

✅ Good: Function names with clear actions
// ✅ Good: Function names with clear actions

// get group: retrieving data (no side effects)
function getUserById(id: string): User | undefined {
return users.find(user => user.id === id);
}

function getCurrentTime(): Date {
return new Date();
}

function getFullName(firstName: string, lastName: string): string {
return `${firstName} ${lastName}`;
}

// set group: setting a value (has side effects)
function setTheme(theme: 'light' | 'dark'): void {
document.body.className = theme;
}

// calculate group: computation
function calculateTotalPrice(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}

function calculateAge(birthDate: Date): number {
const today = new Date();
return today.getFullYear() - birthDate.getFullYear(); // Simplified: it's off by one before the birthday
}

// fetch group: asynchronous data retrieval
async function fetchUserData(userId: string): Promise<User> {
const response = await fetch(`/api/users/${userId}`);
return response.json();
}

// create group: creating something new
function createUser(name: string, email: string): User {
return {
id: generateId(),
name,
email,
createdAt: new Date(),
};
}

// update group: updating
function updateUserProfile(userId: string, updates: Partial<User>): void {
const user = getUserById(userId);
if (user) {
Object.assign(user, updates);
}
}

// delete/remove group: deleting
function deleteUser(userId: string): boolean {
const index = users.findIndex(u => u.id === userId);
if (index !== -1) {
users.splice(index, 1);
return true;
}
return false;
}

// validate group: validation
function validateEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}

// convert group: conversion
function convertMinsToHours(minutes: number): number {
return minutes / 60;
}

function convertCelsiusToFahrenheit(celsius: number): number {
return (celsius * 9/5) + 32;
}

❌ Patterns to avoid

❌ Bad: Patterns to avoid
// ❌ Bad: Too abstract
function process(data: any) {
// Unclear what it processes
}

function handle(value: string) {
// Unclear what it handles
}

function doSomething() {
// Unclear what it does
}

// ✅ Good: Concrete
function processPayment(payment: Payment) {
// Clearly processes a payment
}

function handleUserInput(input: string) {
// Clearly handles user input
}

function sendEmailNotification() {
// Clearly sends an email notification
}

// ❌ Bad: Abbreviated words
function calc(num: number): number {
return num * 2;
}

function getUserInf(id: number) {
// ...
}

// ✅ Good: Full words
function calculate(num: number): number {
return num * 2;
}

function getUserInfo(id: number) {
// ...
}

Naming conventions for functions that return a boolean

Name a function that returns a boolean so it reads as a question (a form you can answer with Yes/No).

✅ Good: is + adjective/noun
// ────────────────────────────────────────────
// Naming patterns for functions that return a boolean
// ────────────────────────────────────────────

// ✅ is + adjective/noun
function isValid(value: string): boolean {
return value.length > 0;
}

function isAdult(age: number): boolean {
return age >= 18;
}

function isEmpty(array: any[]): boolean {
return array.length === 0;
}

// ✅ has + noun
function hasPermission(user: User, permission: string): boolean {
return user.permissions.includes(permission);
}

function hasError(result: Result): boolean {
return result.errors.length > 0;
}

// ✅ can + verb
function canEdit(user: User, document: Document): boolean {
return user.id === document.authorId || user.role === 'admin';
}

function canSubmit(form: Form): boolean {
return form.isValid && !form.isSubmitting;
}

// ✅ should + verb
function shouldRetry(attempt: number, maxAttempts: number): boolean {
return attempt < maxAttempts;
}

function shouldShowWarning(value: number, threshold: number): boolean {
return value > threshold;
}

// ✅ exists (existence check)
function exists(path: string): boolean {
return fs.existsSync(path);
}

// ❌ Bad: Starting with a verb while returning a boolean (confused with an action)
function checkValid(value: string): boolean { // "check" looks like an action
return value.length > 0;
}

// ✅ Good
function isValid(value: string): boolean {
return value.length > 0;
}

Exercise 4: Naming functions

// Name the following functions appropriately

// 1. A function that gets all users
async function xxx() {
const response = await fetch('/api/users');
return response.json();
}

// 2. A function that determines whether a number is even
function xxx(num: number): boolean {
return num % 2 === 0;
}

// 3. A function that gets the maximum value of an array
function xxx(numbers: number[]): number {
return Math.max(...numbers);
}

// 4. A function that checks whether a file exists
function xxx(filePath: string): boolean {
return fs.existsSync(filePath);
}

// 5. A function that adds consumption tax to a price
function xxx(price: number, taxRate: number): number {
return price * (1 + taxRate);
}
📝 View answer
✅ Good: Answer
// ✅ Answer

// 1. A function that gets all users
async function getAllUsers(): Promise<User[]> {
const response = await fetch('/api/users');
return response.json();
}
// or
async function fetchAllUsers(): Promise<User[]> {
const response = await fetch('/api/users');
return response.json();
}

// 2. A function that determines whether a number is even
function isEven(num: number): boolean {
return num % 2 === 0;
}

// 3. A function that gets the maximum value of an array
function getMaxValue(numbers: number[]): number {
return Math.max(...numbers);
}
// or
function findMaxValue(numbers: number[]): number {
return Math.max(...numbers);
}

// 4. A function that checks whether a file exists
function fileExists(filePath: string): boolean {
return fs.existsSync(filePath);
}
// or
function hasFile(filePath: string): boolean {
return fs.existsSync(filePath);
}

// 5. A function that adds consumption tax to a price
function calculatePriceWithTax(price: number, taxRate: number): number {
return price * (1 + taxRate);
}
// or
function addTaxToPrice(price: number, taxRate: number): number {
return price * (1 + taxRate);
}

Naming conventions for classes

Name classes with a noun. Choose a name that clearly indicates the thing or concept the class represents.

✅ Good: Expressed with a noun
// ────────────────────────────────────────────
// Class naming patterns
// ────────────────────────────────────────────

// ✅ Good: Expressed with a noun

// Entity (model)
class User {
constructor(
public id: string,
public name: string,
public email: string
) {}
}

class Product {
constructor(
public id: string,
public name: string,
public price: number
) {}
}

// Service (a noun expressing responsibility)
class UserService {
createUser(name: string, email: string): User {
return new User(generateId(), name, email);
}

deleteUser(userId: string): void {
// ...
}
}

class EmailNotificationService {
send(to: string, subject: string, body: string): void {
// ...
}
}

// Utility
class DateFormatter {
format(date: Date, format: string): string {
// ...
}
}

class StringValidator {
isEmail(value: string): boolean {
// ...
}

isUrl(value: string): boolean {
// ...
}
}

// Manager (a class expressing management)
class SessionManager {
private sessions: Map<string, Session> = new Map();

create(userId: string): Session {
// ...
}

destroy(sessionId: string): void {
// ...
}
}

// Controller (server-side frameworks such as Express / NestJS)
class UserController {
getUser(req: Request, res: Response): void {
// ...
}
}

// ❌ Bad: Starting with a verb
class CalculatePrice { // Verb
// ...
}

class GetUser { // Verb
// ...
}

// ✅ Good: Fixed to a noun
class PriceCalculator {
calculate(items: Item[]): number {
// ...
}
}

class UserRepository {
getById(id: string): User | undefined {
// ...
}
}

Suffix patterns for class names

Using common suffixes clarifies a class's role.

// ────────────────────────────────────────────
// Common class suffixes
// ────────────────────────────────────────────

// 🔹 ~Service: provides business logic
class AuthenticationService {
login(email: string, password: string): Promise<User> { }
logout(): void { }
}

// 🔹 ~Repository: the data access layer
class UserRepository {
findById(id: string): Promise<User | null> { }
save(user: User): Promise<void> { }
}

// 🔹 ~Controller: request handling
class UserController {
getUser(req: Request, res: Response): void { }
createUser(req: Request, res: Response): void { }
}

// 🔹 ~Manager: resource management
class ConnectionManager {
open(): Connection { }
close(connection: Connection): void { }
}

// 🔹 ~Factory: object creation
class UserFactory {
create(data: UserData): User {
return new User(data);
}
}

// 🔹 ~Builder: step-by-step construction of complex objects
class QueryBuilder {
private query = '';

select(fields: string[]): this {
this.query += `SELECT ${fields.join(', ')} `;
return this;
}

from(table: string): this {
this.query += `FROM ${table} `;
return this;
}

build(): string {
return this.query;
}
}

// 🔹 ~Validator: validation
class FormValidator {
validate(data: FormData): ValidationResult {
// ...
}
}

// 🔹 ~Helper / ~Util: utility
class DateHelper {
formatDate(date: Date): string { }
parseDate(str: string): Date { }
}

// 🔹 ~Handler: event and error handling
class ErrorHandler {
handle(error: Error): void {
console.error(error);
}
}

Don't make method names redundant

Since a class's methods already have clear context from the class name, you don't need to repeat the class name.

❌ Bad: Repeating the class name
// ❌ Bad: Repeating the class name
class User {
printUserProfile(): void {
console.log(this.name);
}

getUserEmail(): string {
return this.email;
}
}

// ✅ Good: Concise and clear
class User {
printProfile(): void {
console.log(this.name);
}

getEmail(): string {
return this.email;
}
}

// The context is clear at the call site
const user = new User("Taro", "taro@example.com");
user.printProfile(); // ✅ It's obvious this prints the User's profile
user.getEmail(); // ✅ It's obvious this gets the User's email

More examples

❌ Bad
// ❌ Bad
class Product {
getProductName(): string { }
setProductPrice(price: number): void { }
calculateProductDiscount(): number { }
}

// ✅ Good
class Product {
getName(): string { }
setPrice(price: number): void { }
calculateDiscount(): number { }
}

// ❌ Bad
class ShoppingCart {
addItemToShoppingCart(item: Item): void { }
removeItemFromShoppingCart(itemId: string): void { }
getShoppingCartTotal(): number { }
}

// ✅ Good
class ShoppingCart {
addItem(item: Item): void { }
removeItem(itemId: string): void { }
getTotal(): number { }
}