37

I'm wondering if I can switch from Java to Scala in a Spring + Hibernate project to take advantage of some Scala features such as pattern matching, Option and what it seems to me a cleaner syntax in general. I've been looking for the ORM by default in the Scala ecosystem and I've found thinks like Activate (but mostly I try to find if Hibernate can be used with Scala). Searching for this I've read this in the Play documentation about JPA + Scala.

But the most important point is: do you really need a Relationnal to Objects mapper when you have the power of a functional language? Probably not. JPA is a convenient way to abstract the Java’s lack of power in data transformation, but it really feels wrong when you start to use it from Scala.

I don't have a deep understanding of how to use functional programming to create a complete application (that's why I intend to use Scala so that I can understand this incrementally, since it combines OO + Functional), so I can't figure out why I would not need an ORM with a functional language and what would be the functional approach to tackling persistence of the domain model.

A DDD approach for the business logic still makes sense with Scala, doesn't it?

Andres F.
  • 5,119
  • 2
  • 29
  • 41
gabrielgiussi
  • 1,326
  • 1
  • 11
  • 10
  • 3
    This is an opinion-based question. Scala is not purely functional, it is also an OO language, so that would explain why you'd still want to use an ORM tool. For DB mapping, see for example: [Slick](http://slick.typesafe.com/), [SORM](http://sorm-framework.org/), [Anorm](https://www.playframework.com/documentation/2.0/ScalaAnorm). – Jesper Nov 25 '15 at 13:35
  • I'm not looking for an opinion, I'm asking to something with deep understanding of the functional paradigm what is the way of achieve persistence. I know that Scala is a hybrid and I want to use its OO part for DDD. So you say that if I take an DDD approach even with Scala, an ORM is the way to go? – gabrielgiussi Nov 25 '15 at 14:28
  • In functional languages you mainly deal with values which don't have identity as objects do. Therefore you don't need change-tracking which is one of the main jobs of an ORM. – Lee Nov 25 '15 at 15:49
  • 2
    You might like this talk: [From Functional to Reactive - Patterns in Domain Modeling](https://www.youtube.com/watch?v=TiwNrioZoTo) – Jesper Nov 25 '15 at 20:58
  • A word of warning: if you try to use Hibernate or any other invasive ORM which "takes over" your collections, you're in for a world of hurt in Scala. I strongly suggest you look for alternatives (either ditch Hibernate or Scala...). My own personal preference favors using Scala and ditching Hibernate, but be aware this is not a trivial change. – Andres F. Nov 26 '15 at 15:01
  • 5
    You don't *need* an ORM in *any* major language. – GrandmasterB Nov 27 '15 at 22:33
  • You can definitely use Hibernate from Scala. For example, see this Stack Overflow post: http://stackoverflow.com/questions/11215621/how-to-effectively-use-scala-in-a-spring-mvc-project/11218385#11218385. There are number of other Stack Overflow questions that cover the topic. – sourcedelica Nov 28 '15 at 01:28
  • @ericacm You technically *can*, but you shouldn't. The class in the accepted answer you linked to is an abomination. That's not idiomatic Scala code, it's wasteful, and shouldn't be done unless using Hibernate was mandatory in your project... at which point you should really reconsider whether Scala is right for you. Please don't recommend this kind of code as if it was acceptable Scala :/ – Andres F. Nov 28 '15 at 18:41
  • This person and the person from the question I linked wanted to know if you can use Hibernate in Scala. Sometimes Hibernate is a requirement for a project and you can't just wish it away. If this is the case then it's straightforward to use it. Unfortunately you can't use idiomatic Scala with Hibernate because that's not how it works (it's based on mutable objects). – sourcedelica Nov 29 '15 at 06:28
  • If you think that code is an abomination, please show how you would write Hibernate code in Scala. – sourcedelica Nov 29 '15 at 06:35
  • @sourcedelica As I said, if using Hibernate is a requirement, then Scala is no good for you (and in my experience, it's *never* a requirement to use *both* Hibernate *and* Scala). Writing unidiomatic Scala is *always the wrong choice*. I wouldn't write Hibernate code in Scala, because it's the wrong fit -- there is no "right" way to do it. Are you familiar with the phrase "using the right tool for the job"? – Andres F. Nov 29 '15 at 14:43

4 Answers4

38

Well, one thing that's important to do whenever we have a discussion like this is to clearly distinguish between object relational mappers ("ORM") and database abstraction layers. An ORM is a kind of database abstraction layer, but not all database abstraction layers are ORMs. One good tool to study to grasp this is Python's popular SQLAlchemy library, which bills itself as a "SQL toolkit and Object Relational Mapper" (my boldface), with the idea that these are different things. As they put it in their key features page:

No ORM Required

SQLAlchemy consists of two distinct components, known as the Core and the ORM. The Core is itself a fully featured SQL abstraction toolkit, providing a smooth layer of abstraction over a wide variety of DBAPI implementations and behaviors, as well as a SQL Expression Language which allows expression of the SQL language via generative Python expressions. A schema representation system that can both emit DDL statements as well as introspect existing schemas, and a type system that allows any mapping of Python types to database types, rounds out the system. The Object Relational Mapper is then an optional package which builds upon the Core.

The front page describes the ORM like this:

SQLAlchemy is most famous for its object-relational mapper (ORM), an optional component that provides the data mapper pattern, where classes can be mapped to the database in open ended, multiple ways - allowing the object model and database schema to develop in a cleanly decoupled way from the beginning.

The key idea of an ORM is to try and bridge the famous object-relational impedance mismatch. This means defining relationships between user-defined classes to tables in a database schema and providing automatic "save" and "load" operations for your application's classes.

In contrast, non-ORM database abstraction layers tend to be more committed to the relational data model and to SQL, and not at all to object-orientation. So instead of featuring "mappings" between tables and classes and hiding the database schema from the programmer, they tend to expose the database to the programmer but with better APIs and abstractions. For example, SQL query builders allow you to generate complex SQL queries programmatically, without string manipulation, like this (an example from the jOOQ library for Java):

// Typesafely execute the SQL statement directly with jOOQ
Result<Record3<String, String, String>> result =
    create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
          .from(BOOK)
          .join(AUTHOR)
          .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID))
          .where(BOOK.PUBLISHED_IN.equal(1948))
          .fetch();

Now, the Play framework doesn't seem to be 100% in league with what I just described, but their argument seems to be in this general space: work with the relational model directly instead of translating it to classes and back from them.

The jOOQ library is worth studying as a counterpoint to ORMs. They also have some relevant blog entries that are worth a read:

sacundim
  • 4,748
  • 1
  • 19
  • 16
24

It's kind of hard to explain until you've done a lot of functional programming. In object-oriented programming, your data is sort of stuck in one object and stays there. That object gets passed around a bit, and modified quite a bit, but you're usually fundamentally working with the same "identity" over the lifetime of that data.

ORMs are generally designed around that paradigm. You retrieve some data from the database, munge it into an object, potentially modify it a bunch, and when you're done, you still have the same object you can write back to the database.

Functional programming works differently. Your data doesn't maintain a single identity over its lifetime. It gets split up, copied, shared, and transformed. It sort of flows through a bunch of functions, then eventually gets reassembled into the output form you need. For any database API to feel natural in a functional language, it has to take that into account, and JPA doesn't.

Karl Bielefeldt
  • 146,727
  • 38
  • 279
  • 479
  • 3
    +1000 People who insist on using Scala as if it were Java++ make me afraid for the future of the language :( – Andres F. Nov 29 '15 at 14:51
13

In scala it is still useful to map database tables to objects, and there are several ways of doing it.

One popular framework in the world of Scala is slick. It is not an ORM, because it does less (namely, it doesn't fetch relationships without being told to do joins explicitly).

So you still map objects to database rows, but your objects are immutable, (hence no state-flushing) and you explicitly execute queries using a monadic DSL. The result is you get a lot of the "good" parts of an ORM without the issues around mutability, and unpredictable N+1 problems.

One should note that people have gotten great success using much thinner libraries, like anorm or straight JDBC too, using functional techniques to keep code beautiful.

One fantastic library that applies functional techniques on top of JDBC is also doobie.

So you have a lot of choices for database access, but Hibernate (which seems to be the de-facto ORM) isn't one of the best ones, due being biased towards mutability.

triggerNZ
  • 231
  • 1
  • 4
1

You don't need an ORM even in Object-oriented languages.

First, who said that your data should physically be copied from your persistent storage to your object? Alan Kay, a man behind Smalltalk, wanted objects to get rid of data. He suggested that an object can have only a reference to some area where its data is stored.

Second -- what's the best way to achieve that? I recommend identify your objects by their responsibilities, and not to think about data they possess. If you've heard about CRC cards approach, it's used exactly for that.

And, finally, just in case you'll ever return to OO-field, here is a way to implement it.

Vadim Samokhin
  • 2,158
  • 1
  • 12
  • 17