Code Style

This guide outlines the coding conventions and style guidelines for TrustWeave.

Overview

TrustWeave follows Kotlin coding conventions with some project-specific guidelines:

  • Kotlin Style Guide – follows official Kotlin style guide
  • ktlint – automated formatting with ktlint
  • Naming Conventions – clear, descriptive names
  • Documentation – comprehensive KDoc comments

Code Formatting

ktlint Configuration

The project uses ktlint for code formatting. Format your code:

1
2
3
4
5
# Check formatting
./gradlew ktlintCheck

# Auto-format
./gradlew ktlintFormat

Format on Save

Configure your IDE to format on save:

IntelliJ IDEA:

  1. Install ktlint plugin
  2. Enable “Reformat code on save”
  3. Configure ktlint as formatter

Naming Conventions

Classes

Use PascalCase for class names:

1
2
3
class MyCustomDidMethod : DidMethod {
    // ...
}

Functions

Use camelCase for function names:

1
2
3
suspend fun createDid(options: DidCreationOptions): DidDocument {
    // ...
}

Variables

Use camelCase for variable names:

1
2
val issuerDid = "did:key:issuer"
val credentialSubject = jsonData { }

Constants

Use UPPER_SNAKE_CASE for constants:

1
2
3
4
companion object {
    const val DEFAULT_TIMEOUT = 30000L
    const val MAX_RETRIES = 3
}

Code Structure

File Organization

Organize files logically:

1
2
3
4
5
6
7
8
9
10
11
// Package declaration
package org.trustweave.example

// Imports
import org.trustweave.did.*
import kotlinx.coroutines.runBlocking

// Class/object definitions
class Example {
    // ...
}

Function Length

Keep functions concise:

  • Short functions – prefer functions under 20 lines
  • Complex logic – extract to separate functions
  • Single responsibility – each function should do one thing

Class Size

Keep classes focused:

  • Single responsibility – each class should have one purpose
  • Composition over inheritance – prefer composition
  • Interfaces – use interfaces for abstractions

Documentation

KDoc Comments

Document public APIs:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * Creates a DID using the specified method.
 *
 * @param method The DID method to use (e.g., "key", "web")
 * @param options Configuration options for DID creation
 * @return Result containing the created DID document or error
 */
suspend fun createDid(
    method: String,
    options: DidCreationOptions
): Result<DidDocument> {
    // ...
}

Inline Documentation

Add comments for complex logic:

1
2
// Generate identifier from public key using multibase encoding
val identifier = multibase.encode(key.publicKey)

Error Handling

Result Types

Use Result<T> for your own helpers when it fits. The TrustWeave facade and DID layer prefer sealed types (DidCreationResult, DidResolutionResult, IssuanceResult, VerificationResult, …)—handle those with when, not only Result.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
suspend fun createDid(): Result<DidDocument> {
    return try {
        val document: DidDocument = /* implementation */
        Result.success(document)
    } catch (e: Exception) {
        Result.failure(
            DidException.DidCreationFailed(
                did = null,
                reason = e.message ?: "Unknown error",
                cause = e
            )
        )
    }
}

Error types

Prefer module sealed exception hierarchies (for example org.trustweave.did.exception.DidException, org.trustweave.anchor.exceptions.BlockchainException) and the shared base org.trustweave.core.exception.TrustWeaveException instead of ad-hoc error classes.

Testing

Test Naming

Use descriptive test names:

1
2
3
4
5
6
7
8
9
@Test
fun testCreateDidWithEd25519Algorithm() = runBlocking {
    // ...
}

@Test
fun testResolveDidReturnsDocument() = runBlocking {
    // ...
}

Test Organization

Organize tests logically:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class DidMethodTest {
    @Test
    fun testCreateDid() = runBlocking {
        // ...
    }

    @Test
    fun testResolveDid() = runBlocking {
        // ...
    }

    @Test
    fun testUpdateDid() = runBlocking {
        // ...
    }
}

Best Practices

Immutability

Prefer immutable data:

1
2
3
4
5
6
7
8
9
// Prefer immutable data classes
data class DidDocument(
    val id: String,
    val verificationMethod: List<VerificationMethod>
)

// Avoid mutable state
// ❌ var document: DidDocument? = null
// ✅ val document: DidDocument? = null

Null Safety

Use Kotlin’s null safety features:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// TrustWeave: resolveDid returns sealed DidResolutionResult — branch, then use document
import org.trustweave.did.identifiers.Did
import org.trustweave.did.model.DidDocument
import org.trustweave.did.resolver.DidResolutionResult
// val trustWeave: TrustWeave = …

val didDocument: DidDocument? = when (val r = trustWeave.resolveDid(Did("did:key:…"))) {
    is DidResolutionResult.Success -> r.document
    is DidResolutionResult.Deactivated -> null
    is DidResolutionResult.Failure -> null
}

// Safe calls on a nullable DidDocument from any layer
didDocument?.verificationMethod?.first()

// Elvis for defaults
val method = didDocument?.verificationMethod?.first() ?: throw NotFoundException()

Collapsing Deactivated to null here is fine for a “do I have a document” check, but it throws away the distinction between “never registered” and “revoked.” Code that uses the document for verification or authorization should branch on Deactivated separately and reject it, rather than treating a null document as merely absent.

Extension Functions

Use extension functions for utilities:

1
2
3
fun DidDocument.toJson(): JsonObject {
    // Conversion logic
}

Scope Functions

Use scope functions appropriately:

1
2
3
4
5
6
7
8
9
10
// Use `let` for null checks
didDocument?.let { document ->
    // Use document
}

// Use `apply` for configuration
val config = MyConfig().apply {
    endpoint = "https://example.com"
    timeout = 30000L
}

Code Review Guidelines

Checklist

Before submitting code for review:

  • Code is formatted (./gradlew ktlintCheck)
  • All tests pass (./gradlew test)
  • Public APIs are documented
  • Error handling is appropriate
  • Code follows naming conventions
  • No hardcoded values (use constants)
  • No commented-out code

Review Feedback

When reviewing code:

  • Be constructive and respectful
  • Focus on code quality, not style preferences
  • Suggest improvements, don’t just point out issues
  • Explain why changes are needed

Next Steps

References


This site uses Just the Docs, a documentation theme for Jekyll.