Intro to Coding - raisercostin/software-wiki GitHub Wiki
Check that every commit respect the following rules:
Use principles as guide in unknown territory.
Styles
- Offensive programming
- Add preconditions when interacting with external systems. Otherwise the system should crash (fail fast).
- https://en.wikipedia.org/wiki/Defensive_programming
- Use guava Preconditions
- see https://www.elegantobjects.org/
- Functional style
- top down, focus on input-output parameters (intention) rather than implementation details, TDD
- non strict, imutable collections
- Bad Objectual style
- Getter/setter vomit
- Prefer aggregation over inheritance
Principle Samples
- SRP
- Do not use Singletons
- Do not use modifiable static fields (log is acceptable)
- Elegant Objects
- Use NullObjects (read about nullability in kotlin)
- Collections (list, map, array, ...) should be empty collections not null
- Do not use null (use java.util.Optional) - Null Object
- Do not have references to null objects.
- If you could return null better to return Optional.empty()
- Never return null
- Simple classes
- Should
- be immutable: all fields final and imutable themselfs
- ideally :
private final Type field;
. If really neededpublic final Type field;
- initialized once at construction time
- Should Not
- have getters - imutable fields can be public if information needs to be exposed
- setters - imutable fields don't need setters
- Should
- Spring classes
- Use @Component, have one @Autowired, use constructor injection (do not use setter injection)
- Use NullObjects (read about nullability in kotlin)
- DCSS
- Do not use for(...) . Use functional operations on collections:
.map
,.foreach
,.filter
etc. - Important collections
- vavr: Seq, List, Map, Option, Try, Either
- reactor: Flux, Mono - future
- Do not use multithreading code. See DCSS. Thread, synchronized, Executor, java.Future, java.concurrent.* are raw (so dumb) structures. Actors, Flux are smarter.
- Do not use for(...) . Use functional operations on collections:
- DRY
- Use lombok: @Data @Getter(lombok.AccessLevel.NONE) @Setter(lombok.AccessLevel.NONE)
- Use short methods
- Use libraries
- Defer Execution
- Prefer smart delayed/lazy/non-strict structures - https://www.scala-lang.org/blog/2017/11/28/view-based-collections.html
- Supplier, Callable, vavr.Function, Flux, Mono, Iterable
- vavr: Seq, List, Map - they are immutable data structures that by design are not strict (don't have all the elements computed)
- Do not use:
- java.Function - not smart enough - not composable
- java.Stream - not smart enough, but not strict which is good
- If is possible do not use:
- java collections - they are strict structures
- Prefer smart delayed/lazy/non-strict structures - https://www.scala-lang.org/blog/2017/11/28/view-based-collections.html
Libraries
The absolute needed libraries are:
- junit5 - testing api
- slf4j - logging api - Intro to Logging
- logback - simple logging implementation (robust reporting on bean config and version of the used libraries)
- guava - google utilities
- typesafe config - more robust reporting than properties
- vavr
- vavr imutable collections over java standard ones
- vavr Option not standard java Optional
- reactor-flux
- java.time
Rules to follow when writing code:
- Careful on exception idioms
- Never swallow an exception. If in doubt rethrow it.
- principle~Fail Fast
- A logged exception at info level is always a bug.
- The exception should give enough details to be able to investigate the problem without debugging. If the investigation lasts more than 30s you have a bug on investigation of the exception.
- see Checked Exceptions vs Unchecked Exceptions
- Beans, Getters and Setters are overhyped
- Immutable classes (do not confuse with final fields)
Sample refactorings
Huge refactoring. Attention to
- use slf4j - private final static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DataSupplier.class);
- never hide exceptions
- at least log as debug: catch(...){ logger.debug("",ex); }
- catch(...){ /do nothing/ }
- never throw CheckedExceptions, catch and
throw new RuntimeException(checkedException)
- logger.info("text",ex) (never do an ex.toString())
- never use static except for logger
- never expose internals to others
- create immutable classes
- no duplicate code
- all fields by default private and final
- no circular dependencies
- attention to Runnable that can throw exceptions