Skip to content

Commit 09f97a6

Browse files
committed
make coding style part of AGENTS.md
1 parent e25278e commit 09f97a6

File tree

2 files changed

+134
-133
lines changed

2 files changed

+134
-133
lines changed

AGENTS.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,3 +419,137 @@ def xform(text):
419419
print('OK')
420420
PY
421421
```
422+
423+
# Java DOP Coding Standards ####################
424+
425+
This file is a Gen AI summary of CODING_STYLE.md to use less tokens of context window. Read the original file for full details.
426+
427+
IMPORTANT: We do TDD so all code must include targeted unit tests.
428+
IMPORTANT: Never disable tests written for logic that we are yet to write we do Red-Green-Refactor coding.
429+
430+
## Core Principles
431+
432+
* Use Records for all data structures. Use sealed interfaces for protocols.
433+
* Prefer static methods with Records as parameters
434+
* Default to package-private scope
435+
* Package-by-feature, not package-by-layer
436+
* Create fewer, cohesive, wide packages (functionality modules or records as protocols)
437+
* Use public only when cross-package access is required
438+
* Use JEP 467 Markdown documentation examples: `/// good markdown` not legacy `/** bad html */`
439+
* Apply Data-Oriented Programming principles and avoid OOP
440+
* Use Stream operations instead of traditional loops. Never use `for(;;)` with mutable loop variables use
441+
`Arrays.setAll`
442+
* Prefer exhaustive destructuring switch expressions over if-else statements
443+
* Use destructuring switch expressions that operate on Records and sealed interfaces
444+
* Use anonymous variables in record destructuring and switch expressions
445+
* Use `final var` for local variables, parameters, and destructured fields
446+
* Apply JEP 371 "Local Classes and Interfaces" for cohesive files with narrow APIs
447+
448+
## Data-Oriented Programming
449+
450+
* Separate data (immutable Records) from behavior (never utility classes always static methods)
451+
* Use immutable generic data structures (maps, lists, sets) and take defense copies in constructors
452+
* Write pure functions that don't modify state
453+
* Leverage Java 21+ features:
454+
* Records for immutable data
455+
* Pattern matching for structural decomposition
456+
* Sealed classes for exhaustive switches
457+
* Virtual threads for concurrent processing
458+
459+
## Package Structure
460+
461+
* Use default (package-private) access as the standard. Do not use 'private' or 'public' by default.
462+
* Limit public to genuine cross-package APIs
463+
* Prefer package-private static methods. Do not use 'private' or 'public' by default.
464+
* Limit private to security-related code
465+
* Avoid anti-patterns: boilerplate OOP, excessive layering, dependency injection overuse
466+
467+
## Constants and Magic Numbers
468+
469+
* **NEVER use magic numbers** - always use enum constants
470+
* **NEVER write large if-else-if statements over known types** - will not be exhaustive and creates bugs when new types are added. Use exhaustive switch statements over bounded sets such as enum values or sealed interface permits
471+
472+
## Functional Style
473+
474+
* Combine Records + static methods for functional programming
475+
* Emphasize immutability and explicit state transformations
476+
* Reduce package count to improve testability
477+
* Implement Algebraic Data Types pattern with Function Modules
478+
* Modern Stream Programming
479+
* Use Stream API instead of traditional loops
480+
* Write declarative rather than imperative code
481+
* Chain operations without intermediate variables
482+
* Support immutability throughout processing
483+
* Example: `IntStream.range(0, 100).filter(i -> i % 2 == 0).sum()` instead of counting loops
484+
* Always use final variables in functional style.
485+
* Prefer `final var` with self documenting names over `int i` or `String s` but its not possible to do that on a `final` variable that is not yet initialized so its a weak preference not a strong one.
486+
* Avoid just adding new functionality to the top of a method to make an early return. It is fine to have a simple guard statement. Yet general you should pattern match over the input to do different things with the same method. Adding special case logic is a code smell that should be avoided.
487+
488+
## Documentation using JEP 467 Markdown documentation
489+
490+
IMPORTANT: You must not write JavaDoc comments that start with `/**` and end with `*/`
491+
IMPORTANT: You must "JEP 467: Markdown Documentation Comments" that start all lines with `///`
492+
493+
Here is an example of the correct format for documentation comments:
494+
495+
```java
496+
/// Returns a hash code value for the object. This method is
497+
/// supported for the benefit of hash tables such as those provided by
498+
/// [java.util.HashMap].
499+
///
500+
/// The general contract of `hashCode` is:
501+
///
502+
/// - Whenever it is invoked on the same object more than once during
503+
/// an execution of a Java application, the `hashCode` method
504+
/// - If two objects are equal according to the
505+
/// [equals][#equals(Object)] method, then calling the
506+
/// - It is _not_ required that if two objects are unequal
507+
/// according to the [equals][#equals(Object)] method, then
508+
///
509+
/// @return a hash code value for this object.
510+
/// @see java.lang.Object#equals(java.lang.Object)
511+
```
512+
513+
## Logging
514+
515+
- Use Java's built-in logging: `java.util.logging.Logger`
516+
- Log levels: Use appropriate levels (FINE, FINER, INFO, WARNING, SEVERE)
517+
- **FINE**: Production-level debugging, default for most debug output
518+
- **FINER**: Verbose debugging, detailed internal flow, class resolution details
519+
- **INFO**: Important runtime information
520+
- LOGGER is a static field: `static final Logger LOGGER = Logger.getLogger(ClassName.class.getName());` where use the primary interface or the package as the logger name with the logger package-private and shared across the classes when the package is small enough.
521+
- Use lambda logging for performance: `LOGGER.fine(() -> "message " + variable);`
522+
523+
# Compile, Test, Debug Loop
524+
525+
- **Check Compiles**: Focusing on the correct mvn module run without verbose logging and do not grep the output to see compile errors:
526+
```bash
527+
$(command -v mvnd || command -v mvn || command -v ./mvnw) -pl json-java21-api-tracker -Djava.util.logging.ConsoleHandler.level=SEVERE
528+
```
529+
- **Debug with Verbose Logs**: Use `-Dtest=` to focus on just one or two test methods, or one class, using more logging to debug the code:
530+
```bash
531+
$(command -v mvnd || command -v mvn || command -v ./mvnw) -pl json-java21-api-tracker -Dtest=XXX -Djava.util.logging.ConsoleHandler.level=FINER
532+
```
533+
- **No Grep Filtering**: Use logging levels to filter output, do not grep the output for compile errors, just run less test methods with the correct logging to reduce the output to a manageable size. Filtering hides problems and needs more test excution to find the same problems which wastes time.
534+
535+
## Modern Java Singleton Pattern: Sealed Interfaces
536+
537+
**Singleton Object Anti-Pattern**: Traditional singleton classes with private constructors and static instances are legacy should be avoided. With a functional style we can create a "package-private companion module" of small package-private methods with `sealed interfacee GoodSingletonModule permits Nothing { enum Nothing extends GoodSingletonModule{}; /* static functional methods here */ }`.
538+
539+
### Assertions and Input Validation
540+
541+
1. On the public API entry points use `Objects.assertNonNull()` to ensure that the inputs are legal.
542+
2. After that on internal method that should be passed only valid data use `assert` to ensure that the data is valid.
543+
- e.g. use `assert x==y: "unexpected x="+x+" y="+y;` as `mvn` base should be run with `-ea` to enable assertions.
544+
3. Often there is an `orElseThrow()` which can be used so the only reason to use `assert` is to add more logging to the error message.
545+
4. Consider using the validations of `Object` and `Arrays` and the like to ensure that the data is valid.
546+
- e.g. `Objects.requireNonNull(type, "type must not be null")` or `Arrays.checkIndex(index, array.length)`.
547+
548+
## JEP References
549+
550+
[JEP 467](https://openjdk.org/jeps/467): Markdown Documentation in JavaDoc
551+
[JEP 371](https://openjdk.org/jeps/371): Local Classes and Interfaces
552+
[JEP 395](https://openjdk.org/jeps/395): Records
553+
[JEP 409](https://openjdk.org/jeps/409): Sealed Classes
554+
[JEP 440](https://openjdk.org/jeps/440): Record Patterns
555+
[JEP 427](https://openjdk.org/jeps/427): Pattern Matching for Switch

CODING_STYLE_LLM.md

Lines changed: 0 additions & 133 deletions
This file was deleted.

0 commit comments

Comments
 (0)