Let Kody automatically check quality, security and performance in every pull request—cloud or self-hosted, in under 2 minutes.
A complete checklist to help you review Java code for correctness, security and performance, ensuring every pull request is production ready.
Here’s what this checklist helps you review before approving a pull request.
✅ Code & Design Quality – clear structure, modern Java/OOP patterns, solid module boundaries
✅ Security & Performance – input validation, safe deserialization, secrets management, efficient queries, caching, scalability
✅ Reliability & Operability – robust error handling, testing, observability, safe CI/CD rollouts
✅ Data & Integration – APIs/contracts, transactions, safe migrations, multi-tenant isolation, clean configuration
Use these points as a starting guide to automate code reviews with your agent.
Names are descriptive and follow Java conventions (classes PascalCase
, methods/fields camelCase
, constants UPPER_SNAKE_CASE
).
Methods are short, single-purpose, and have clear intent; no “God” classes or 1K-line files.
No commented-out code or dead code; TODOs are tracked in issues, not left in source.
Consistent formatting via an auto-formatter (e.g., google-java-format
or IDE profile); no style bikeshedding in review.
Public APIs have Javadoc on classes, public methods, and non-obvious behavior; internal code has focused comments explaining why, not what.
Clear package structure (domain-oriented or hexagonal); no cyclic package dependencies.
Avoid unnecessary abbreviations; avoid wildcard imports; static imports used only for test/assertions.
Use enhanced switch
/pattern matching where it improves clarity; prefer var
locally only when it increases readability.
Stream/λ usage is readable; no deeply nested stream pipelines—extract steps with named methods when complex.
Avoid primitive obsession when a value object conveys intent; prefer record
for simple immutable aggregates.
Favor immutability: fields final
where possible; objects defensive-copy mutable inputs/collections.
Correctly implement equals
/hashCode
/toString
for value types; prefer record
to get these for free.
Respect encapsulation: minimal visibility (private
> package-private > protected
> public
).
Program to interfaces; invert dependencies; no hard wiring of implementations inside domain logic.
Avoid inheritance for code reuse; prefer composition; abstract classes used only for shared behavior contracts.
No business logic in constructors; use factories/builders for complex construction.
Optional
only for return values, not fields/params; do not call get()
without presence checks.
Null-handling strategy is explicit; avoid returning null
collections; use List.of()
/Collections.emptyList()
.
Concurrency aware: avoid shared mutable state; prefer thread-safe structures or confinement.
Java 17+/21 features: sealed classes for closed hierarchies; record
for DTOs; virtual threads (if adopted) used intentionally.
Inputs validated and sanitized at boundaries; use bean validation (jakarta.validation
) for DTOs.
No SQL injection risks: parameterized queries or ORM with safe binding; no string concatenation in queries.
Sensitive data never logged; use structured logging with redaction; PII masked by default.
Secrets/keys/credentials loaded from secure store or env, never from source control; no secrets in config, tests, or Git history.
Cryptography via vetted libs; no custom crypto; strong algorithms and proper key sizes; secure random (SecureRandom
).
Authentication/authorization enforced on all endpoints and background jobs; least-privilege for service accounts.
CSRF, CORS, and clickjacking protections configured; HTTP security headers set (HSTS, X-Content-Type-Options, etc.).
Deserialization is safe: disable default typing; allow-list types; prefer JSON-B/Jackson with strict config.
File uploads: validate content type/size; store outside web root; scan if needed.
Command execution and path handling: no shell injection; use ProcessBuilder
; validate/normalize paths with Path
API.
Dependencies scanned and up to date; no known CVEs; use BOMs and lockfiles; evaluate transitive risk.
Multi-tenant/data isolation rules enforced at every data access path.
TLS everywhere; verify certificates; enforce modern cipher suites on servers/clients.
Rate limiting, abuse detection, and audit trails present on sensitive operations.
Hot paths avoid unnecessary allocations; reuse buffers; prefer StringBuilder
for concatenation in loops.
Collections chosen appropriately (ArrayList
vs LinkedList
, EnumSet
/EnumMap
, ConcurrentHashMap
when needed).
Avoid N+1 queries; batching/fetch graphs configured; pagination/streaming for large datasets.
Caching strategy defined (keys, TTLs, invalidation); no unbounded in-memory maps; consider Cache
/Caffeine.
I/O uses NIO where beneficial; proper timeouts on network calls; no blocking calls on reactive threads (if using reactive).
Parallelism used intentionally: executors sized correctly; CompletableFuture
or virtual threads where appropriate.
No synchronized bottlenecks; fine-grained locks or lock-free structures; avoid contention on shared monitors.
Algorithmic complexity is acceptable; avoid quadratic behavior on large inputs; include rough Big-O awareness in reviews.
JSON/XML mappers configured for performance (afterburner, record modules) where safe; avoid reflection heavy paths in hot loops.
Avoid premature micro-optimizations; add microbenchmarks (JMH) for disputed hotspots.
Exceptions are meaningful and actionable; no swallowed exceptions; never catch Throwable
unless rethrowing safely.
Use specific exception types; wrap and add context; avoid leaking internal details to clients.
Try-with-resources for all Closeables; streams/sockets/files are closed deterministically.
Retries use bounded attempts with backoff and jitter; only for idempotent operations; circuit breaker where needed.
Timeouts on all external calls (HTTP, DB, message broker); no infinite waits or blocking joins without limits.
Fallbacks are safe and degrade gracefully; no silent data corruption.
Domain errors modeled explicitly (e.g., result types) where it improves clarity over exceptions.
Error messages/logs include correlation/request IDs; avoid stack traces in user-facing responses.
Distinguish transient vs permanent errors; do not retry on validation/authz failures.
Unit tests (JUnit 5) cover core logic; fast and deterministic; meaningful assertions (no “assertTrue(true)”).
Property-based tests for critical pure functions and parsers; boundary conditions included.
Integration tests cover DB, message brokers, and HTTP edges; use Testcontainers or equivalent.
API/contract tests for external integrations; consider Pact/contract testing where coupling exists.
Repro of prod bugs has a test before the fix; tests fail without the fix.
Fixtures are minimal and readable; factories/builders for complex objects; avoid global mutable state.
Concurrency tests (where applicable) simulate contention/races; use @Timeout
to prevent hangs.
Performance/regression tests for hotspots with guardrails (not flaky microbenchmarks in CI).
Code coverage is monitored, but quality > %; critical paths and error handling are covered.
Test names describe behavior; Given/When/Then or Arrange/Act/Assert structure.
Module boundaries are clear; no cross-layer leaks (e.g., controllers aware of ORM internals).
Domain logic isolated from frameworks; ports/adapters or hexagonal seams exist for I/O.
Public APIs stable with versioning; backward compatibility considered; deprecations documented.
Config via env/props with sane defaults; 12-factor principles; no environment-specific branches in code.
Observability: structured logs, metrics (RED/USE), and traces added at key points; no log spam.
Idempotency for handlers and consumers; deduplication where messages may be delivered at-least-once.
Backpressure respected (reactive or queue-based); no unbounded queues; rate limits where needed.
Data migrations are incremental, backward compatible, and include rollback plans.
Feature flags used for risky changes; dark launches and canaries available.
Horizontal scaling considered: stateless services or sticky requirements justified; session state externalized.
GC and memory settings sane for workload; no large object retention; leaks checked with tooling.
Documentation updated (README/ADR/Runbook) for new modules, configs, and ops procedures.
Patterns used to simplify not complicate: only when they reduce duplication or clarify variability.
Factory/Builder for complex object creation; no telescoping constructors.
Strategy/Policy to encapsulate variable behaviors; avoid if/else
pyramids on type codes—prefer polymorphism or sealed hierarchies.
Template Method/Hook points only when extension is needed and documented.
Adapter/Facade to isolate third-party SDKs; prevent vendor lock-in leaking across the codebase.
Observer/Eventing used with clear ownership and delivery guarantees; avoid hidden side effects.
Repository/Aggregate boundaries consistent (if using DDD); invariants enforced inside aggregates.
Anti-patterns avoided: service locator, God objects, anemic domain model (unless explicitly opting for transaction script), circular deps.
DTOs vs Entities separated; records for immutable DTOs; mapping centralized (MapStruct or equivalent).
Configuration/Feature toggles not sprinkled across domain logic; centralized toggle access with typed wrappers.
Dependency injection scopes correct; avoid field injection; prefer constructor injection.
Transaction boundaries explicit; correct isolation/propagation; no lazy loads outside transactions unless intended.
Web layer validates inputs and returns consistent error contracts; no leaking exceptions as 500 without mapping.
Schedulers and async execution backed by properly sized executors; no default unbounded pools.
HTTP clients configured with timeouts, connection pools, and resilience policies.
Message consumers are idempotent; dead-letter/retry policies configured.
Configuration properties are type-safe; no @Value
stringly-typed sprawl for complex config.
Schema normalized/denormalized intentionally; indexes exist for query patterns; no full scans on hot paths.
Migrations (Flyway/Liquibase) are forward-only with checks; data backfills planned.
Lazy vs eager loading decisions explicit; projections used for read-heavy paths.
Transactions minimize lock contention; long transactions avoided; batch writes where safe.
Time handled with java.time
(UTC storage, zone conversion at edges); no legacy Date
/Calendar
usage.
Reproducible builds; pinned plugin and dependency versions; BOMs used for alignment.
CI runs unit + integration tests, linters, security scans, and produces artifacts with provenance.
SBOM generated and stored; vulnerability gates enforced with clear SLAs.
Container images minimal, non-root, read-only fs; health/readiness endpoints implemented.
Startup/shutdown hooks graceful; SIGTERM respected; long tasks drain on shutdown.
Rollback is possible; versioned configs; database compatibility checked during deploys.
Runbooks/alerts defined for SLOs; alarms actionable; no noisy alerts.
Let Kody automatically check quality, security and performance in every pull request—cloud or self-hosted, in under 2 minutes.