This document discusses moving from UML modeling to using Scala macros to define a domain-specific language (DSL) for modeling database entities and queries. It describes issues with UML like lack of efficiency and impedance mismatch. Scala macros allow defining a DSL that is compiled into type-checked code and avoids runtime overhead. An example DSL defines entities, relationships, constraints and generates corresponding Slick code. The implementation uses both dynamic and macro features to allow type-checked queries defined at the call site. The DSL approach reduced code and improved delivery time over the UML-based workflow.
2. Summary
• What this talk is about ?
o
Why did we choose UML ?
o Why did we move from UML to DSL
o Our experience in designing a DSL on top of Slick using
Scala macros.
• The macro-based DSL on top of Slick
• Implementation
o
How macros work
o @Model annotation-macro
o Dynamic methods statically compiled
4. Why UML ?
• Encapsulation
o Hide implementation details and expose relevant
abstractions only
• Communication
o Product owner and dev team understand each other
• Quality
o Boilerplate code is generated with respect to the
architect guidelines. Dev team focus on business
rules
5. Why not UML ?
• Lack of efficiency
o
Any modification require code regeneration
UML to XMI
(20 % - more or less)
XMI to code
(78% - more or more)
Code to bytecode
(2% - much less)
o Excessive generation time
Code is regenerated for all model entities regardless of
whether they were modified
o Almost inexistent (real life) collaborative capabilities
Always locked model syndrome
Anyone tried to merge UML models on a regular basis ?
• Impedance mismatch
o
Not all concepts are easily represented in UML
7. Why not Scala macros ?
• DSL design is complex
o We are used to apply existing patterns
o Are we used to design grammars ?
• Difficult to develop and maintain
o Development at the meta-level
o Hey, we’re working on the AST
9. The DSL Goal
• Allow the product owner and the developer
o to share info about the static representation of the
system (The database model in our case)
• The product owner should be able to read it
• The developer should be able to compile it
10. The good old architecture
http://www.mywebsite.com
Controller
Controller
Service
Service
DAO
DAO
Model
Model
Model
Persistence
Persistence
layer
layer
11. Why Slick as the persistence framework
• Why Slick as a persistence framework
o Because it ’s not an ORM so we’ve got
DBA is happy : No more huge SQL requests that
makes SQL auditing difficult
Network is happy : No unnecessary round trip
Webserver is happy : no more objects to proxify
€€€ When the customer is happy my boss is
happy too
12. Why Slick as the persistence framework
• What we lost of columns to update
o Automatic detection
Who cares ?
•
Unit of I/O defaults to 8K for Postgres, Oracle, SQLServer …
So for most cases (to say the least), updating the whole object
has no real impact on performance
o Automatic inserts of dependent objects
Our use case focus is on scalable OLTP applications
Is it really an issue in OLTP ?
•
•
Do we really want the framework to guess what we’re doing ?
Does it justify the overhead ?
•
•
•
We’ve got actors
We’ve got transactions
We’ve got joins
We’ve got to rethink our persistence patterns
13. A Slick-macros example
Timestamp all rows
Timestamp all rows
1..1 relationship
1..1 relationship
0..1 relationship
0..1 relationship
Embedded value
Embedded value
Constraints
Constraints
*..* relationship
*..* relationship
25. Simplify Querying
• Simplify update
o Instead of this
o Write this
def macro
def macro
Argument names and types are known at call site only
Argument names and types are known at call site only
and still this code remains typechecked at compile time
and still this code remains typechecked at compile time
27. A mix of Dynamic and Scala-macros
• First the Slick Query object gets the Dynamic
•
trait
Since arguments are all named we define the
applyDynamicNamed method as a macro
o Def macros are applied at call site, we can thus
typecheck at call site against the prefix object.
28. Conclusion
• As a developer
o It was almost
A copy/paste task and AST node substitution
o Made easier using the quasiquote feature
• As a user
o Much less code to maintain
o Reduced time to deliver
o No runtime overhead
Encapsulation : c’est plus pratique qu’un fichier HBM
tuyauterie
Les points faibles
Productivit »
Faiblesse dans l’’expressivté de certains concepts conduit à multiplier les stéréotypes
Vu que pour toutt I/O de moins de 8K, le sgbd écrit 8K alors updater 1k ou 8k revient au même
Si tu ajoutes un adresse à une personne
Quand tu persisteras la personne alors hibernate persistera aussi l’adresse
() === Company.apply() qui renvoie en fait un objet Query de Slick
On ne connaît aps le type des paramètres à la définition de la fonction ni le nom des paramètres puisqu’il dépendent du contexte d’appel cad de la table sur laquelle on est entrain de faire l’update et
Les colones qu’on veut mettre à jour.
Dans le doupdate on aura toujours des name = bvlue en paramètre
Donc dans le cas de Dynamic, c la méthode applyDyn… qui est appelée quand les paramètres sont nommés