ArchUnit icon indicating copy to clipboard operation
ArchUnit copied to clipboard

Support for Scala

Open tusharmath opened this issue 4 years ago • 4 comments

ArchUnit is a great project for both Kotlin and Java. It seems like scala support is very limited. Does the project intend to support Scala any time in the future?

Is it possible to update the documentation for scala usage alternatively?

tusharmath avatar Jun 06 '20 08:06 tusharmath

Sorry for answering so late. I have to admit that so far I have not had the chance to really try out ArchUnit in a big Scala project. But in the end Scala is statically typed and generates Java bytecode, so I don't see a reason, why it should not work. I finally found the time to play around a little and I didn't find it so hard to get started. For example I used ScalaTest, and the following setup

build.sbt
---
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % Test
libraryDependencies += "com.tngtech.archunit" % "archunit" % "0.15.0" % Test
SomeExample.scala
---
class SomeExample {
  def call(other: Other): Unit = {
    other.foo()
  }
}
Other.scala
---
class Other {
  def foo(): Int = 42
}
ArchitectureTest.scala
---
class ArchitectureTest extends FunSuite {

  test("SomeExample should not depend on Other") {
    val classes = new ClassFileImporter().importPackagesOf(classOf[Other])

    noClasses().that().haveSimpleName("SomeExample")
      .should().dependOnClassesThat().haveSimpleName("Other")
      .check(classes)
  }
}

And I get a reasonable test failure

Architecture Violation [Priority: MEDIUM] - Rule 'no classes that have simple name 'SomeExample' should depend on classes that have simple name 'Other'' was violated (2 times):
Method <com.tngtech.example.SomeExample.call(com.tngtech.example.Other)> calls method <com.tngtech.example.Other.foo()> in (SomeExample.scala:5)
Method <com.tngtech.example.SomeExample.call(com.tngtech.example.Other)> has parameter of type <com.tngtech.example.Other> in (SomeExample.scala:0)

So I'm not exactly sure what you mean by "support Scala". What ArchUnit will probably not do in the near future (and also does not do for Kotlin), is to have language specific handling. So the terminology will be Java and the problems reported will be those of Java bytecode. But from the failure I see for this little example it seems fairly useful to me and as if it should be well possible to assert Scala architectures with this. Again, I have not used it in big industry Scala projects, so there might be some corner cases where the generated bytecode is somewhat confusing.

So maybe you could tell me what exactly is missing from your point of view. Is it another section in the user guide, similar to the little one that Kotlin has? Or do you have concrete problems with the way that ArchUnit reports violations for Scala bytecode? (I.e. so far away from the source code that it's hard to translate problems back to the actual code?)

codecholeric avatar Dec 19 '20 17:12 codecholeric

@codecholeric Scala concepts auch as packages and traits seem to be problematic. For example, traits seem to be implemented in the JVM by creating a helper class, but it appears that while ArchUnit finds the trait in classes(), checks like isAnnotatedWith or isPublic don't work as expected on it. I think(?) there's also no great way of excluding those.

Airblader avatar Sep 09 '21 10:09 Airblader

Thanks for the example! But for such idiomatic cases I think it would be necessary to create something like ArchUnit-Scala with some specific handling :thinking: It might be possible to jump from one class to the other for specific well known cases to restore the same behavior, but I don't think we can cover all such special cases that a compiler of a different language can create in the core :thinking: (if we don't want to end up in hell :joy:) Anyway, my problem is that my own Scala knowledge is fairly limited :disappointed: So I don't think I can really tackle these things, be it docs or special handling of Scala idiomatics (if I should end up in a Scala project in the future things might turn 180 degrees, but so far it's Kotlin and Groovy :joy:) I'm happy to support anybody willing to invest some energy into this though! So if anyone motivated with Scala knowledge should want to jump in feel free to ping me!

codecholeric avatar Oct 28 '21 17:10 codecholeric

The generated class files also depend heavily on the Scala compiler version and the JVM target version. For example, traits were compiled to abstract classes and are now compiled to interfaces (since Java/JVM now supports default methods in interfaces). I think the fact that different Scala versions generate different bytecode is an additional difficulty. But in Principle with the byte code generated by Kotlin, the problem should also exist, but probably less strong, since the differences are not quite so large and Kotlin arose later.

frankbe avatar May 27 '22 19:05 frankbe