Spinnaker is a collection of microservices built from a common foundation which has evolved over time. You do not need to know all of the technologies listed to contribute. Please consider these standards and conventions when submitting pull requests to Spinnaker.
Spinnaker is comprised of JVM backend-services and a frontend application (Deck). See an overview of the architecture in our reference documentation.
Use the following languages to fix and extend Spinnaker services:
Sub-projects of Spinnaker microservices are called modules.
Our language of choice is Kotlin , and we recommend using it in any module that does not currently use Groovy. However, it is absolutely fine to write Java code if that’s what you’re more comfortable with.
There are cross-compilation issues with mixing Groovy and Kotlin in the same source tree. To reduce complexity, please avoid mixing both languages in a single module.
If you are writing new code for an existing module that uses Groovy, please write in Java.
Spinnaker uses Java 8, and where appropriate, we encourage use of newer features such as lambdas, the streams API, the
java.time package, and default interface methods.
Although much of Spinnaker is written in it, we have deprecated Groovy . Please avoid contributing new production code that uses Groovy. Changes to existing Groovy code are acceptable, but new classes should not be written in Groovy.
You are welcome to use Groovy with Spock for writing tests.
Refactoring is also welcome. If your changes touch Groovy code that you can transform into Java, please feel free to do so. Interfaces, for example require almost no changes.
Types from the Groovy runtime libraries should not be exposed in the API of any class. Since Groovy closures can be automatically type-coerced to Java SAM types , please use an appropriate SAM type for parameters or return types that may be implemented with Groovy closures.
Spinnaker is built on the shoulders of giants. This is not an exhaustive list of libraries that we use, but the ones we’ve identified as having a large presence across the product.
Spinnaker is an ever-evolving system, and as such, so are the foundations we’ve chosen to build on top of. These libraries still see extensive use within Spinnaker, however they have been deprecated in favor of another solution and the spread of their use is discouraged.
For Groovy and miscellaneous files, please use:
Code formatting is applied automatically with a git pre-commit hook, but if you need to check or apply code formatting outside of this process:
Spinnaker microservices automatically component-scan for
@Configuration classes in the
com.netflix.spinnaker.config package (although we will need to rethink this convention for Java 9 compatibility).
Other classes should be placed in
<service> is the microservice name, for example
<feature> is something descriptive of the feature being implemented.
Please do not separate classes into different packages according to what they are. Packages should represent the group of classes that implement a particular piece of functionality not all components of a particular type.
Please use descriptive but concise names for variables, classes, properties, methods, and so on. Longer names are good when they add clarity. Shorter names are good when they reduce redundancy.
It’s preferable to use types that properly represent things like durations, or timestamps (
java.time.Instant would be ideal in those specific cases).
If that’s not practical please include a suffix on the property / variable name that describes the unit.
A property declared as
public long getTimeout() is ambiguous and can easily lead to errors when developers using your code assume what the units are.
For example, these names are much less likely to result in errors:
public long getTimeoutMillis(); public long getTimeoutSeconds();
When writing Java code, please use
@javax.annotation.Nonnull annotations on return types and parameters of public methods.
This lets the Kotlin compiler make better decisions about the interactions between Kotlin and Java code.
Please use classes from
java.time and not
Please select, or create, appropriate exception types rather than throwing overly general things such as
Exception types you create should extend
RuntimeException (directly or indirectly).
Please try to include descriptive information in exception messages, especially for errors that will be surfaced to the user.
kork-exceptions includes some standard base exception types that you are encouraged to use directly or extend as needed.
Deprecating old, unused or high-debt code is highly encouraged!
When deprecating code, you MUST include the
@Deprecation annotation, along with supporting documentation:
Do not annotate code as deprecated without additional context. Deprecations without sufficient context will be rejected.
Refrain from using open-ended, ambiguous types, such as
These types, while flexible, make APIs unobvious, difficult to integrate with and test.
Instead, use well-defined types, or if a
Map type is truly needed, use the most constrictive contract as possible, such as
We really appreciate contributions that include tests. Thorough testing at the unit level with maybe an integration test to validate how components tie together is ideal.
Spinnaker uses Spock for testing Java and Groovy code.