Domain Driven Design Ktlint-rules
Waived Violation When There Is Only One Argument
Do.

package some.packages

@Action
class MyAction {

  fun someAssertion(b: Boolean) {
  }

}
                
Violation
Don't.

package some.packages

@Action
class MyAction {

  fun someMethod(i: Int, b: Boolean) {
  }

}
                
Violation With Only One Primitive Argument
Don't.

package some.packages

@Action
class MyAction {

  fun someMethod(paymentMean: PaymentMean, b: Boolean) {
  }

}
                
Violation With Only One Nullable Primitive Argument
Don't.

package some.packages

@Action
class MyAction {

  fun someMethod(paymentMean: PaymentMean, b: Boolean?) {
  }

}
                
No Violation
Do.

package some.packages

@Action
class MyAction {

  fun someMethod(paymentMean: PaymentMean, billingInfo: BillingInfo) {
  }

}
                

Violation Action
Don't.

package some.packages.infra

@Action
class MyAction {

  fun someMethod() {
  }
}
                
Violation Domain Service
Don't.

package some.packages.infra

@DomainService
class MyDomainService {

  fun someMethod() {
  }
}
                
Violation Repository
Don't.

package some.packages.action

@Repository
class MyRepository {

  fun someMethod() {
  }
}
                
Violation Gateway
Don't.

package some.packages.action

@Gateway
class MyGateway {

  fun someMethod() {
  }
}
                
Violation Component
Don't.

package some.packages.action

@Component
class MyComponent {

  fun someMethod() {
  }
}
                
No Violation Component
Do.

package some.packages.infra.gateways.myservice

@Component
class MyComponent {

  fun someMethod() {
  }
}
                
No Violation Action
Do.

package some.packages.actions

@Action
class MyAction {

  fun someMethod() {
  }
}
                
No Violation When No Package
Do.


class MyClass {

  fun someMethod() {
  }
}
                

Violation
Don't.

package some.packages

@Action
class MyAction {

  fun someMethod() {
    for (i in 0..10){
      println("Hello World")
    }
  }
}
                
Nested While
Don't.

package some.packages

@Action
class MyAction {
  private var hello = true

  fun someMethod() {
    if (hello){
      var i = 0
      while (i < 10){
        println("Hello World")
        i++
      }
    }
  }
}
                
No Violation
Do.

package some.packages

data class Traveler(val id: Int)

fun List<Traveler>.tookApart(toDo: (Traveler) -> Unit) = this.map { toDo(it) }

@Action
class MyAction {
  private var hello = true

  fun someMethod(theTravelers : List<Traveler>) {
    theTravelers.tookApart { println ("Hello " + it) }
  }
}
                

Violation
Don't.

package some.packages

import org.springframework.web.client.RestTemplate

@Action
class MyAction {

  fun someMethod() {
    val template = RestTemplate()
    val template2 = org.springframework.data.mongodb.core.MongoTemplate()
  }
}
                
Violation In Domain Service
Don't.

package some.packages

import org.springframework.web.client.RestTemplate

@DomainService
class MyDomainService {

  fun someMethod() {
    val template = RestTemplate()
    val template2 = org.springframework.data.mongodb.core.MongoTemplate()
  }
}
                
No Violation
Do.

package some.packages

@DomainService
class MyAction {

  private val userProfileReader: UserProfileReader

  fun someMethod(val id: Int) {
    val userProfile = userProfileReader.read(id)
  }
}
                
No Violation In Gateway
Do.

package some.packages

import org.springframework.web.client.RestTemplate

@Gateway
class MyGateway {

  fun someMethod() {
    val template = RestTemplate()
    val template2 = org.springframework.data.mongodb.core.MongoTemplate()
  }
}
                

Violation
Don't.

package some.packages

fun someMethod() {
  var i
  for (i in 0..10){
    if (i == 2) continue
    println (i + " (skipping 3)")
    if (i == 4) break
  }
}
                

Violation
Don't.

package some.packages

@ForeignModel
data class A(val i: Int)

data class B(val j: Int)

@ForeignModel
data class C(val k: Int)

data class D(val l: Int)

                
No Violation
Do.

package some.packages

@ForeignModel
data class A(val i: Int)

@ValueType
data class B(val j: Int)

@ForeignModel
data class C(val k: Int)
                

No Violation With Foreign Model
Do.

package some.packages

@Entity
@ForeignModel
data class Account(var id: ObjectId, var firstName: String, var lastName: String)

                
Violation
Don't.

package some.packages

@Entity
data class Account(var id: ObjectId, var firstName: String, var lastName: String)

                

Violation1
Don't.

package some.packages

@Action
class MyAction1 {
}

@Action
class MyAction2 {
   val action1: MyAction1
}


                
Violation2
Don't.

package some.packages

@Action
class MyAction1 {
  val myAction2: MyAction2
}

@Action
class MyAction2 {
}


                

Violation
Don't.

package some.packages
class MyClass {
  private var myFieldOne: Int
  private var myFieldTwo: String
  private var myFieldThree: Boolean
}
                
Violation While Cheating On The Parent Class
Don't.

package some.packages
class MyClass : Object {
  private var myFieldOne: Int
  private var myFieldTwo: String
  private var myFieldThree: Boolean
}
                

No Violation
Do.

package some.packages

@ValueType
data class MyClass (
  val myFieldOne: Int,
  val myFieldTwo: String,
  val myFieldThree: Boolean
)

                
Violation
Don't.

package some.packages

@ValueType
data class MyClass (
  val myFieldOne: Int,
  val myFieldTwo: String,
  val myFieldThree: Map<String, Any>
)

                

allowed When In Expression
Do.

package some.packages

fun someMethod() {
    val i = 0
    var below2 = false
    if (i > 0)
      below2 = if (i < 2) true else false
}
                
else If Is Allowed
Do.

package some.packages

fun someMethod() {
    val i = 0
    if (i < 0)
      println("i must be below 0")
    else if (i >= 0)
       println ("i must be equal to 0")
    
}
                
Violation
Don't.

package some.packages

fun someMethod() {
    val i = 0
    if (i <= 0) {
        if (i >= 0) {
            println ("i must be equal to 0")
        }
    }
}
                

Violation Action Role First
Don't.

package org.toilelibre.libe.domaindrivendesignktrules

import kotlin.String
import org.toilelibre.libe.domaindrivendesignktrules.A

@Action
class B {
    fun testingTheViolation(a: A) {
    }
}

@ForeignModel
data class A
                
Violation
Don't.

package org.toilelibre.libe.domaindrivendesignktrules

import kotlin.String
import org.toilelibre.libe.domaindrivendesignktrules.A

@ForeignModel
data class A

@Action
class B {
    fun testingTheViolation(a: A) {
    }
}
                
Violation In Infra
Don't.

package org.toilelibre.libe.domaindrivendesignktrules

import kotlin.String
import org.toilelibre.libe.domaindrivendesignktrules.A

@ForeignModel
data class A

@Gateway
class B {
    fun testingTheViolation(a: A) {
    }
}
                
Private Method In Infra Should Be Tolerated
Do.

package org.toilelibre.libe.domaindrivendesignktrules

import kotlin.String
import org.toilelibre.libe.domaindrivendesignktrules.A

@ForeignModel
data class A

@Gateway
class B {
    private fun testingTheViolation(a: A) {
    }
}
                
Violation With Return Type
Don't.

package org.toilelibre.libe.domaindrivendesignktrules

import org.toilelibre.libe.domaindrivendesignktrules.A

@ForeignModel
data class A(val e: Int)

@ValueType
data class C(val f: Int)

@Action
class B {
    fun testingTheViolation(): A {
      return A()
    }
}
                
Violation In Domain Service
Don't.

package org.toilelibre.libe.domaindrivendesignktrules

import kotlin.String
import org.toilelibre.libe.domaindrivendesignktrules.A

@ForeignModel
data class A

@DomainService
class B {
    fun testingTheViolation(a: A) {
    }
}
                
should Not Report Anything
Do.

package some.packages.actions

import some.packages.domain.transverse.DomainDrivenDesignAnnotations.Action
import some.packages.infra.database.Storage
import org.bson.types.ObjectId

@Entity
data class Instance(val id: Int)

@Action
class GetInstanceByRowId(private val storage: Storage) {

    infix fun retrievePaymentBy(`an id`: ObjectId): Instance? = storage rowMatching `an id`
}
                

no Violation If Action Invocation Inside Nested Block
Do.

        package some.packages.infra.endpoint

        import some.packages.actions.HandleVerifyRequest
        
        @Action
        class HandleVerifyRequest {
            fun with(verifyOperationRequest: VerifyOperationRequest){
            }
        }

        @Controller
        class TheController(val handleVerifyRequest: HandleVerifyRequest) {
            fun performVerify(
                @RequestBody verifyOperationRequest: VerifyOperationRequest
            ) = runBlocking {
                handleVerifyRequest.with(verifyOperationRequest)
            }
        }
        
Violation
Don't.

package some.packages

@Action
class TheAction {
  fun doIt(){
  }
}

@Controller
class TheController {
  fun someMethod() {
    println("Hello world")
  }
}

                
violation If The Method Is AMessage Queue Listener
Don't.

package some.packages

class TheController {
  @RabbitListener
  fun someMethod() {
    println("Hello world")
  }
}

                
no Violation If The Method Is Just An Internal Event Listener
Do.

package some.packages

class TheController {
  @EventListener
  fun someMethod() {
    println("Hello world")
  }
}

                

Violation
Don't.

package some.packages


fun someMethod() {
 try {
   println("Hello World")
 } catch (e: Exception){
 }
}
                

Violation
Don't.

package some.packages

@Repository
class MyRepository(var dataSource: DataSource, private var jdbcUrl: String, val password: String){

  fun find(id: ObjectId){ // this should be allowed
    var ref = id.toString() // this should be allowed
    return dataSource.findOne(ref)
  }

}

                
No Violation For Data Classes
Do.

package some.packages

@Entity
@ForeignModel
data class Account(val id: ObjectId, val firstName: String, val lastName: String)

                
No Violation For Non Var And Non Val Parameters
Do.

package some.packages

class Tester(id: ObjectId) {
  fun isValid(){
    return true
  }
}

                
No Violation For Overriden Value Parameters
Do.

package some.packages

class Tester(override var id: ObjectId) {
  fun isValid(){
    return true
  }
}

                

Violation
Don't.

package some.packages

@Action
class MyAction {

  fun doIt(){
    this.doItBetter()
  }

  private fun doItBetter(){
  }

  fun doItAgain(){
    this.doItAgainBetter()
  }

  private fun doItAgainBetter(){
  }

}

                
No Violation
Do.

package some.packages

@Action
class MyAction {

  fun doIt(){
  }

}
                

integration Test In Test
Do.

package com.egencia.service.infra.test1

import com.egencia.service.infra.test1.Test1
import com.egencia.service.infra.test2.Test2

@DomainService
class HelloIT
                
In Test
Do.

package com.egencia.service.infra.test1

import com.egencia.service.infra.test1.Test1
import com.egencia.service.infra.test2.Test2

@DomainService
class MyTest
                
Outside Infra
Do.

package com.egencia.service.domain.ktlintrules

import com.egencia.service.infra.test1.Test1
import com.egencia.service.infra.test2.Test2

@DomainService
class Hello
                
No Violation In Infra
Do.

package com.egencia.service.infra.test1

import com.egencia.service.infra.test1.Test1
import com.egencia.service.infra.test1.Test11

@Gateway
class Hello
                
No Violation For Spring Config
Do.

package com.egencia.service.infra.test1

import com.egencia.service.infra.test1.Test1
import com.egencia.service.infra.test2.Test2

@Configuration
class TestConfiguration
                
Violation In Infra
Don't.

package com.egencia.service.infra.test1

import com.egencia.service.infra.test1.Test1
import com.egencia.service.infra.test2.Test2

@Gateway
class Hello
                

No Violation
Do.

package some.packages

@ValueType
data class Currency {
  fun rate(olderCurrency: Currency): Float {
     return CURRENCY_TABLE[olderCurrency]
  }
}

@ValueType
data class Price (
  val currency: Currency,
  val amount: Float,
) {
  fun toCurrency(newCurrency: Currency): Float {
    return newCurrency.rate(currency) * amount
  }
}

                
No Violation When The Function Uses AClass Member
Do.

package some.packages

@ValueType
data class Currency(val name: String, val currencyTable: Map<String, Float>)

class PriceConverter(val currencyHelper: CurrencyHelper) {
  fun getRate(newCurrency: Currency): Float {
    return currencyHelper.extractRateFromCurrencyTable(currency.name, newCurrency.name)
  }
}

                
No Violation When The Function Uses AComponent
Do.

package com.company.service.test.infra.gateways.configservice

import com.company.library.configuration.configservice.resolver.ConfigurationResolver
import com.company.library.configuration.configservice.resolver.ResolverParams
import com.company.service.test.infra.gateways.configservice.ProductAndTravelerReferences
import com.company.service.test.domain.transverse.DomainDrivenDesignAnnotations.Gateway

@ValueType
data class ProductAndTravelerReferences(pointOfSale: PointOfSale, company: Company, productsAndTravelersMapping: List<Mapping>)

@Gateway
class ArrangerCardsToggler(private val config: ConfigurationResolver) {

    infix fun displayOrHideArrangerCardsAccordingTo(theInput: ProductAndTravelerReferences): Boolean =
        theInput.productsAndTravelersMapping.any {
            val params = ResolverParams()
                .withProductId(theInput.pointOfSale.code)
                .withCompanyId(theInput.company.id.value)
                .withStripe("lineOfBusiness", it.designation.lineOfBusiness.name)
            config.resolve("arrangerCreditCardAllowed", params) as String? == "true" &&
                config.resolve("arrangercc", params) as String? == "1"
        }
}
                
No Violation When The Function Uses AReceived Type
Do.

    package com.company.service.test.domain.booking

    import com.company.service.test.domain.payment.Instance
    import com.company.service.test.domain.payment.search.RetrievePayment
    import com.company.service.test.domain.transverse.DomainDrivenDesignAnnotations.DomainService
    import org.slf4j.LoggerFactory
    
    @ValueType
    data class Booking(val id: String?, val bookingContext: BookingContext?, val traveler: Traveler) {
      val rightOriginalBookingPaymentInstanceId get() = id
      val hasProvidedAnOriginalBookingPaymentInstance get() = id != 0
    }

    @DomainService
    class RetrieveOriginalBookingPaymentInstance(private val retrieveOriginalPayment: RetrievePayment) {

        fun fromThe(booking: Booking) =
            if (booking.hasProvidedAnOriginalBookingPaymentInstance)
                retrieveOriginalPayment byIdFromThe booking
                    ?: retrieveOriginalPayment byLookingToHistoryFromThe booking
            else null

        companion object {
            private val LOGGER = LoggerFactory.getLogger(RetrieveOriginalBookingPaymentInstance::class.java)

            private infix fun RetrievePayment.byIdFromThe(booking: Booking) =
                by(listOf(booking.rightOriginalBookingPaymentInstanceId!!))
                    .firstOrNull()
                    .takeIf { it?.bookingContext?.userId == booking.traveler.userId }
        }
    }
                
No Violation When The Function Uses AClass Function
Do.

package some.packages

@ValueType
data class Currency(val name: String, val currencyTable: Map<String, Float>)

class PriceConverter(val currencyHelper: CurrencyHelper) {
  fun getRate(newCurrency: Currency): Float {
    return this.delegateToCurrencyHelper(newCurrency)
  }

  private fun delegateToCurrencyHelper(newCurrency: Currency) {
    return currencyHelper.extractRateFromCurrencyTable(currency.name, newCurrency.name)
  }
}

                
No Violation When The Function Is An Exception Handler
Do.

package some.packages

@ValueType
data class ProductNotAvailableException(val name: String): RuntimeException

@ControllerAdvice
class ExceptionHandler() {
  @ExceptionHandler(ProductNotAvailableException::class)
  @ResponseStatus(value = HttpStatus.BAD_REQUEST)
  @ResponseBody
  fun handleAProductNotAvailableException(productNotAvailableException: ProductNotAvailableException): ErrorNode {
        LOGGER.error(ex.message, ex)
        return ErrorNode(name = productNotAvailableException.name, errorDescription = productNotAvailableException.message)
    }
}

                
Violation
Don't.

package some.packages

@ValueType
data class Currency(val name: String, val currencyTable: Map<String, Float>)

class PriceConverter {
  fun getRate(newCurrency: Currency): Float {
    return newCurrency.currencyTable[currency.name]
  }
}

                

Violation
Don't.

package some.packages

import org.springframework.web.client.RestTemplate

@Gateway
class MyGateway {

  private val restTemplate1: RestTemplate
  private val restTemplate2: RestTemplate

}
                
Multiple Kinds Violation
Don't.

package some.packages

import org.springframework.web.client.RestTemplate
import org.springframework.data.mongodb.core.MongoTemplate

@Gateway
class MyGateway {

  private val restTemplate: RestTemplate
  private val mongoTemplate: MongoTemplate

}
                
Repository Violation
Don't.

package some.packages

import org.springframework.web.client.RestTemplate
import org.springframework.data.mongodb.core.MongoTemplate

@Repository
class MyRepository {

  private val restTemplate: RestTemplate
  private val mongoTemplate: MongoTemplate

}
                
No Violation
Do.

package some.packages

import org.springframework.web.client.RestTemplate
import org.springframework.data.mongodb.core.MongoTemplate

@Repository
class MyRepository {

  private val mongoTemplate: MongoTemplate

}
                
Repository No Violation
Do.

package some.packages

import org.springframework.web.client.RestTemplate
import org.springframework.data.mongodb.core.MongoTemplate

@Repository
class MyRepository {

  private val mongoTemplate: MongoTemplate

}
                

No Violation
Do.

package some.packages

@ValueType
data class Price (
  val currency: Currency,
  val amount: Float,
) {
  fun toCurrency(newCurrency: Currency): Float {
    return Currency.rate(currency, newCurrency) * amount
  }
}

                
Violation In Constructor
Don't.

package some.packages

@ValueType
data class Price (
  @Inject
  val currencyConverter: CurrencyConverter,
  val amount: Float,
) {
  fun toCurrency(newCurrency: Currency): Float {
    return currencyConverter.rate(currency, newCurrency) * amount
  }
}

                
Violation In Getter
Don't.

package some.packages

@ValueType
data class USDPrice (
  val amount: Float,
) {
  fun getInEuros(@Autowired currencyConverter: CurrencyConverter): Float {
    return currencyConverter.rate("USD", "EUR") * amount
  }
}