|
| 1 | +# Development guidelines |
| 2 | + |
| 3 | +# Getting started |
| 4 | + |
| 5 | +To get started you need: |
| 6 | + |
| 7 | +- JDK 11 installed |
| 8 | + |
| 9 | +alternatively a recent IntelliJ IDEA Community Edition version is enough. |
| 10 | + |
| 11 | +The project is built using [Gradle](https://gradle.org), the build is defined using Gradle Kotlin DSL. If you never used |
| 12 | +Gradle I kindly suggest to start from [its awesome docs](https://gradle.org/guides/#getting-started). |
| 13 | + |
| 14 | +## Server |
| 15 | + |
| 16 | +The server is [quarkus](https://quarkus.io) application that exposes a REST API implementing Whitefox and |
| 17 | +delta-sharing protocol. If you never worked with Quarkus, have a look at [its awesome doc](https://quarkus.io/get-started/). |
| 18 | + |
| 19 | +The app is developed and run for JVM 11 because hadoop libraries (which are a dependency of delta-lake kernel) do |
| 20 | +not run properly on newer versions of the JVM. |
| 21 | + |
| 22 | +As soon as you clone the project you should verify that you are able to build and test locally, to do so you need to |
| 23 | +run the `check` command of Gradle, you can achieve that using either `gradlew` script in the project root (`. |
| 24 | +/gradlew check`) or run the same [gradle task from intellij](https://www.jetbrains.com/help/idea/work-with-gradle-tasks. |
| 25 | +html). If you're default jvm is not version 11, you can run `gradlew` passing another java home as follows: |
| 26 | +`./gradlew -Dorg.gradle.java.home=<PATH_TO_JAVA_HOME> build`. |
| 27 | + |
| 28 | +Sometimes IntelliJ will tell you have build errors, especially when moving from one branch to the other. The problem |
| 29 | +might be that the auto-generated code (we generate stubs from openapi) is out of date. A simple `compileJava` will |
| 30 | +fix it. |
| 31 | + |
| 32 | +Before every push you ~~can~~ should run locally `./gradlew devCheck` that will both reformat the code and run the |
| 33 | +unit tests. |
| 34 | + |
| 35 | +You can run the server locally with the command: `gradlew server:quarkusDev` |
| 36 | + |
| 37 | +### Windows |
| 38 | + |
| 39 | +Some hadoop related tests do not run on Windows (especially in the Windows CI) so you can find the disabled using junit5 |
| 40 | +annotation `@DisabledOnOs(WINDOWS)`. If you want to provide a fix for them, feel free to open a PR. |
| 41 | + |
| 42 | +## Code formatting |
| 43 | + |
| 44 | +We use spotless to format and check the style of Java code. Spotless can be run through Gradle: |
| 45 | + |
| 46 | +- to reformat: `./gradlew spotlessApply` |
| 47 | +- to check formatting: `./gradlew spotlessCheck` |
| 48 | + |
| 49 | +## Protocol |
| 50 | + |
| 51 | + Whitefox protocol and original delta-sharing are kept under [`docs/protocol`](protocol). We use openapi |
| 52 | + specification to generate code for server and client. Furthermore, the protocol itself is validated using [spectral] |
| 53 | + (https://stoplight.io/open-source/spectral), you can find spectral configuration at [`.spectral.yaml`](../.spectral.yaml). |
| 54 | + |
| 55 | + |
| 56 | +# Software Engineering guidelines |
| 57 | + |
| 58 | +Some golden rules that we use in this repo: |
| 59 | + |
| 60 | +- always prefer immutability, this helps writing correct concurrent code |
| 61 | +- use constructor-based dependency injection when possible (i.e. do not annotate with `@Inject` any field) this |
| 62 | + makes testing beans easy without a CDI framework (that makes unit test much faster) |
| 63 | +- the "core" code should [make illegal states unrepresentable](https://khalilstemmler.com/articles/typescript-domain-driven-design/make-illegal-states-unrepresentable/) |
| 64 | +- never use `null`, use `Optional` to convey optionality, ignore IntelliJ "warning" when passing `Optional` to methods |
| 65 | +- throw exceptions and write beautiful error messages |
| 66 | +- use `@QuarkusTest` annotation only when you really need the server to be running, otherwise write a "simple" unit |
| 67 | + test |
| 68 | +- don't use `@SessionScoped` it will make our life miserable when trying to scale horizontally |
| 69 | +- [use `@ApplicationScoped` everywhere, `@Singleton` when `@ApplicationScoped` does not fit](https://quarkus.io/guides/cdi#applicationscoped-and-singleton-look-very-similar-which-one-should-i-choose-for-my-quarkus-application) |
| 70 | +- de-couple different layers of the application as much as possible: |
| 71 | + - REST API classes should deal with auto-generated model classes, convert them (when needed) to the "core" |
| 72 | + representation and pass it to "services" |
| 73 | + - services should not know anything about the outside world (i.e. REST API) and should deal with "core" models |
| 74 | + that do not depend on any given serialization format |
| 75 | + - persistence is its own world too, if needed we can create "persistence-related" classes to use ORM tools but |
| 76 | + these should not interfere in any way with the core ones |
| 77 | + - we will hand-craft (for now, who knows in the future) a lot of `mappers` that are function that go from one |
| 78 | + "layer" to another (REST API/persistence/core are all layers) |
| 79 | + |
| 80 | +For example, you can see the `DeltaSharesApiImpl` class, it deals with jakarta annotations to define http endpoints, |
| 81 | +it deals with errors thrown by the underlying (core) service and transforms those errors into 500/400 status codes |
| 82 | +and related http response and performs "protocol adaptation" which is transform http requests into core objects, |
| 83 | +then invokes the underlying core service and transforms the output of the service into a http response. `DeltaSharesApiImpl` |
| 84 | +has no business logic, it performs only "mappings" between the internal core model (made of methods, exceptions |
| 85 | +classes) to the external world made of json payloads and http response/requests. |
| 86 | + |
| 87 | +On the other hand `DeltaSharesServiceImpl` is business logic, it knows nothing about http, therefore it does not |
| 88 | +depend on any auto-generated code from the openapi spec. |
0 commit comments