Files
trueref/CODE_STYLE.md
moze c5f950c2c0
Some checks failed
Build and publish Docker image / Build and push (push) Failing after 1m27s
Initial commit: trueref v0.1.0-SNAPSHOT
Java 21 / Spring Boot 3.5.3 multi-module Maven project.
Hybrid BM25+HNSW search with RRF, cross-encoder reranker,
ONNX Runtime 1.22.0 (CPU + CUDA 12 GPU variants).
2026-05-06 00:49:16 +02:00

5.9 KiB

trueref — Code Style

1. Language & Toolchain

  • Java 21, source/target 21.
  • Maven with spring-boot-maven-plugin for the fat JAR.
  • Spotless with Palantir Java Format for formatting (4-space indent, 120 col).
  • ErrorProne + NullAway for static analysis. NullAway annotations: @org.jspecify.annotations.Nullable / @NonNull.
  • Hexagonal boundaries are enforced by Maven module dependencies (no ArchUnit). See ARCHITECTURE §3.

2. Records, Sealed Types, Pattern Matching

  • Prefer records for DTOs, value objects, and port.in/port.out parameter/result types.
  • Use sealed interfaces for closed result/event hierarchies (sealed interface IngestionEvent permits ...).
  • Use pattern matching (switch expressions, instanceof) over visitor pattern.

3. Nullability & Optional

  • All API surfaces (public methods on ports, REST DTOs) are non-null by default; mark nullable explicitly with @Nullable.
  • Use Optional<T> only as a return type from query-style methods. Never as a field, never as a parameter.

4. Concurrency

  • Spawn virtual threads via Thread.ofVirtual().start(...) or Executors.newVirtualThreadPerTaskExecutor(). Never call Thread.sleep inside a synchronized block.
  • Shared mutable state is forbidden in domain and discouraged in application. When unavoidable, use java.util.concurrent.atomic.* or a ReentrantLock.
  • GPU work goes through GpuSemaphore.acquire() (a thin wrapper around Semaphore).
  • Long-running orchestration uses structured concurrency (StructuredTaskScope) where it improves cancellation safety.

5. Error Handling

  • Domain errors are sealed exception hierarchies rooted at TrueRefException. Adapters translate them to HTTP/JSON-RPC errors centrally (REST: @ControllerAdvice; MCP: dedicated translator).
  • No checked exceptions at port boundaries. Wrap third-party checked exceptions at the adapter edge.
  • Validation errors carry a stable code (string) so the UI can localize.
  • Never catch (Exception e) and swallow. Either log + rethrow as a domain exception or let it propagate.

6. Logging

  • SLF4J with parameterized messages: log.info("indexed tag {} of repo {}", tag, repoName); — never string-concatenate.
  • Structured fields via MDC: repoId, versionId, jobId, stage. Cleared in a try/finally.
  • Log levels:
    • ERROR: unrecoverable, requires operator attention.
    • WARN: degraded, automatic recovery in progress.
    • INFO: lifecycle events (job started/finished, repo registered).
    • DEBUG: per-file, per-chunk detail. Off by default.

7. Naming

  • Use cases (port.in): imperative verb phrases — IndexVersion, ResolveLibraryId.
  • SPIs (port.out): noun-ish role names — EmbeddingService, ChunkStore, GitClient.
  • Adapter classes: <Tech><Role>LuceneChunkStore, OnnxEmbeddingService, JGitClient.
  • DTOs: <Resource><Action>Request / <Resource>Response.
  • Records' field names are camelCase (no Hungarian, no _ prefixes).

8. Package & File Discipline

  • One public type per file.
  • Internal helpers are package-private. Avoid public unless used across packages.
  • Domain packages export only records and interfaces. No Spring annotations, no Lombok, no Jackson annotations.
  • Adapter packages may use Spring stereotypes (@Component, @Repository, @RestController) but adapters depend on port interfaces only when interacting with the application.

9. Spring Wiring

  • Wiring lives in bootstrap. Each adapter package may define a @Configuration (constructor-injected @Bean factories) but does not auto-@ComponentScan itself; bootstrap explicitly imports.
  • Use @ConfigurationProperties records for typed config; never raw @Value.
  • Prefer constructor injection. No field injection.

10. Persistence (H2)

  • Migrations under src/main/resources/db/migration named V<N>__<snake_case>.sql. Flyway runs at startup.
  • All access via Spring JdbcClient (Spring Boot 3.2+, fluent JDBC). No JPA/Hibernate, no JdbcTemplate directly.
  • Mappers are explicit RowMapper<T> lambdas, not reflection-based.
  • SQL lives next to the repository class, either as static final String constants or in *.sql files loaded via ClassPathResource for non-trivial queries.

11. REST

  • Controllers in adapter.in.rest. They depend only on port.in interfaces and DTO records.
  • DTOs are separate from domain records. Mapping via plain static of(...) factories. No MapStruct.
  • All endpoints documented with @Operation, @ApiResponses, @Schema (springdoc).
  • Request validation via jakarta.validation annotations on DTOs.
  • SSE endpoints return SseEmitter; subscribe to JobEventBus, unsubscribe on completion/timeout.

12. MCP

  • Tool definitions are records decorated to produce JSON Schema via Spring AI's MCP support. Schema strings stay verbatim (1:1 with Context7) so LLMs see identical contracts.
  • Tool handlers depend only on port.in (SearchLibraryDocs, ResolveLibraryId).

13. Tests

  • JUnit 5 + AssertJ + Mockito (sparingly).
  • Unit tests live next to the package they test. Integration tests under src/test/java/.../it/ and use @SpringBootTest.
  • Use Testcontainers only when truly required (we mostly avoid it via embedded stores).
  • ArchUnit test suite is mandatory and runs in CI.

14. Dependency Hygiene

  • BOM-managed versions only. Add a dependency only if it provides clear value over JDK + Spring Boot + already-included libs.
  • No Lombok, no Guava (use JDK 21 equivalents), no Reactor (we use virtual threads + blocking).
  • No Kotlin, no Scala.

15. Documentation

  • All architectural decisions go in ARCHITECTURE.md.
  • All research notes go in FINDINGS.md with sources.
  • All conventions go in this file.
  • Per-package package-info.java may exist for non-trivial packages, summarizing role and exported types.
  • No README sprawl: README.md is a quickstart only and links to the three docs above.