命名規則 ② 関数とクラス
本記事は命名規則 3 部構成の第 2 部です。第 1 部: ケース規約と変数・定数で扱った基本を踏まえて、関数・クラス・メソッドの命名規則を扱います。
関数の命名規則
関数名は「何をするのか」を明確に表す動詞で始めます。
基本パターン
関数名のパターン
| パターン | 例 |
|---|---|
| get + 名詞 | getUserById, getCurrentTime |
| set + 名詞 | setUserName, setTheme |
| calculate + 名詞 | calculateTotal, calculateAge |
| fetch + 名詞 | fetchUserData, fetchPosts |
| create + 名詞 | createUser, createElement |
| update + 名詞 | updateProfile, updateSettings |
| delete + 名詞 | deleteUser, removeItem |
| validate + 名詞 | validateEmail, validateInput |
| convert + A + to + B | convertMinsToHours |
具体例
✅ Good: 動作が明確な関数名
// ✅ Good: 動作が明確な関数名
// get系: データの取得(副作用なし)
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系: 値の設定(副作用あり)
function setTheme(theme: 'light' | 'dark'): void {
document.body.className = theme;
}
// calculate系: 計算処理
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(); // 簡略版: 誕生日前は 1 歳多くなる
}
// fetch系: 非同期データ取得
async function fetchUserData(userId: string): Promise<User> {
const response = await fetch(`/api/users/${userId}`);
return response.json();
}
// create系: 新規作成
function createUser(name: string, email: string): User {
return {
id: generateId(),
name,
email,
createdAt: new Date(),
};
}
// update系: 更新
function updateUserProfile(userId: string, updates: Partial<User>): void {
const user = getUserById(userId);
if (user) {
Object.assign(user, updates);
}
}
// delete/remove系: 削除
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系: 検証
function validateEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
// convert系: 変換
function convertMinsToHours(minutes: number): number {
return minutes / 60;
}
function convertCelsiusToFahrenheit(celsius: number): number {
return (celsius * 9/5) + 32;
}
❌ 避けるべきパターン
❌ Bad: 避けるべきパターン
// ❌ Bad: 抽象的すぎる
function process(data: any) {
// 何を処理するのか不明
}
function handle(value: string) {
// 何を扱うのか不明
}
function doSomething() {
// 何をするのか不明
}
// ✅ Good: 具体的
function processPayment(payment: Payment) {
// 支払い処理をすることが明確
}
function handleUserInput(input: string) {
// ユーザー入力を扱うことが明確
}
function sendEmailNotification() {
// メール通知を送信することが明確
}
// ❌ Bad: 単語の省略
function calc(num: number): number {
return num * 2;
}
function getUserInf(id: number) {
// ...
}
// ✅ Good: 完全な単語
function calculate(num: number): number {
return num * 2;
}
function getUserInfo(id: number) {
// ...
}
真偽値を返す関数の命名規則
真偽値を返す関数は、疑問文(Yes/Noで答えられる形)になるように命名します。
✅ Good: is + 形容詞/名詞
// ────────────────────────────────────────────
// 真偽値を返す関数の命名パターン
// ────────────────────────────────────────────
// ✅ is + 形容詞/名詞
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 + 名詞
function hasPermission(user: User, permission: string): boolean {
return user.permissions.includes(permission);
}
function hasError(result: Result): boolean {
return result.errors.length > 0;
}
// ✅ can + 動詞
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 + 動詞
function shouldRetry(attempt: number, maxAttempts: number): boolean {
return attempt < maxAttempts;
}
function shouldShowWarning(value: number, threshold: number): boolean {
return value > threshold;
}
// ✅ exists(存在チェック)
function exists(path: string): boolean {
return fs.existsSync(path);
}
// ❌ Bad: 動詞始まりで真偽値を返す(アクションと混同)
function checkValid(value: string): boolean { // check は動作に見える
return value.length > 0;
}
// ✅ Good
function isValid(value: string): boolean {
return value.length > 0;
}
練習問題 4: 関数の命名
// 以下の関数を適切に命名してください
// 1. ユーザー全員を取得する関数
async function xxx() {
const response = await fetch('/api/users');
return response.json();
}
// 2. 偶数かどうかを判定する関数
function xxx(num: number): boolean {
return num % 2 === 0;
}
// 3. 配列の最大値を取得する関数
function xxx(numbers: number[]): number {
return Math.max(...numbers);
}
// 4. ファイルが存在するか確認する関数
function xxx(filePath: string): boolean {
return fs.existsSync(filePath);
}
// 5. 価格に消費税を加算する関数
function xxx(price: number, taxRate: number): number {
return price * (1 + taxRate);
}
📝 解答を見る
✅ Good: 解答
// ✅ 解答
// 1. ユーザー全員を取得する関数
async function getAllUsers(): Promise<User[]> {
const response = await fetch('/api/users');
return response.json();
}
// または
async function fetchAllUsers(): Promise<User[]> {
const response = await fetch('/api/users');
return response.json();
}
// 2. 偶数かどうかを判定する関数
function isEven(num: number): boolean {
return num % 2 === 0;
}
// 3. 配列の最大値を取得する関数
function getMaxValue(numbers: number[]): number {
return Math.max(...numbers);
}
// または
function findMaxValue(numbers: number[]): number {
return Math.max(...numbers);
}
// 4. ファイルが存在するか確認する関数
function fileExists(filePath: string): boolean {
return fs.existsSync(filePath);
}
// または
function hasFile(filePath: string): boolean {
return fs.existsSync(filePath);
}
// 5. 価格に消費税を加算する関数
function calculatePriceWithTax(price: number, taxRate: number): number {
return price * (1 + taxRate);
}
// または
function addTaxToPrice(price: number, taxRate: number): number {
return price * (1 + taxRate);
}
クラスの命名規則
クラスは名詞で命名します。そのクラスが表すもの・概念を明確に示す名前を選びます。
✅ Good: 名詞で表現
// ────────────────────────────────────────────
// クラスの命名パターン
// ────────────────────────────────────────────
// ✅ Good: 名詞で表現
// エンティティ(モデル)
class User {
constructor(
public id: string,
public name: string,
public email: string
) {}
}
class Product {
constructor(
public id: string,
public name: string,
public price: number
) {}
}
// サービス(責務を表す名詞)
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 {
// ...
}
}
// ユーティリティ
class DateFormatter {
format(date: Date, format: string): string {
// ...
}
}
class StringValidator {
isEmail(value: string): boolean {
// ...
}
isUrl(value: string): boolean {
// ...
}
}
// マネージャー(管理を表すクラス)
class SessionManager {
private sessions: Map<string, Session> = new Map();
create(userId: string): Session {
// ...
}
destroy(sessionId: string): void {
// ...
}
}
// コントローラー(Express / NestJS などのサーバーサイドフレームワーク)
class UserController {
getUser(req: Request, res: Response): void {
// ...
}
}
// ❌ Bad: 動詞で始まる
class CalculatePrice { // 動詞
// ...
}
class GetUser { // 動詞
// ...
}
// ✅ Good: 名詞に修正
class PriceCalculator {
calculate(items: Item[]): number {
// ...
}
}
class UserRepository {
getById(id: string): User | undefined {
// ...
}
}
クラス名のサフィックスパターン
一般的なサフィックス(接尾辞)を使うことで、クラスの役割を明確にできます。
// ────────────────────────────────────────────
// 一般的なクラスのサフィックス
// ────────────────────────────────────────────
// 🔹 ~Service: ビジネスロジックを提供
class AuthenticationService {
login(email: string, password: string): Promise<User> { }
logout(): void { }
}
// 🔹 ~Repository: データアクセス層
class UserRepository {
findById(id: string): Promise<User | null> { }
save(user: User): Promise<void> { }
}
// 🔹 ~Controller: リクエスト処理
class UserController {
getUser(req: Request, res: Response): void { }
createUser(req: Request, res: Response): void { }
}
// 🔹 ~Manager: リソース管理
class ConnectionManager {
open(): Connection { }
close(connection: Connection): void { }
}
// 🔹 ~Factory: オブジェクト生成
class UserFactory {
create(data: UserData): User {
return new User(data);
}
}
// 🔹 ~Builder: 複雑なオブジェクトの段階的構築
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: 検証
class FormValidator {
validate(data: FormData): ValidationResult {
// ...
}
}
// 🔹 ~Helper / ~Util: ユーティリティ
class DateHelper {
formatDate(date: Date): string { }
parseDate(str: string): Date { }
}
// 🔹 ~Handler: イベント・エラー処理
class ErrorHandler {
handle(error: Error): void {
console.error(error);
}
}
メソッド名は冗長にしない
クラスのメソッドは、すでにクラス名で文脈が明確なので、クラス名を繰り返す必要はありません。
❌ Bad: クラス名を繰り返している
// ❌ Bad: クラス名を繰り返している
class User {
printUserProfile(): void {
console.log(this.name);
}
getUserEmail(): string {
return this.email;
}
}
// ✅ Good: 簡潔で明確
class User {
printProfile(): void {
console.log(this.name);
}
getEmail(): string {
return this.email;
}
}
// 使用時には文脈が明確
const user = new User("Taro", "taro@example.com");
user.printProfile(); // ✅ Userのprofileを表示することは自明
user.getEmail(); // ✅ Userのemailを取得することは自明
より多くの例
❌ 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 { }
}
次に読む
- 命名規則 ③ 命名の質を高める — 発音可能な名前・対比語・省略の基準など、命名の質を高める原則に進む