Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

vague-type-name

Level: warn · Article: Method Ownership

When you need a word like “Manager” or “Service” to explain what your code does, you’re admitting you don’t know what your code does.

What it checks

A struct, enum, trait or type alias whose name ends in Service, Manager, Handler, Controller, Repository, Coordinator, Processor, Helper, UseCase, Util or Utils. The suffix must be a whole word: Chandler is fine.

Don’t

#![allow(unused)]
fn main() {
struct UserService {
    db: Database,
}

struct UserRepository {
    db: Database,
}

struct UserManager {
    db: Database, // added six months ago; nobody knows why
}
}

You need to ban a user. Which one owns it? You pick one, ship it, and eight months later there are two ban_users.

Do

#![allow(unused)]
fn main() {
struct User {
    banned: bool,
    id: UserId,
}

struct Store {
    db: Database,
}

impl User {
    fn ban(self) -> Self {
        Self { banned: true, ..self }
    }

    async fn save(&self, store: &Store) -> Result<(), SaveError> {
        store.db.upsert(self).await
    }
}
}

Tell a colleague what you shipped: “the API and the todos”. Those are the structs. TodoController is a name from a tutorial.

Options

[naming]
vague-suffixes = ["Controller", "Coordinator", "Handler", "Helper", "Manager",
                  "Processor", "Repository", "Service", "UseCase", "Util", "Utils"]

Silence it

#![allow(unused)]
fn main() {
// rabot: allow(vague-type-name) implements the DDD Repository contract: the domain never sees SQL
struct OrderRepository { .. }
}

If you are genuinely implementing the pattern, own it. Write down why.