Naming¶
Names are the primary documentation. These rules exist because the legacy codebase lost
whole features to casing mistakes (D-03,
D-04) and because _Misc, cider, rg_base and
Exausted are all real identifiers a maintainer had to decode.
1. Casing¶
| Element | Convention | Example |
|---|---|---|
| Namespace, type, method, property, event, constant | PascalCase |
InventoryService |
| Interface | PascalCase, I prefix |
IPersistenceBackend |
| Parameter, local | camelCase |
itemDefinition |
| Private field | _camelCase |
_registry |
| Static readonly / const | PascalCase |
MaximumDoors |
| Type parameter | T prefix |
TDefinition |
| Async method | suffix Async |
LoadCharacterAsync |
2. No abbreviations¶
Write the word.
| ✗ | ✓ |
|---|---|
inv |
inventory |
cfg, conf |
configuration |
plr, ply |
player |
ent |
entity |
amt |
amount |
msg |
message |
tmp |
(name what it holds) |
mgr |
(see §4) |
svc |
service |
idx |
index |
btn |
button |
Permitted, because they are more readable than the expansion and are universally
understood in this domain: Id, Ui, Rpc, Hp, Json, Http, Db, Npc, Ai, Fov.
Loop counters i, j, k and lambda parameter x are permitted in bodies of five lines or
fewer. Beyond that, name them.
3. Say what it is¶
A name describes the concept, not the container.
| ✗ | ✓ | Why |
|---|---|---|
ItemDictionary |
ItemRegistry |
The container type can change |
PlayerList |
Roster |
Same |
DoorArray |
Doors |
Plurals are enough |
DataManager |
CharacterStore |
See §4 |
StringHelper |
(delete it) | See §4 |
4. Banned suffixes¶
Manager, Helper, Util, Utils, Utility, Handler, Processor, Data, Info,
Base.
These are what you write when the class has no single responsibility. If you cannot name the type without one, the type is doing more than one thing — split it, and the names will appear.
Legitimate replacements: Registry, Store, Service, Factory, Provider, Policy,
Resolver, Validator, Calculator, Serializer.
Base is permitted only on an abstract type genuinely designed for inheritance, and
inheritance is limited to two levels (00_CODING_STANDARDS.md).
5. Booleans read as assertions¶
IsLocked, HasAccess, CanAfford, WasArrested, ShouldPersist.
Never negative: IsNotReady forces the reader to invert twice at every call site. Use
IsReady and negate at the call.
6. Methods are verbs¶
Transfer, Purchase, Arrest, Resolve, Validate.
- A method returning a value without side effects:
Get…,Find…,Calculate…, or a property. Getimplies cheap and always succeeds.Findimplies it may return null.Loadimplies I/O and isAsync.- A method with side effects reads as a command:
Purchase, notDoPurchaseorHandlePurchase.
7. Events¶
Events are named for what happened, in the past tense, and carry a payload record:
public readonly record struct DoorPurchased(Character Buyer, Door Door, int Price);
public readonly record struct CharacterArrested(Character Character, TimeSpan Duration);
Cancellable events are named for what is about to happen, and expose cancellation explicitly — never by returning a truthy value (D-07):
public sealed class DoorPurchasing : CancellableEvent { … }
8. Namespaces¶
Applejack.Core.<Concern> Logging, Events, Persistence, Configuration
Applejack.<Module> Character, Items, Inventory, Economy, Crime, Jobs…
Applejack.<Module>.<Concern> .Components, .Rules, .Persistence, .Ui
The namespace matches the folder path. One type per file, filename matching the type.
No cider prefix. The legacy internal name is historical; it appears in
Documentation/Legacy/ and nowhere else.
9. Domain vocabulary¶
Use these consistently. Where the legacy name was misleading, the new name is given and the old one is recorded for translation.
| Term | Means | Legacy name |
|---|---|---|
| Character | A playable persona | (none — was the Steam account) |
| Account | The persistent Steam-level identity above characters | ply.cider |
| Item definition | The authored template | ITEM / GM.Items[id] |
| Item instance | A specific item with identity and state | (did not exist) |
| Inventory | A container of item instances | _Inventory / entity._Inventory |
| Space | The capacity unit (not weight) | Size |
| Ownership | Player / team / gang claim over an entity | _Owner |
| Access | Permission to use something you may not own | _Owner.access |
| Permission | A named capability held by a character | _Access flag string |
| Group / Gang / Team | The three-level job hierarchy | same |
| Need | An ambient depleting stat | _Hunger, _Stamina |
| Interaction | A timed, cancellable player action | timer.Conditional |
| Module | A unit of the framework | "plugin" |
"Plugin" now means a third-party extension. First-party units are modules. Keeping those distinct avoids the confusion that ADR-0002 resolves.
10. Files and assets¶
| Kind | Convention | Example |
|---|---|---|
| Source file | matches the type | InventoryService.cs |
| Test file | <TypeUnderTest>Tests.cs |
InventoryServiceTests.cs |
| Razor panel | PascalCase.razor |
InventoryPanel.razor |
| Item asset | snake_case.item |
small_pocket.item |
| Job asset | snake_case.job |
police_officer.job |
| Prefab | PascalCase.prefab |
WorldItem.prefab |
| Documentation | NN_SCREAMING_SNAKE.md |
06_PERSISTENCE.md |
Asset IDs stay snake_case deliberately: it matches the original's item IDs, which keeps the
legacy documentation directly usable as a content specification.