# Role








## Declaring a Role

An app that follows an architecture definition has files with specific roles (Roles).
For example `UseCase`, `Repository`, `Controller`, or `ViewModel`.

You define what Roles exist inside `architecture { }`.

```kt
architecture {
    // Define a Role called UseCase
    "UseCase" {
        // Write the description, placement, and constraints inside here
    }
}
```

You write a Role's description, placement, and constraints inside that Role's block.

- `title`, `summary`, `description`, etc. ... The description of the Role. Used when generating documentation.
- `layout { }` ... Defines where the files for that Role may be placed.
  - See [Layout definitions](/katachi/guides/layout/) for details.
- `"constraint name".konsist { }` ... Defines constraints you can apply to that Role's files.
  - Constraints are defined using Konsist. See [Konsist integration](/katachi/guides/konsist-integration/) for details.
- `.template { }` ... Attached to a file declared in `layout { }`, it defines the template used when that file is newly created.
  - See [Generate code from a template](/katachi/guides/generate-code-from-template/) for details.

```kt
architecture {
    "UseCase" {
        title = "Use case"
        summary = "A single app-specific behavior that occurs on each screen"

        example("GetUserUseCase", "Fetch the user")

        // Where it may be placed
        layout {
            "src/main/kotlin/com/example/useCase" / "*UseCase".ktFile()
        }

        // What its contents should look like
        "has exactly one invoke function".konsist {
            classes().must { it.functions().map { f -> f.name } == listOf("invoke") }
        }
    }
}
```

Let's look at each of these in a bit more detail.

<details>
<summary>Writing a description</summary>

At minimum, all you need is `summary`. It becomes the one-line entry for the Role in the generated documentation's list table.

```kt
"UseCase" {
    summary = "A single app-specific behavior that occurs on each screen"
}
```

`description` can hold a longer explanation, and `example()` a representative example. Calls to `example()` are kept in the order you call them.

```kt
"UseCase" {
    title = "Use case"
    summary = "A single app-specific behavior that occurs on each screen"
    description = """
        Call only UseCase from the UI; never touch Repository directly.

        ### Things not to do
        - Depend on Android types
    """.trimIndent()

    example("GetUserUseCase", "Fetch the user")
    example("UpdateUserUseCase", "Update the user")
}
```

</details>

<details>
<summary>Declaring where files go</summary>

This is the case where a Role has just one place to live.

```kt
"UseCase" {
    layout {
        "src/main/kotlin/com/example/useCase" / "*UseCase".ktFile()
    }
}
```

**You can write multiple `layout { }` blocks.** This declares that the same kind of file is allowed to appear in more than one place. Files of different kinds go in separate Roles.

```kt
"Screen" {
    // In the feature-home module
    layout {
        "feature-home/src/main/kotlin/screen" / "*Screen".ktFile()
    }

    // And in the feature-settings module
    layout {
        "feature-settings/src/main/kotlin/screen" / "*Screen".ktFile()
    }
}
```

**Placing a file anywhere you haven't declared is a violation.**

```text
src/main/kotlin/com/example/GetUserUseCase.kt   ← placed outside useCase/
```

When you run the test, katachi reports the nearby valid location and how to fix it together in a single block.

```text
Katachi check failed: 1 violation (Unexpected: 1)

[UnexpectedFile] file:///path/to/project/src/main/kotlin/com/example/GetUserUseCase.kt
  No role is defined for this file.

  Nearby locations:
    UseCase file:///path/to/project/src/main/kotlin/com/example/useCase/

  How to fix:
    - Move it to one of the locations above
    - Delete it if it is not needed
    - Add a new role for it:
        "GetUserUseCase" {
          summary = "TODO"
          layout {
            "src/main/kotlin/com/example" / "GetUserUseCase".ktFile()
          }
        }
```

</details>

<details>
<summary>Constraining the contents</summary>

You give each constraint a name. **That name appears directly in the violation report.**

```kt
"UseCase" {
    layout {
        "src/main/kotlin/com/example/useCase" / "*UseCase".ktFile()
    }

    "has exactly one invoke function".konsist {
        classes().must { it.functions().map { f -> f.name } == listOf("invoke") }
    }
}
```

A constraint applies to the files that matched the Role's `layout { }`. You cannot write a constraint on a Role that has no `layout { }`.

You can also express a prohibition with `mustNot` and `mustBeEmpty()`.

```kt
"RepositoryInterface" {
    layout {
        "src/main/kotlin/com/example/repository" / "*Repository".ktFile()
    }

    // Write the required condition as a negation
    "must not be internal".konsist {
        classes().mustNot { it.hasInternalModifier }
    }

    // Require that none match
    "must not place Impl in the same location".konsist {
        classes().filter { it.hasNameEndingWith("Impl") }.mustBeEmpty()
    }
}
```

**A class that doesn't satisfy the constraint is a violation.**

```kt
// Placed inside useCase/, but has a function other than invoke
class GetUserUseCase(private val repository: UserRepository) {
    suspend fun invoke(id: String) = repository.find(id)
    fun clearCache() = repository.clear()   // ← this one
}
```

When the test calls `assert(FileConstraintCheck())`, it shows up in the same report as placement violations. **It even tells you which file and which line.**

```text
[UnsatisfiedFileConstraint] file:///path/to/project/src/main/kotlin/com/example/useCase/GetUserUseCase.kt
  Role: UseCase / FileConstraint: "has exactly one invoke function"
  Declaration: GetUserUseCase (line 3)
  Declared at: ProjectArchitecture.kt:12
```

</details>


Also, because Role names are used for things like documentation generation, they must be ASCII only (starting with a letter, followed by letters, digits, `_`, or `-`). Put a Japanese (or any other) display name in `title`.

## Grouping Roles

You can group Roles together using `"group name".group { ... }`.

```kt {2}
architecture {
    "domain".group {
        "UseCase" {
            // ...
        }

        "RepositoryInterface" {
            // ...
        }
    }
}
```

## Best practices for designing Roles

### A good Role definition needs no changes

**If you have to rewrite `architecture { }` every time you add a feature to the app, that `architecture { }` definition is poorly designed.**

Make good use of wildcards like `*` and `**` so that `architecture { }` doesn't end up as a duplicate of your directory structure, requiring double the work to maintain.

### Put only one kind of file in a Role

**Make each Role stand for exactly one kind of file.**
For example, a Repository interface and its implementation have similar names but are different kinds of file. If you put both in one Role, its description, constraints, and templates split by "which of the two files this is about", and your `konsist { }` constraints end up with branches like "if it is the interface…, if it is the implementation…".
With one Role per kind, the description and constraints only deal with that kind of file, and the generated documentation gets one page per kind.

<CodeComparison>
    <CodeComparison.Panel label="🆖 Two kinds of file in one Role" labelVariant="danger">

    ```kt {4-5,7-8} nocollapse
    "Repository" {
        summary = "Loads and saves data"
        layout {
            "repository" / "*Repository".ktFile()      // interface
            "repository" / "*RepositoryImpl".ktFile()  // implementation
        }
        "Declarations only for the interface, and for the implementation…".konsist {
            // the constraint has to branch on which file it is
        }
    }
    ```

    </CodeComparison.Panel>

    <CodeComparison.Panel label="🆗 One Role per kind" labelVariant="success">

    ```kt {1,3,9,11} nocollapse
    "RepositoryInterface" {
        summary = "The entry point for loading and saving data"
        layout { "repository" / "*Repository".ktFile() }
        "Put only interfaces here".konsist {
            classes().mustBeEmpty()
        }
    }

    "RepositoryImplementation" {
        summary = "The implementation of RepositoryInterface"
        layout { "repository" / "*RepositoryImpl".ktFile() }
    }
    ```

    </CodeComparison.Panel>
</CodeComparison>

## Splitting Role definitions

The bigger the project, the more the `architecture { }` definition tends to bloat.

Because `architecture { }` is a Kotlin DSL, you can factor it out into extension functions just like ordinary Kotlin code.

Here's the recommended **way to split Role definitions**.

### Splitting the `architecture { }` definition

What tends to bloat is **the detail inside each Role**.
Factor each Role out into its own extension function.

<CodeComparison>
    <CodeComparison.Panel label="Before">

    ```kt title=ProjectArchitecture.kt nocollapse
    architecture {
        "UseCase" {
            layout { 
                "src/main/kotlin/com/example/project/useCase" / "*UseCase".ktFile()
            }
            "has exactly one invoke function".konsist {
                classes().must { it.functions().map { f -> f.name } == listOf("invoke") }
            }
            // ...
        }

        "RepositoryInterface" {
            layout { 
                "src/main/kotlin/com/example/project/repository" / "*Repository".ktFile()
            }
            "must not hold a class".konsist {
                classes().mustBeEmpty()
            }
            // ...
        }

        // ...
    }
    ```

    </CodeComparison.Panel>

    <CodeComparison.Panel label="After" labelVariant="success">

    <FileTree>
        - ProjectArchitecture.kt
        - **domain/**
            - UseCaseRole.kt
            - RepositoryInterfaceRole.kt
    </FileTree>

    ```kt title=ProjectArchitecture.kt
    architecture {
        useCase()
        repositoryInterface()

        // ...
    }
    ```

    ```kt title=domain/UseCaseRole.kt
    // hint: DeclarationContainerScope is the receiver of architecture { } and "...".group { }.
    fun DeclarationContainerScope.useCase() = "UseCase" {
        layout {
            "src/main/kotlin/com/example/project/useCase" / "*UseCase".ktFile()
        }
        "has exactly one invoke function".konsist {
            classes().must { it.functions().map { f -> f.name } == listOf("invoke") }
        }
        // ...
    }
    ```

    ```kt title=domain/RepositoryInterfaceRole.kt
    fun DeclarationContainerScope.repositoryInterface() = "RepositoryInterface" {
        layout {
            "src/main/kotlin/com/example/project/repository" / "*Repository".ktFile()
        }
        "must not hold a class".konsist {
            classes().mustBeEmpty()
        }
        // ...
    }
    ```

    </CodeComparison.Panel>

</CodeComparison>

### Splitting the inside of a Role definition

Within a Role definition, `"...".konsist { }` in particular tends to bloat as the number of constraints grows or they get more complex.

Don't hesitate to factor `"...".konsist { }` out into private extension functions.

<CodeComparison>
    <CodeComparison.Panel label="Before">
      ```kt
        fun DeclarationContainerScope.useCase() = "UseCase" {
            layout {
                "src/main/kotlin/com/example/project/useCase" / "*UseCase".ktFile()
            }
            "has exactly one invoke function".konsist {
                classes().must { it.functions().map { f -> f.name } == listOf("invoke") }
            }
            // ...
        }
      ```
    </CodeComparison.Panel>

    <CodeComparison.Panel label="After" labelVariant="success">
      ```kt
        fun DeclarationContainerScope.useCase() = "UseCase" {
            layout {
                "src/main/kotlin/com/example/project/useCase" / "*UseCase".ktFile()
            }

            onlyInvokeFun()
            // ...
        }

        private fun RoleScope.onlyInvokeFun() = 
            "has exactly one invoke function".konsist {
                classes().must { it.functions().map { f -> f.name } == listOf("invoke") }
            }
      ```
    </CodeComparison.Panel>
</CodeComparison>

## Summary

- A Role is **a kind of file that's allowed to appear in the project**. It's independent of packages and modules.
- A single Role **brings together** its description (`title` / `summary`), placement (`layout { }`), and constraints (`konsist { }`).
- **Role definitions bloat easily.** To keep `architecture { }` and Role definitions from bloating, make good use of extension functions to split them appropriately.

```kt
architecture {
    "domain".group {
        "UseCase" {
            summary = "A single app-specific behavior that occurs on each screen"

            // However many places it is put in, the description stays in this one place
            layout {
                "core/domain/src/main/kotlin/useCase" / "*UseCase".ktFile()
            }

            "has exactly one invoke function".konsist {
                classes().must { it.functions().map { f -> f.name } == listOf("invoke") }
            }
        }
    }
}
```

## Next steps

- [Layout](/katachi/guides/layout/) ... Learn how to declare where a Role's files may be placed.
- [Konsist integration](/katachi/guides/konsist-integration/) ... Learn how to constrain the contents of a Role's files.
- [Your first architecture definition](/katachi/get-started/first-architecture/) ... Introduce katachi into your project and actually write a Role.