ORMs have been accepted as the standard solution for database access in the Java enterprise world for a long time. Like other patterns in Java enterprise programming they are based on a traditional model of object-oriented programming with object identity, mutable state, behavior and encapsulation. In practice, this leads to two problems:
This programming model is inherently imperative, unlike the declarative languages used for database access which describe the constraints on the data that should be queried but leave the execution strategy up to the database engine. It is practically impossible to predict the data access patterns in an imperative, mutable-state-based application in an automated way so that a minimum number of efficient database queries could be generated, thus leading to the biggest part of the well-known “impedance mismatch” of ORMs. The usual work-around consists of annotating the data model with hints for fetching certain data, or writing performance-critical queries explicitly, thus foregoing the convenience of the imperative data mapping.
In recent years, however, the traditional object-oriented programming model itself has come under attack. As CPUs are gaining more and more cores and the performance of the individual cores is not increasing by much, multi-threaded programming has become a requirement for scalable applications but this is very difficult to do in imperative programming with mutable state.
The solution has been known for a long time: functional programming. Taken to its extremes, it completely eschews mutable state, object identity and eager evaluation. Much like in a database query language, you only state what data you need, but not when or in what order it should be computed. A more pragmatic solution is provided by languages like Scala which gives you the power of abstraction from both object-oriented and functional programming and avoids mutable state in many cases but still allows you to use it when you want.
This new approach to programming also requires a new way of thinking about database access. Instead of object-relational mapping we need something akin to functional-relational mapping that allows us to compose database queries the same way we can compose functions, and then materialize the data in the form of immutable objects in the application. This is the approach taken by Slick, Typesafe’s database library for Scala, which treats database tables like Scala collections and compiles queries to a single SQL statement. This is only possible by using a host language as powerful as Scala which is well suited to building expressive DSLs that can be verified at type-checking time.
Stefan Zeiger is a Senior Software Engineer at Typesafe and the tech lead for Slick, the Scala database library