DataWeave 2.0
Improving Readability and Performance
Joshua Erney
● Mountain State Software Solutions
● www.jerney.io
● www.linkedin.com/in/jerney
● @jerney_io
Agenda
1. Introduction
2. What is DataWeave?
3. Expressions vs Statements
4. Problems with Expressions
5. Solution?
About Me
🎉MuleSoft Ambassador
📝Blog at www.jerney.io
❤DataWeave
👨‍💻Working at Mountain State Software Solutions (MS3
) in the MuleSoft/Integration space for ~3 years
About this talk
● Expressions vs Statements
● Exploring the good and bad that come with expression-heavy langs like DW
● Keeping the good, eliminating the bad by leveraging DW 2.0 features
● Real world use case
What is DataWeave?
● Domain-specific Language created specifically to assist with data transformations regardless of
source and target formats
● Fully-fledged programming language
● Adheres to the core tenets of functional programming
○ One of these tenets is: Expressions over statements
Expressions vs Statements
(Almost) Everything is an Expression
Most FP programs are made up of expressions.
● An expression is something that evaluates to a value, e.g, 2 + 2
● A statement is more like a command, and represents an action, e.g.,
System.out.print(“Hello, World!);or list.add(1);
● Expressions return values, statements do not.
(Almost) Everything is an Expression (cont.)
Expressions and statements generally serve different purposes:
● Statements are great for executing commands like printing, getting and setting values from objects,
and I/O operations.
● Expressions are great for doing calculations and transformations. Expressions also tend to make
our code more concise and declarative.
● Expressions can always be substituted with the value they return (💪)
(Almost) Everything is an Expression (cont.)
Java Statements
boolean even = true;
int x = 0;
if(even) {
x = 2;
} else {
x = 1;
}
DataWeave Expressions
var even = true
var x = if (even) 2 else 1
This returns
This does not return
Expression Problems
Having primarily expressions to work with presents its own set of problems. If we organize code into
small, flexible functions, we end up with heavily nested function calls:
thenFinallyDoThis(thenDoThis(doThis(x)))
Expression Problems
Expression Problems (Cont.)
We might think to solve the right-to-left problem by breaking the function calls out into multiple lines:
thenFinallyDoThis(
thenDoThis(
doThis(x)))
How can we fix this problem?
One Solution: Operators
Operators allow us to put arguments on both the left and right hand side of the function.
map, filter, and reducegive us this kind of convenience. When you format them a certain way, the
flow becomes obvious:
// Add one to each
arr map (n) -> n + 1
// Then filter out the odds
filter (n) -> isEven(n)
// Then sum the array
reduce $$ + $
Shortcomings of Operators
1. More complicated lambdas do not lend themselves to organizing code in the more friendly format:
// Add one to each, filter out odds, then sum
arr map (v) -> {
“type” : “integer”,
“n” : v.n + 1,
“time” : now()
} filter (v) -> isEven(v.n)
reduce (v, total=n) n + v.n
Shortcomings of Operators (Cont.)
1. More complicated lambdas do not lend themselves to organizing our code in the more friendly
format.
2. Operators force us to have a deeper understanding of operator precedence. Which evaluates first?
arr map (v) -> v + 1 filter (v) -> isEven(v) reduce $$ + $
Is this even valid code?
Nope
Scripting language error on expression '%dw 2.0
output application/java
var arr = [1,2,3,4]
---
arr map (v) -> v + 1...'. Reason: Expecting Type: `Array<T>`, but got: `Number`.
Function: `filter(items: `Array<T>`, criteria: (item: `T`, index: `Number`) -> `Boolean`) -> `Array<T>``
Actual : `filter(items: `Number`, criteria: (v, $$) -> `?`)`.
Shortcomings of Operators (Cont.)
1. More complicated lambdas do not lend themselves to organizing our code in the more friendly
format.
2. Operators force us to have a deeper understanding of operator precedence. Which evaluates first?
arr map ((v) -> v + 1) filter ((v) -> isEven(v)) reduce $$ + $
Need to wrap the first two lambdas in parenthesis so DW knows when the lambda body closes.
Shortcomings of Operators (Cont.)
1. More complicated lambdas do not lend themselves to organizing our code in the more friendly
format.
2. Operators force us to have a deeper understand of order of operations.
3. Even if we were ok with the above, we cannot create our own operators.
What if we’re using Java?
// Java, but still very functional
finallyDoThis(thenDoThis(doThis(x)))
// It’s imperative, but we’re still
// adhering to FP tenets.
String that = doThis(x);
Int n = thenDoThis(that);
Result res = finallyDoThis(n);
Simple Solution: Declarations
Declarations (Cont.)
Declarations in DataWeave are whatever you find above the triple-dash:
%dw 2.0
output application/json // Format declaration
var n = 1 // Variable declaration
fun addOne(n) = n + 1 // Function Declaration
---
addOne(n)
Declarations (Cont.)
Use declarations to regain a Java-esque imperative style. This gives us the ability to “un-nest” our
function calls so they can be read left-to-right, top-to-bottom:
var that = doThis(payload)
var n = thenDoThis(that)
---
finallyDoThis(n)
Declarations (Cont.)
Q: Can we only place declarations above the triple-dash at the top of the DataWeave file?
Declarations (Cont.)
Q: Can we only place declarations above the triple-dash at the top of the DataWeave file?
A: No!
do Example
fun tomorrow() = do {
var today = now() // Can declare new variables
fun addOneDay(dt) = // Can declare new functions
dt + |P1D|
---
addOneDay(today) // This is what is ultimately returned
}
---
tomorrow()
Declarations
Body (what gets returned from do)
do Use Cases - Unnecessary Calculations
var arr = [1,2,3]
fun doSomething() =
arr map (n) -> {
plusOne : n + 1,
// Called sizeOf(arr) times
meta : reallyExpensiveFunc()
}
fun doSomething() = do {
// Called 1x
var val = reallyExpensiveFunc()
---
arr map (n) -> {
plusOne : n + 1,
meta : val
}
}
do Use Cases - Unnecessary Calculations
var arr = [1,2,3]
fun doSomething() =
arr map (n) -> {
plusOne : n + 1,
// Called sizeOf(arr) times
meta : reallyExpensiveFunc()
}
fun doSomething() = do {
// Called 1x
var val = reallyExpensiveFunc()
---
arr map (n) -> {
plusOne : n + 1,
meta : val
}
}
do Use Cases - Extract repetitive functionality
fun between(dateStr, start, end) =
(dateStr
as Date {format: “MM/dd/yyyy”})
> start
and
(dateStr
as Date {format: “MM/dd/yyyy”})
< end
fun doSomething() = do {
var date = dateStr
as Date {format: “MM/dd/yyyy”}
---
date > start and date < end
}
do Use Cases - Extract repetitive functionality
fun between(dateStr, start, end) =
(dateStr
as Date {format: “MM/dd/yyyy”})
> start
and
(dateStr
as Date {format: “MM/dd/yyyy”})
< end
fun doSomething() = do {
var date = dateStr
as Date {format: “MM/dd/yyyy”}
---
date > start and date < end
}
do - A Real World Example
Determine amount owed from an Array of amounts. Each item in the Array will be like the following:
[
{
“Account” : “jerney.io”,
“Type” : “Debit”,
“Amount” : 123.10,
“Date” : “1/1/2019”
}, ...
]
A Real World Example: Business Logic
Accumulate the total Amount owed for each Account.
● If the Date field is in the past, add 10% to the Amount.
● If the Type is “Credit” subtract the modified Amount from the total,
● If the Type is “Debit” add the modified Amount to the total.
A Real World Example: First Take
A Real World Example: First Take (cont.)
Use var to name this
Eliminate
this
duplication
Second Take
Second Take (Cont.)
Should be its own function
Third Take
Third Take (Cont.)
This is called for every item in the Array, but we only need to call it once
Final Version
Final Thoughts
● Expression-heavy languages are a double-edged sword
○ Great for conciseness and reasoning about a problem
○ Expressions without declarations kill readability and punish us for writing small, reusable functions
● Use declarations and do statements (expressions) to write:
○ Code that is easier to understand
○ Code that is more performant
○ Code that is easier to develop
Get the code here: https://github.com/jerneyio/connect19presentation
Questions?
Come “Ask me Anything”!
● Tomorrow
● Community Booth
● 10:30am to 11:15am

DataWeave 2.0 - MuleSoft CONNECT 2019

  • 1.
    DataWeave 2.0 Improving Readabilityand Performance Joshua Erney ● Mountain State Software Solutions ● www.jerney.io ● www.linkedin.com/in/jerney ● @jerney_io
  • 2.
    Agenda 1. Introduction 2. Whatis DataWeave? 3. Expressions vs Statements 4. Problems with Expressions 5. Solution?
  • 3.
    About Me 🎉MuleSoft Ambassador 📝Blogat www.jerney.io ❤DataWeave 👨‍💻Working at Mountain State Software Solutions (MS3 ) in the MuleSoft/Integration space for ~3 years
  • 4.
    About this talk ●Expressions vs Statements ● Exploring the good and bad that come with expression-heavy langs like DW ● Keeping the good, eliminating the bad by leveraging DW 2.0 features ● Real world use case
  • 5.
    What is DataWeave? ●Domain-specific Language created specifically to assist with data transformations regardless of source and target formats ● Fully-fledged programming language ● Adheres to the core tenets of functional programming ○ One of these tenets is: Expressions over statements
  • 6.
  • 7.
    (Almost) Everything isan Expression Most FP programs are made up of expressions. ● An expression is something that evaluates to a value, e.g, 2 + 2 ● A statement is more like a command, and represents an action, e.g., System.out.print(“Hello, World!);or list.add(1); ● Expressions return values, statements do not.
  • 8.
    (Almost) Everything isan Expression (cont.) Expressions and statements generally serve different purposes: ● Statements are great for executing commands like printing, getting and setting values from objects, and I/O operations. ● Expressions are great for doing calculations and transformations. Expressions also tend to make our code more concise and declarative. ● Expressions can always be substituted with the value they return (💪)
  • 9.
    (Almost) Everything isan Expression (cont.) Java Statements boolean even = true; int x = 0; if(even) { x = 2; } else { x = 1; } DataWeave Expressions var even = true var x = if (even) 2 else 1 This returns This does not return
  • 10.
  • 11.
    Having primarily expressionsto work with presents its own set of problems. If we organize code into small, flexible functions, we end up with heavily nested function calls: thenFinallyDoThis(thenDoThis(doThis(x))) Expression Problems
  • 12.
    Expression Problems (Cont.) Wemight think to solve the right-to-left problem by breaking the function calls out into multiple lines: thenFinallyDoThis( thenDoThis( doThis(x))) How can we fix this problem?
  • 13.
    One Solution: Operators Operatorsallow us to put arguments on both the left and right hand side of the function. map, filter, and reducegive us this kind of convenience. When you format them a certain way, the flow becomes obvious: // Add one to each arr map (n) -> n + 1 // Then filter out the odds filter (n) -> isEven(n) // Then sum the array reduce $$ + $
  • 14.
    Shortcomings of Operators 1.More complicated lambdas do not lend themselves to organizing code in the more friendly format: // Add one to each, filter out odds, then sum arr map (v) -> { “type” : “integer”, “n” : v.n + 1, “time” : now() } filter (v) -> isEven(v.n) reduce (v, total=n) n + v.n
  • 15.
    Shortcomings of Operators(Cont.) 1. More complicated lambdas do not lend themselves to organizing our code in the more friendly format. 2. Operators force us to have a deeper understanding of operator precedence. Which evaluates first? arr map (v) -> v + 1 filter (v) -> isEven(v) reduce $$ + $ Is this even valid code?
  • 16.
    Nope Scripting language erroron expression '%dw 2.0 output application/java var arr = [1,2,3,4] --- arr map (v) -> v + 1...'. Reason: Expecting Type: `Array<T>`, but got: `Number`. Function: `filter(items: `Array<T>`, criteria: (item: `T`, index: `Number`) -> `Boolean`) -> `Array<T>`` Actual : `filter(items: `Number`, criteria: (v, $$) -> `?`)`.
  • 17.
    Shortcomings of Operators(Cont.) 1. More complicated lambdas do not lend themselves to organizing our code in the more friendly format. 2. Operators force us to have a deeper understanding of operator precedence. Which evaluates first? arr map ((v) -> v + 1) filter ((v) -> isEven(v)) reduce $$ + $ Need to wrap the first two lambdas in parenthesis so DW knows when the lambda body closes.
  • 18.
    Shortcomings of Operators(Cont.) 1. More complicated lambdas do not lend themselves to organizing our code in the more friendly format. 2. Operators force us to have a deeper understand of order of operations. 3. Even if we were ok with the above, we cannot create our own operators.
  • 19.
    What if we’reusing Java? // Java, but still very functional finallyDoThis(thenDoThis(doThis(x))) // It’s imperative, but we’re still // adhering to FP tenets. String that = doThis(x); Int n = thenDoThis(that); Result res = finallyDoThis(n);
  • 20.
  • 21.
    Declarations (Cont.) Declarations inDataWeave are whatever you find above the triple-dash: %dw 2.0 output application/json // Format declaration var n = 1 // Variable declaration fun addOne(n) = n + 1 // Function Declaration --- addOne(n)
  • 22.
    Declarations (Cont.) Use declarationsto regain a Java-esque imperative style. This gives us the ability to “un-nest” our function calls so they can be read left-to-right, top-to-bottom: var that = doThis(payload) var n = thenDoThis(that) --- finallyDoThis(n)
  • 23.
    Declarations (Cont.) Q: Canwe only place declarations above the triple-dash at the top of the DataWeave file?
  • 24.
    Declarations (Cont.) Q: Canwe only place declarations above the triple-dash at the top of the DataWeave file? A: No!
  • 25.
    do Example fun tomorrow()= do { var today = now() // Can declare new variables fun addOneDay(dt) = // Can declare new functions dt + |P1D| --- addOneDay(today) // This is what is ultimately returned } --- tomorrow() Declarations Body (what gets returned from do)
  • 26.
    do Use Cases- Unnecessary Calculations var arr = [1,2,3] fun doSomething() = arr map (n) -> { plusOne : n + 1, // Called sizeOf(arr) times meta : reallyExpensiveFunc() } fun doSomething() = do { // Called 1x var val = reallyExpensiveFunc() --- arr map (n) -> { plusOne : n + 1, meta : val } }
  • 27.
    do Use Cases- Unnecessary Calculations var arr = [1,2,3] fun doSomething() = arr map (n) -> { plusOne : n + 1, // Called sizeOf(arr) times meta : reallyExpensiveFunc() } fun doSomething() = do { // Called 1x var val = reallyExpensiveFunc() --- arr map (n) -> { plusOne : n + 1, meta : val } }
  • 28.
    do Use Cases- Extract repetitive functionality fun between(dateStr, start, end) = (dateStr as Date {format: “MM/dd/yyyy”}) > start and (dateStr as Date {format: “MM/dd/yyyy”}) < end fun doSomething() = do { var date = dateStr as Date {format: “MM/dd/yyyy”} --- date > start and date < end }
  • 29.
    do Use Cases- Extract repetitive functionality fun between(dateStr, start, end) = (dateStr as Date {format: “MM/dd/yyyy”}) > start and (dateStr as Date {format: “MM/dd/yyyy”}) < end fun doSomething() = do { var date = dateStr as Date {format: “MM/dd/yyyy”} --- date > start and date < end }
  • 30.
    do - AReal World Example Determine amount owed from an Array of amounts. Each item in the Array will be like the following: [ { “Account” : “jerney.io”, “Type” : “Debit”, “Amount” : 123.10, “Date” : “1/1/2019” }, ... ]
  • 31.
    A Real WorldExample: Business Logic Accumulate the total Amount owed for each Account. ● If the Date field is in the past, add 10% to the Amount. ● If the Type is “Credit” subtract the modified Amount from the total, ● If the Type is “Debit” add the modified Amount to the total.
  • 32.
    A Real WorldExample: First Take
  • 33.
    A Real WorldExample: First Take (cont.) Use var to name this Eliminate this duplication
  • 34.
  • 35.
    Second Take (Cont.) Shouldbe its own function
  • 36.
  • 37.
    Third Take (Cont.) Thisis called for every item in the Array, but we only need to call it once
  • 38.
  • 39.
    Final Thoughts ● Expression-heavylanguages are a double-edged sword ○ Great for conciseness and reasoning about a problem ○ Expressions without declarations kill readability and punish us for writing small, reusable functions ● Use declarations and do statements (expressions) to write: ○ Code that is easier to understand ○ Code that is more performant ○ Code that is easier to develop Get the code here: https://github.com/jerneyio/connect19presentation
  • 40.
    Questions? Come “Ask meAnything”! ● Tomorrow ● Community Booth ● 10:30am to 11:15am