SpringOne Platform 2016
Speakers: Joseph Rodriguez; Engineering Manager, Pivotal. Peter Clowes; Software Developer, Savoya.
Are you taking on a large project that seems insurmountable? Perhaps a full rewrite, migrating to the cloud, or a large ETL? Extreme Programming can help!
Following a full rewrite of our legacy application, we were tasked with transferring data from Oracle to Postgres- with an entirely different schema. This session covers basic principles of XP and how they helped get us to production in under 2 months.
3. What we’ll cover
• Our unwieldy project
• Why & how we applied XP
• Interesting SQL
3
4. • Safe and secure ground transportation worldwide
• 24/7/365
• 70/100 Fortune 100 CEOs
• Founded in 2000
• Based in Dallas
• 10+ year legacy software
4
5. • Ground up re-write
• Enable new team
• Extreme Programming
5
11. Second false start
3rd Party ETL team
• Team not co-located
• Big problems stayed big
11
12. Second false start
3rd Party ETL team
• Team not co-located
• Big problems stayed big
• Feedback anti-patterns
12
* Note: vehicles get much heavier when filled with water
13. Extreme Programming
• Refactoring
• Continuous integration
• 40-hour workweek
• On-site customer
• Metaphor
• Coding standard
13
• Test Driven Development
• Pair programming
• Rapid iteration
• User stories
• Collective ownership
• Fix It
• Simple design
14. Test Driven Development
• High risk one-off
• Prevent regressions
• Clarity
• Easy to deal with changing requirements
14
15. Messy Data
15
d=# select xmlparse(document note.value);
ERROR: syntax error
update note set value = ‘<?xml version="1.0" ?>…’
^
16. Messy Data
16
id value
290384 update note set value = ‘<notes>
<note>
<value>Please have a micro USB cable</value>
<author>Peter C</author>
<created>1201932175</created>
</note>
…
</note>’;
note
17. What does 20973889 mean?
17
id ops_status
313 20973889
reservation
We asked for the legacy source code, but we got a .war instead.
20973889 >> 4 & 128 > 0 == The reservation was confirmed!
19. 19
public void testEventsAreCreated_ForReservationInTransit() {
// arrange
exec("insert into etl.reservation (id, ops_status) values (313,
20973889)");
// act
new ReservationEventsEtlService.run();
// assert
assertEvents(313, ”created", ”confirmed", ”in_transit");
}
Unit Testing ETL Code
20. Rapid iteration
• Real, up-to-date data
• Multiple pushes a day
• Dedicated environment for testers
20
21. Fake data for complex relationships
21
reservation
coordinator driver
update reservation set driver = 1;
22. One Script
Step 1: Download DB dump
Step 2: Restore dump into VM
Step 3: Copy Oracle DB to Postgres
Step 4: Run Transformation
Step 5: Create Postgres dump
Step 6: Upload dump and restart app
22
26. Basic data mappings
1. Select from source table
2. Transform data
3. Insert into destination
26
WITH passenger_objects AS (
SELECT id,
unnest(xpath(‘//passenger’, passengers::xml))
p
FROM ms_reservation
)
INSERT INTO reservation_passengers (
reservation_id, first_name, …
)
SELECT id,
xpath(‘/first_name/text()’, p) first_name, …
FROM passenger_objects;
2
1
3
2
27. A more complex mapping
27
reservation reservation_passenger passenger
30. 30
WITH passengers_with_reservation_id AS (
SELECT reservation_id, (…) AS name , (…) AS email from etl.reservation
), new_passengers AS (
INSERT INTO passenger (name, email)
SELECT name, email FROM passengers_with_reservation_id
RETURNING *
)
INSERT INTO reservation_passenger
(reservation_id, passenger_id, name, email)
SELECT reservation_id, id, name, email
FROM passengers_with_reservation_id
JOIN new_passengers ON (…);
31. Launch Day
• ETL took 2 hours
• Handled issues over the next 24
hours
• Flew to HQ to support team
• Fully stable in 2 weeks
• Deep trust between teams
• Agile mindset
31
What does unwieldy mean?
Simply anytime you’re unsure of what to do and do not see a clear path forward.
What is unwieldy to one may not be unwieldy to another
Unwieldy problems often appear simplistic from the outside.
Avoid reductionist argument
Does everyone know what XP is?
Badly named but highly effective subset of Agile
We will go deeper later
(Peter)
Using ETL as example
Happy medium agile process/technical talk
Invite questions and feedback
(Peter)
Our mission is to be the world’s safest and most reliable ground transportation company.
-Product lines: everything from a black car, to private air (the majority), to armed convoys
-(Story?)
When it has to go right, use Savoya.
Tech:
Legacy Java Application on an Oracle DB, dev team in India
-original authors became rich doing real estate speculation in India.
-Turns out Sr. Engineers becoming independently wealthy is bad for your codebase
(Peter)
(Peter)
Fail fast?
None of our clients are "beta testing" anything.
Transportation is hard (1/3 of you)
Bringing agile to the enterprise during a transition
Limited wiggle room.
Purposefully built the new system without knowing about the old
Didn't know how data flowed through the old application. Which tables contained what etc.
Lack of expertise. Nobody on the team was a DBA or experts at Oracle or Postgres.
Started at the most basic objects and relationships in our system and tried to work up
However thats like pulling a string... what was simple in our system was tightly coupled to everything in the old system.
Seemingly Simple transformations would constantly snowball.
Iteration planning was hard. No idea how long anything would take
This generated a lot of uncertainty which caused a lot of frustration as feature work slowed to a crawl.
(Peter)
Made this decision to allow devs to keep building features and not get bogged down by ETL work.
It seemed like a good idea at the time, but proved to be completely wrong because it turns out hard things are hard.
Hard things are even harder when you are not put in a position to succeed.
Transportation looks deceivingly simple
Lack of testing
Tried to tackle too much all at once
Regressions were common
You would think a mapping was solved and then it would be way worse
(Peter)
Meetings would be too far apart, no daily standups
Then a couple big regressions would occur that would spark a wave of meeting to fix both the regressions, and the meetings,
Questions weren’t asked enough
Decided to give it a try again now that feature work was farther along. Pulled in pivotal engineers with deep SQL backgrounds
In hindsight this is nice, it gave us a “control” we have tried it multiple ways.
But now we were back in the muck.
To garner some sympathy…
(Joe) The data was messy and the mapping was complex. The development team and the data transfer (etl) team working seperately severely hindered progress
(Joe)
Tdd – less effort for more accurate code
Pairing – shared context, learning and education, …
Rapid iteration– small, digestable chunks of work. Fast feedback from product. Better roi for savoya, less churn.
We’re going to show you some specifics!
(JOE)
Just because the code only ran once didn’t make it any less valuable than the production code/system. Actually it was more important because we only had 1 chance to do it right
False starts had regression issues. Fixing one issue would bring old bugs back.
Easy to see what each transformation/mapping was doing.
Lots of revisiting, Easiest way to see what etl code was doing
There’s no such thing as clean data
8th bit
(JOE)
What are reservation passengers?
Using the status example we just looked at…
tie back to principal... how to build a test harness for your project?
We tried a couple of different ways to test SQl... We don't typically do this in app code
On unwieldy projects you may be tempted to stray from the process, espicially if the benefits aren’t immediately apparent
(PETER)
Principle: small release
Typical practice: rapid iteration
How to iterate a one-off event?
Our users won’t beta test
Multiple pushes a day. Constant and open communication with our Product Owner
Learn how to iterate and do work in smaller chunks. Tackle the risk early on and put shims in place if they help.
Make it work, make it right, make it fast
Single script to run entire ETL process
Start with most difficult tables and fake their relationships
This allowed us to gain momentum and deliver smaller stories
Feedback: go through each step
Breaking apart the shell script into individually executable steps allowed for easy testing of each stage as well as timing of each stage to make sure we were well within the window
The script was easily runnable by anyone on the team.
Foreign data wrappers were used to pull all data from oracle into postgres
Management was able to test on fresh data constantly
Stories were accepted more quickly
Edge cases were discovered more quickly
AUTOMATED – any team member could run the script at any time
This enabled us to complete the etl much faster
(JOE)
SQL expertise working alongside app specific expertise
By the end of the project, everyone became solid in SQL thanks to pairing. It’s the fastest way for programmers to learn new technologies. Try pairing a junior dev with a senior dev and track the junior devs career progress.
15% percent fewer
- If someone is sick or on vacation, pairing
Some cool sql examples but before I show you that you may be asking…
Why not use a standard programming language?
Obvious
Lowest level, most control
CTE, FDW, Dealing with XML
speed
equivalent java or ruby is many more LOC
Example time
(JOE)
What are reservation passengers?
(JOE)
(JOE)
But what if it’s a many-to-many mapping?
This is a bit more difficult because the passsenger ids are only known after they are inserted.
This means we have multiple destinations: RETURNING from a CTE for multiple destinations