mcpField
C
clean-code

clean-code

github.com/decebals開発761396 回インストール8 週間前に更新
リポジトリ

clean-code について

Clean Code の原則に基づき、コードの可読性と保守性を高めるスキルです。リファクタリングやコードレビュー向けに、命名、関数、重複、コードの不吉な臭いを扱います。

主な機能

  1. 01DRY、KISS、YAGNI 原則の適用
  2. 02明確な命名と役割を絞った関数の指針
  3. 03重複コードとよくあるコードの臭いの特定
  4. 04リファクタリング手法とレビュー用チェックリスト

活用シーン

  1. 01可読性を高めるコードのリファクタリング
  2. 02保守性と複雑さのレビュー
  3. 03命名の改善と重複ロジックの削減

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/decebals/claude-code-java --skill clean-code

インストール後、Claude Code で/clean-codeを入力して読み込まれたか確認します。

同梱ファイルREADME.md

詳細

クリーンコードスキル

クリーンコードの原則に従って、読みやすく保守しやすいコードを書きます。

使用する場面

  • ユーザーが「このコードをきれいにして」「リファクタリングして」「読みやすくして」と依頼したとき
  • 保守性に重点を置いたコードレビュー
  • 複雑さの軽減
  • 命名の改善

基本原則

原則意味違反の兆候
DRY同じことを繰り返さないコードブロックのコピー&ペースト
KISSできるだけシンプルにする過剰に設計されたソリューション
YAGNI必要になるまで作らない「念のため」の機能

DRY - 同じことを繰り返さない

「知識のすべての要素は、システム内で単一かつ曖昧さのない形で表現されなければなりません。」

違反例
// ❌ BAD: Same validation logic repeated
public class UserController {

    public void createUser(UserRequest request) {
        if (request.getEmail() == null || request.getEmail().isBlank()) {
            throw new ValidationException("Email is required");
        }
        if (!request.getEmail().contains("@")) {
            throw new ValidationException("Invalid email format");
        }
        // ... create user
    }

    public void updateUser(UserRequest request) {
        if (request.getEmail() == null || request.getEmail().isBlank()) {
            throw new ValidationException("Email is required");
        }
        if (!request.getEmail().contains("@")) {
            throw new ValidationException("Invalid email format");
        }
        // ... update user
    }
}
リファクタリング後
// ✅ GOOD: Single source of truth
public class EmailValidator {

    public void validate(String email) {
        if (email == null || email.isBlank()) {
            throw new ValidationException("Email is required");
        }
        if (!email.contains("@")) {
            throw new ValidationException("Invalid email format");
        }
    }
}

public class UserController {
    private final EmailValidator emailValidator;

    public void createUser(UserRequest request) {
        emailValidator.validate(request.getEmail());
        // ... create user
    }

    public void updateUser(UserRequest request) {
        emailValidator.validate(request.getEmail());
        // ... update user
    }
}
DRYの例外

重複がすべて悪いわけではありません。時期尚早な抽象化は避けましょう。

// These look similar but serve different purposes - OK to duplicate
public BigDecimal calculateShippingCost(Order order) {
    return order.getWeight().multiply(SHIPPING_RATE);
}

public BigDecimal calculateInsuranceCost(Order order) {
    return order.getValue().multiply(INSURANCE_RATE);
}
// Don't force these into one method - they'll evolve differently

KISS - シンプルに保つ

「通常、最もシンプルなソリューションが最善です。」

違反例
// ❌ BAD: Over-engineered for simple task
public class StringUtils {

    public boolean isEmpty(String str) {
        return Optional.ofNullable(str)
            .map(String::trim)
            .map(String::isEmpty)
            .orElseGet(() -> Boolean.TRUE);
    }
}
リファクタリング後
// ✅ GOOD: Simple and clear
public class StringUtils {

    public boolean isEmpty(String str) {
        return str == null || str.trim().isEmpty();
    }

    // Or use existing library
    // return StringUtils.isBlank(str);  // Apache Commons
    // return str == null || str.isBlank();  // Java 11+
}
KISSチェックリスト
  • ジュニア開発者がこれを30秒で理解できますか?
  • 標準ライブラリを使う、よりシンプルな方法はありますか?
  • 発生しないかもしれないエッジケースのために複雑さを加えていませんか?

YAGNI - 必要になるまで作らない

「必要になるまで機能を追加しないでください。」

違反例
// ❌ BAD: Building for hypothetical future
public interface Repository<T, ID> {
    T findById(ID id);
    List<T> findAll();
    List<T> findAll(Pageable pageable);
    List<T> findAll(Sort sort);
    List<T> findAllById(Iterable<ID> ids);
    T save(T entity);
    List<T> saveAll(Iterable<T> entities);
    void delete(T entity);
    void deleteById(ID id);
    void deleteAll(Iterable<T> entities);
    void deleteAll();
    boolean existsById(ID id);
    long count();
    // ... 20 more methods "just in case"
}

// Current usage: only findById and save
リファクタリング後
// ✅ GOOD: Only what's needed now
public interface UserRepository {
    Optional<User> findById(Long id);
    User save(User user);
}

// Add methods when actually needed, not before
YAGNIの兆候
  • 「後で必要になるかもしれません」
  • 「念のため設定可能にしておきましょう」
  • 「将来Xをサポートする必要が出たらどうしますか?」
  • 実装が1つしかない抽象クラス

命名規則

変数
// ❌ BAD
int d;                  // What is d?
String s;               // Meaningless
List<User> list;        // What kind of list?
Map<String, Object> m;  // What does it map?

// ✅ GOOD
int elapsedTimeInDays;
String customerName;
List<User> activeUsers;
Map<String, Object> sessionAttributes;
ブール値
// ❌ BAD
boolean flag;
boolean status;
boolean check;

// ✅ GOOD - Use is/has/can/should prefix
boolean isActive;
boolean hasPermission;
boolean canEdit;
boolean shouldNotify;
メソッド
// ❌ BAD
void process();           // Process what?
void handle();            // Handle what?
void doIt();              // Do what?
User get();               // Get from where?

// ✅ GOOD - Verb + noun, descriptive
void processPayment();
void handleLoginRequest();
void sendWelcomeEmail();
User findByEmail(String email);
List<Order> fetchPendingOrders();
クラス
// ❌ BAD
class Data { }           // Too vague
class Info { }           // Too vague
class Manager { }        // Often a god class
class Helper { }         // Often a dumping ground
class Utils { }          // Static method dumping ground

// ✅ GOOD - Noun, specific responsibility
class User { }
class OrderProcessor { }
class EmailValidator { }
class PaymentGateway { }
class ShippingCalculator { }
命名規則の表
要素規則例
クラスパスカルケース、名詞OrderService
インターフェースパスカルケース、形容詞または名詞Comparable、List
メソッドキャメルケース、動詞calculateTotal()
変数キャメルケース、名詞customerEmail
定数大文字のスネークケースMAX_RETRY_COUNT
パッケージ小文字com.example.orders

関数/メソッド

関数を小さく保つ
// ❌ BAD: 50+ line method doing multiple things
public void processOrder(Order order) {
    // validate order (10 lines)
    // calculate totals (15 lines)
    // apply discounts (10 lines)
    // update inventory (10 lines)
    // send notifications (10 lines)
    // ... and more
}

// ✅ GOOD: Small, focused methods
public void processOrder(Order order) {
    validateOrder(order);
    calculateTotals(order);
    applyDiscounts(order);
    updateInventory(order);
    sendNotifications(order);
}
抽象度をそろえる
// ❌ BAD: Mixed abstraction levels
public void processOrder(Order order) {
    validateOrder(order);  // High level

    // Low level mixed in
    BigDecimal total = BigDecimal.ZERO;
    for (OrderItem item : order.getItems()) {
        total = total.add(item.getPrice().multiply(
            BigDecimal.valueOf(item.getQuantity())));
    }

    sendEmail(order);  // High level again
}

// ✅ GOOD: Consistent abstraction level
public void processOrder(Order order) {
    validateOrder(order);
    calculateTotal(order);
    sendConfirmation(order);
}

private BigDecimal calculateTotal(Order order) {
    return order.getItems().stream()
        .map(item -> item.getPrice().multiply(
            BigDecimal.valueOf(item.getQuantity())))
        .reduce(BigDecimal.ZERO, BigDecimal::add);
}
パラメーターを制限する
// ❌ BAD: Too many parameters
public User createUser(String firstName, String lastName,
                       String email, String phone,
                       String address, String city,
                       String country, String zipCode) {
    // ...
}

// ✅ GOOD: Use parameter object
public User createUser(CreateUserRequest request) {
    // ...
}

// Or builder
public User createUser(UserBuilder builder) {
    // ...
}
フラグ引数を避ける
// ❌ BAD: Boolean flag changes behavior
public void sendMessage(String message, boolean isUrgent) {
    if (isUrgent) {
        // send immediately
    } else {
        // queue for later
    }
}

// ✅ GOOD: Separate methods
public void sendUrgentMessage(String message) {
    // send immediately
}

public void queueMessage(String message) {
    // queue for later
}

コメント

明白なコメントを避ける
// ❌ BAD: Noise comments
// Set the user's name
user.setName(name);

// Increment counter
counter++;

// Check if user is null
if (user != null) {
    // ...
}
良いコメント
// ✅ GOOD: Explain WHY, not WHAT

// Retry with exponential backoff to avoid overwhelming the server
// during high load periods (see incident #1234)
for (int attempt = 0; attempt < MAX_RETRIES; attempt++) {
    Thread.sleep((long) Math.pow(2, attempt) * 1000);
    // ...
}

// TODO: Replace with Redis cache after infrastructure upgrade (Q2 2026)
private Map<String, User> userCache = new ConcurrentHashMap<>();

// WARNING: Order matters! Discounts must be applied before tax calculation
applyDiscounts(order);
calculateTax(order);
コードに語らせる
// ❌ BAD: Comment explaining bad code
// Check if the user is an admin or has special permission
// and the action is allowed for their role
if ((user.getRole() == 1 || user.getRole() == 2) &&
    (action == 3 || action == 4 || action == 7)) {
    // ...
}

// ✅ GOOD: Self-documenting code
if (user.hasAdminPrivileges() && action.isAllowedFor(user.getRole())) {
    // ...
}

よくあるコードの不吉な臭い

臭い説明リファクタリング
長いメソッドメソッドが20行を超えるメソッドの抽出
長い引数リスト引数が3つを超えるパラメーターオブジェクト
重複コード複数箇所に同じコードがあるメソッド/クラスの抽出
デッドコード使用されていないコード削除する
マジックナンバー説明のないリテラル名前付き定数
ゴッドクラスクラスが多くの処理を担っているクラスの抽出
フィーチャーエンヴィメソッドが別のクラスのデータを使用しているメソッドの移動
プリミティブ執着オブジェクトの代わりにプリミティブを使っている値オブジェクト
マジックナンバー
// ❌ BAD
if (user.getAge() >= 18) { }
if (order.getTotal() > 100) { }
Thread.sleep(86400000);

// ✅ GOOD
private static final int ADULT_AGE = 18;
private static final BigDecimal FREE_SHIPPING_THRESHOLD = new BigDecimal("100");
private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1);

if (user.getAge() >= ADULT_AGE) { }
if (order.getTotal().compareTo(FREE_SHIPPING_THRESHOLD) > 0) { }
Thread.sleep(ONE_DAY_MS);
プリミティブ執着
// ❌ BAD: Primitives everywhere
public void createUser(String email, String phone, String zipCode) {
    // No validation, easy to mix up parameters
}

createUser("12345", "[email protected]", "555-1234");  // Wrong order, compiles!

// ✅ GOOD: Value objects
public record Email(String value) {
    public Email {
        if (!value.contains("@")) {
            throw new IllegalArgumentException("Invalid email");
        }
    }
}

public record PhoneNumber(String value) {
    // validation
}

public void createUser(Email email, PhoneNumber phone, ZipCode zipCode) {
    // Type-safe, self-validating
}

リファクタリングのクイックリファレンス

変更前変更後手法
長いメソッド短いメソッドメソッドの抽出
重複コード単一のメソッドメソッドの抽出
複雑な条件分岐ポリモーフィズム条件分岐をポリモーフィズムに置き換える
多すぎるパラメーターオブジェクトパラメーターオブジェクトの導入
一時変数クエリメソッド一時変数をクエリに置き換える
コードを説明するコメント自己文書化コード名前変更、抽出
ネストされた条件分岐早期リターンガード節
ガード節
// ❌ BAD: Deeply nested
public void processOrder(Order order) {
    if (order != null) {
        if (order.isValid()) {
            if (order.hasItems()) {
                // actual logic buried here
            }
        }
    }
}

// ✅ GOOD: Guard clauses
public void processOrder(Order order) {
    if (order == null) return;
    if (!order.isValid()) return;
    if (!order.hasItems()) return;

    // actual logic at top level
}

クリーンコードチェックリスト

コードをレビューする際に確認します。

  • 名前は意味が明確で、発音しやすいですか?
  • 関数は小さく、目的が絞られていますか?
  • 重複したコードはありませんか?
  • マジックナンバーやマジック文字列はありませんか?
  • コメントは「何を」ではなく「なぜ」を説明していますか?
  • コードの抽象度は一貫していますか?
  • 簡潔にできるコードはありませんか?
  • デッドコードや未使用コードはありませんか?

関連スキル

  • solid-principles - クラス構造の設計原則
  • design-patterns - 繰り返し発生する問題に対する一般的な解決策
  • java-code-review - 包括的なレビュー用チェックリスト

コメント