# Hide Method

> Reduce a method's visibility to private or protected when nothing outside the class needs it, shrinking the public surface.

- kind: technique
- category: simplifying-method-calls
- canonical: https://aipatterns.dev/refactoring/techniques/hide-method
- inspired-by: https://refactoring.guru/hide-method

## Problem

A method is public, but only the class itself (or its subclasses) calls it. Other code may start depending on it, which ties the class's internals to outside callers and makes later changes risky.

## Solution

**Make the method `private`, or `protected` if subclasses need it.** Use the narrowest visibility the language offers that still compiles.

## Before

```ts
export class PasswordResetService {
  constructor(private tokens: TokenStore, private mail: Mailer) {}

  async requestReset(email: string): Promise<void> {
    const token = this.generateToken();
    await this.tokens.save(email, this.hashToken(token), Date.now() + 15 * 60_000);
    await this.mail.send(email, "reset", { link: `https://app.example/reset?t=${token}` });
  }

  generateToken(): string {
    return crypto.randomBytes(32).toString("base64url");
  }

  hashToken(token: string): string {
    return crypto.createHash("sha256").update(token).digest("hex");
  }
}
```

## After

```ts
export class PasswordResetService {
  constructor(private tokens: TokenStore, private mail: Mailer) {}

  async requestReset(email: string): Promise<void> {
    const token = this.generateToken();
    await this.tokens.save(email, this.hashToken(token), Date.now() + 15 * 60_000);
    await this.mail.send(email, "reset", { link: `https://app.example/reset?t=${token}` });
  }

  private generateToken(): string {
    return crypto.randomBytes(32).toString("base64url");
  }

  private hashToken(token: string): string {
    return crypto.createHash("sha256").update(token).digest("hex");
  }
}
```

## Why

- A smaller public interface is easier to learn and harder to misuse.
- You can change or delete private methods without checking other modules.
- For security-related helpers, hiding prevents callers from building tokens outside the reset flow.

## Steps

1. Search for every call to the method outside its class, including tests, other packages and string-based calls.
2. If there are none, change the visibility to `private`. Run the compiler and tests.
3. If only subclasses call it, use `protected`.
4. If tests call it directly, test through the public method instead, or move the logic into its own small class that is public and tested.
5. Repeat periodically. Methods often become hideable after other refactorings remove their external callers.

## Watch out

- TypeScript `private` is compile-time only; JavaScript callers and `as any` still reach it. Use `#private` fields when runtime privacy matters.
- Do not hide methods that are part of a published library API without a deprecation cycle.
- Do not hide a method just to stop a test from calling it, if that leaves important logic untested. Extract it to a separate unit instead.
- Interface implementations and framework hooks (lifecycle methods, decorators) must stay public.
- The inverse is making the method public, which has no named technique; do it only for a real external caller.

## Related

- Treats [Data Class](https://aipatterns.dev/refactoring/smells/data-class.md) and [Inappropriate Intimacy](https://aipatterns.dev/refactoring/smells/inappropriate-intimacy.md) by narrowing what outsiders can touch.
- Pairs with [Remove Setting Method](https://aipatterns.dev/refactoring/techniques/remove-setting-method.md) and [Encapsulate Field](https://aipatterns.dev/refactoring/techniques/encapsulate-field.md).

## Agent checklist

- [ ] No caller outside the class (or its subclasses) exists, including in other packages and string lookups.
- [ ] The method is not part of an interface, framework hook or published API.
- [ ] Tests exercise the logic through public behavior.
- [ ] Runtime privacy (`#`) was used where it matters for security.
