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
| Pattern | Example |
|---|---|
| get + noun | getUserById, getCurrentTime |
| set + noun | setUserName, setTheme |
| calculate + noun | calculateTotal, calculateAge |
| fetch + noun | fetchUserData, fetchPosts |
| create + noun | createUser, createElement |
| update + noun | updateProfile, updateSettings |
| delete + noun | deleteUser, removeItem |
| validate + noun | validateEmail, validateInput |
| convert + A + to + B | convertMinsToHours |
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 { }
}
What to read next
- Naming conventions 3: Improving naming quality — move on to principles that improve naming quality, such as pronounceable names, contrasting words, and abbreviation criteria