Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 49

Workday's transformation to a new

language platform
Developing a full-fledged programming language with MPS
Safe Harbor Statement

This presentation may contain forward-looking statements for which there are risks, uncertainties, and
assumptions. If the risks materialize or assumptions prove incorrect, Workday’s business results and directions
could differ materially from results implied by the forward-looking statements. Forward-looking statements
include any statements regarding strategies or plans for future operations; any statements concerning new
features, enhancements or upgrades to our existing applications or plans for future applications; and any
statements of belief. Further information on risks that could affect Workday’s results is included in our filings with
the Securities and Exchange Commission which are available on the Workday investor relations
webpage: www.workday.com/company/investor_relations.php

Workday assumes no obligation for and does not intend to update any forward-looking statements. Any
unreleased services, features, functionality or enhancements referenced in any Workday document, roadmap,
blog, our website, press release or public statement that are not currently available are subject to change at
Workday’s discretion and may not be delivered as planned or at all. 

Customers who purchase Workday, Inc. services should make their purchase decisions upon services, features,
and functions that are currently available.
Bircan Copur Antonio Gliubich Alexey Yashin
Software Development Software Development Software Development
Engineer Engineer Engineer

Workday Confidential
Agenda

What is Workday & Overview of our legacy code

YP – As a platform and a language developed with MPS

Updating instances in an immutable world

Handling translations in YP

Implementing generics with MPS

Workday Confidential
Workday

● Established 2005
● Provides business apps:
● Human Capital Management, Payroll,
● Financial Management, Analytics,
● Student, Learning, Recruiting …
● SaaS, in the cloud
● multi-tenant-per server
● Lots of satisfied customers
● Airbnb, Adobe, Amazon, Siemens, Wal-Mart
Applications Development

● Defining business logic as metadata


● Customers define:
● Workers, Organizations, Compensation Plans, …
● Developers define:
● Classes, Methods, Tasks & Pages, …
● XpressO is a bootstrapped language
● “Steve Morgan” is an instance of the Worker class.
● The “Worker” class is an instance of the “Class” class.
● Learn XpressO in a 6-week “boot camp”
● Lots of room for improvement of developer experience here
What Exactly is XpressO? (XO)

● Editable through web forms, mostly


● Like this “GRA - Get Referenced Attribute Method”
What Exactly is XpressO? (XO)
Introduction to YP

What is it?
• YP is a new evaluation runtime for our XpressO language
• YP is a new compiler for our XpressO language.
• YP is a language and IDE for developers. (tYPe)
Introduction to YP

What is it?

Workday Confidential
Updating instances in an immutable world

Challenges
• YP assumes immutability!
‒ Expression based
‒ Local variables cannot be changed
‒ Functions are transparent, do not have side effects
‒ Can rearrange code for more efficient execution
Separating Procedures and Functions

Procedures
Functions

Functions may not call Procedures


Derived PUs

let workerBuilder = new Worker {


Derived
apply Actual
name = “Logan McNeil”
Instance Instance team = “YP EMEA”
}

apply workerBuilder

• Still part of the program flow – has side effects


• Still means we lose immutability
Solution

• NO apply-ing whatsoever!
‒ YP separates update “instructions” from update “execution”
‒ Allow creating instructions for updates only
‒ Pass those instructions around in functions without any side
effects
‒ Whoever is invoking the function is responsible for applying
 UI task, REST API, etc.
The New Way
Syntax
Token

• To represent an entity that does not exist yet:


‒ token<Workdog>()

• To represent an entity that exists:


‒ workdogInstance.getToken()

• Has type Token<Workdog>


Create/Delete/Set Update

• To create an entity:
‒ create workdogToken

• To delete an entity:
‒ delete workdogToken

• To update attribute and relationship values


‒ set workdogToken.name = “Snoopy”
‒ set workdogToken.hasSnapshot = snapshotInstance
Binding Updates Together
Sequence Update

(create workdogToken)
.then(set workdogToken.name = “Snoopy”)
.then(set workdogToken.snapshot = snapshotInstance)

or with some syntactic sugar:

update {
create workdogToken
set workdogToken.name = “Snoopy”
set workdogToken.snapshot = snapshotInstance
}
Binding Updates Together
Chain Update

update {
create breedToken
set breedToken.breedName = “Dalmatian”
}.chain((breed) => {
create workdogToken
set workdogToken.name = “Spots the ” +breed.name
})
Binding Updates Together
Update each

worker.hasWorkdog.updateEach((workdog) => {
let workdogToken = workdog.getToken()
set workdogToken.name = worker.name +”’s ” +workdog.name
})
Unit Testing YP Updates

• Testing updates in XO is… unpleasant - you cannot unit test them!


• We can run update instructions in tests against mock data and
verify them
• Totally offline! No object model/real data is needed for testing!
Developer Feedback

• “Early Adopter“s are using YP for a few months now


• Some initial confusion around the concept of “Token“s
• Overall very positive reception
• Unit testing is a real improvement

Workday Confidential
Handling Translations in YP
Localization vs Translation

Localization
• Date, time, number formats
• Contact information
• Weights, measurements
• Translations
• …
Coding vs Spoken Languages
Translation Process

code +
code
translations
Translation Process with XO

• Translation Tools are written in XO: translators (contractors) access


Workday UI to enter translations
• Translations are basically code changes (metadata changes, exactly
as any code change made by developers via Workday UI)
• Changes get “merged” into master by internal resources

master
WD UI WD UI WD UI
WD UI
XO XO XO
Metadata Translation
Metadata
(code + Metadata
metadata
translations)
Translations with YP - Prototypes

• Created several prototypes


‒ Tried to envision the same approach with YP, storing translations in YP AST

‒ Enriched our test language to specify a language


tranlsatableText { let welcomeMessage = "Hi" + this.getName() + "!" {
expression = "Hi [name]!" translations = {
translations = { de_DE : "Hallo" + this.getName() + "!"
de_DE : "Hallo [name]!" it_IT : "Ciao" + this.getName() + "!"
it_IT : "Ciao [name]!" }
} }
}

test Translations {

case german {
let result = person.getWelcomeMessage("Joe").translate()
assert result == "Hallo Joe!" :: result
} de_DE
}
Translation Process with Prototypes
• Tried to envision the overall Translation Process using those YP prototypes

tYPe tYPe
tYPe YP ver YP ver
control tYPe
YP control
YP AST YP AST
YP AST
(code + YP AST
translations) translations
Prototypes Evaluation
‒ Translators would have to use tYPe or we would need some import process to add
translations to the AST

‒ No plans to change the process or translation tools

‒ Larger AST

‒ Risk to break AST

‒ AST Versions could be out of sync


tYPe tYPe
tYPe YP ver YP ver
control tYPe
YP control
YP AST YP AST
YP AST
(code + YP AST
translations) translations
A Different Approach

• Translations outside YP AST


• Generic interface to load translations

Code Translations XpressO


external Tools
YP …

compiler loader
runtime
Translatable Text Definition in YP

• New type for strings to be translated


• Allows to uniquely identify what needs to be translated
• Handles both strings and text expressions (e.g. “Hello [name]!”)

code Translations
XpressO
external Tools
YP …

+
translatableText WLCM_MSG = "Hi [name]!"
Translations in YP
• Not included in the AST
• Just strings keyed by language code and definition
• Retrieved with a generic interface, from XO metadata, files, etc.
• Translations are retrieved and stored at deployment and available at runtime
code Translations XpressO
external Tools
YP …

+
WLCM_MSG, de_DE, "Hallo [name]!”
WLCM_MSG, it_IT, “Ciao [name]!”
MPS for YP Translations

• Prototyping
• Concepts to define and easily identify a translatable vs non-translatable text
• Human-readable identifier
• Parsing of text expressions
let t = translatableText WLCM_MSG = "Hi [name]!”

• Syntax to resolve the translation

let text = t.translate(“de_DE”)


Implementing Generics for YP
Motivation: Why do we need generics?

In Java generics enable types (classes and interfaces) to be


parameters when defining classes, interfaces and methods. Which
means:
• ability to write generic algorithms
• stronger type checks at compile time
Problem

We wanted:
• to allow the application developers to create libraries of generic
algorithms (e.g. for collections) and to add type parameters in their
YP code.
• to make YP similar to Java or C# in terms of generics and object
oriented features which those have.
Solution Approach

Given that a major part of YP is implemented in MPS we decided to


use the MPS inference rules and type system language features to
add support for generics in YP language.
Generics from the perspective of app dev

• you can have simple type parameters (something like <A>)


• optionally you can define bounds, as well (e.g. <A extends Base>)

Which challenges does it have?   


Implementation details / challenges

function <A, B> f(a1: A, a2: A, b: B): A


f(1, 2, “text”)
f(1, ”wrong”, ”text”)  fails

Since a1 and a2 are referencing the same type parameter definition,


they should be assigned the same runtime type variable.
Runtime type variables

function <A, B> f(a1: A, a2: A, b: B): A


val x: number = f(1, 2, ”text”)

• Introduce runtime type vars for each type parameter definition


• Traverse parameter types and expand generics
• Establish inferences with subtyping between assignments and
parameter types
Type Inference

For each type parameter definition in the referenced parameterized


type:
• If type argument is concrete (e.g. text or number) → do nothing
with the type
• Otherwise, create a type var (RuntimeTypeVariable) and infer
on bounds. When typevar is concrete, assign it to the type
parameter definition
Type Inference: Code sample

var T; // runtime type variable


// Apply inference on bounds
foreach bound in typeParamDef.bounds {
infer typeParamDef :<<=: bound;
}
typeParamDef = T;
// Solve inequalities by establishing the constraints against T
when concrete (T as typeArg) {
// If type system solver succeeds with T,
// that is, it can come up with a concrete type
typeParamDef = typeArg;
}
Type Inference

The block when concrete is asynchronous which means


typeParamDef will be assigned to a concrete type at some point in
the future (if the resolution will ever happen).

Type system is trying to find a solution that satisfies all inequalities


(according to subtyping rules).
• If solving succeeds: runtime type variable gets assigned a concrete
type (e.g. number, text)
• If solving fails: runtime type variable just remains as it is (e.g. g4)
Type Inference

The mapping between type parameters and their runtime type


variables would look like this: 
{A -> y26, B -> t38, X -> d7}

And when the corresponding when concrete blocks get executed (and
the inequalities solving is done) we end up with something like:
{y26 -> number, t38 -> text}
Checking rule

Once the types are concrete we might want to show a custom error
message to the user if the types don’t match by checking them in a
checking rule.
if (!isSubtype(argType :<=: paramType))  error
Evaluation

Where are generics mostly used in YP?  util library

Since the YP application developers very often rely on the data


structures like these, the generics functions are used very intensively
by almost any YP-based project.
• Type inference and runtime type vars

• Generics in YP

• Usages in the early adoption projects

You might also like