1 © 2011 Zynx Health Incorporated | The information contained herein is confidential and proprietary to Zynx Health Incorp...
2 © 2011 Zynx Health Incorporated | The information contained herein is confidential and proprietary to Zynx Health Incorp...
Agile developers like itdynamic.JavaScript, Ruby, NoSQLJava,.Net,SQL
 Strict types in static languages like C++ andJava make code more time-consuming towrite and verbose to read. Static cod...
 Mapping data to objects produces profusecode, mostly boilerplate but obligatorynevertheless Piles of model classes and ...
 Static schema is strict and very difficult andcomplicated to change. Normalized relational models make complex datacumb...
Developers like NoSQL Low barrier to entry Scales horizontally Seamless programming language integration
Developers like NoSQL Low barrier to entry Scales horizontally Seamless programming language integration BUT MOSTLY be...
But when you think XML,you dont think NoSQL.
When I think XML,I think Static XMLMapping to objects strikes again• Serialization libraries map schematic structuresto cl...
When I think XML,I think Static XMLMapping to objects strikes again• Serialization libraries map schematic structuresto cl...
When I think XML,I think Static XML• Pedantic namespace usage complicatescode, especially at the edges• Big, complicated, ...
And yet…• Nothing about XML requires that you map it toobjects– Plenty of support in programming languages formanipulation...
Developers dont like XML itself(even though its a dynamic document format, just like JSON)Wordy and complicatedo Attribut...
Whats More…• XML provides a rich ecosystem• Rich transformation…– …with XQuery in the database– …with XSLT almost everywhe...
Whats More…• XML provides multiple, rich schemastandards (unlike other document NoSQLformats)– Automated validation and ev...
Whats More…• XML provides multiple facilities for dataintegration…– …XInclude for automated documentaggregation (including...
Whats More…• Breadth and depth of XML ecosystemprovides all sorts of network effect benefits– Multiple implementations of ...
Leverage Can Tip the Scale• Complex, modular data• Complex things being done with data• Integration in an XML-rich space– ...
Flexibility (lack of resistance to change)Leverage(providedbyecosystem)SQLJSONNoSQLEnterpriseXMLAgileXML
The Methodology…
Dynamic•No knee-jerk object/data mapping•Limit friction (schemata, namespaces)Modular•Resource orientation•Layered, re-usa...
 Treat data dynamically› Dont reflexively serialize to/from objects› Transform and aggregate resources asneeded for speci...
 Be resource-oriented› Implement use cases by transforming andassembling resources› Write transforms and other resource p...
 Ensure integrity through tests› Test specific data features instead of broadlyschema-validating› Apply test-driven devel...
Test-driving XSLT• My team attempted several approachesbefore we got this right• Lots of testing frameworks, not muchcommu...
Test-driving XSLTTypical framework-based XSL unit test:<test><code>my-stylesheet.xsl</code><input>input-doc.xml</input><ex...
Test-driving XSLT• Problems with this approach:– Test input and output must be data-complete• Verbose, laborious and britt...
Test-driving XSLT<output><stuff/></output><output><stuff/></output><output><stuff/></output><output><stuff/></output><outp...
Test-driving XSLTThe Forced Modularity ProblemOutput-driven XSLT<html><body><xsl:for-each select="//item"><div><xsl:value-...
Test-driving XSLT• We use code to simplify inputs and narrowdependencies on outputs– Focus on features, not unnecessary de...
Test-driving XSLTExample<movieList><movie><title>Citizen Kane</title><genre>drama</genre></movie><movie><title>Tommy Boy</...
Test-driving XSLTTest fixtures simplify complex inputs:FragmentsString makeMovie(Map fields) {"""<movie><title>${fields?.t...
Test-driving XSLTTests analyze specific features:@Testvoid shouldAggregateIntoGenres() {List movies = (1..2).collect {make...
Test-driving XSLTUse of rich language features can helpkeep tests short and expressive:@Testvoid shouldSortMovieTitles() {...
Test-driving XQuery• xray, xquery-unit, XQUT and others forMarkLogic• XQSuite for eXist-db• TDD works for developing XQuer...
Test-driving XQuery• HOWEVER: Functional language makes testdiagnosis more painful (no "print to console")– Alternatively,...
Test-driving XQueryQuery result contains diagnosticinformation to help understandtest failures.Tests a specificfeature, no...
Test-driving XQueryTesting side-effects ofcode that writes to thedatabase can betricky. Here, we useMarkLogicsxdmp:eval fu...
Writing Maintainable XSLT and XQuery• Test-driven development is critical– Well-written tests document the code theyretest...
• Readable tests use names to tell a story– Test (function) names should follow someGiven-When-Then-like convention– Varia...
• XSLT is a flexible language, so employ patternsthat work for your team• Most people find output-driven stylesheetseasier...
• Again, use variables to help tell stories evenwhen theyre unnecessary• Use xsl:include for modularity and re-use• Use mo...
• Ummm… variables!– Lift deeply nested expressions out into "let"variables, where possible• Use function modules for modul...
Database Migrations• Migrations framework took only a few days towrite and integrate into our CI pipeline– Includes easy d...
Database MigrationsOne day, we decided to stop version-managing acategory of documents. Heres what themigration looked lik...
 When we decided that we had a real need tomake ingestion ironclad for certain data, westarted using schema validation. ...
Schema validation usually requires namespace usage. Wewanted schema validation in our database layer, so weimplemented nam...
Treating Data DynamicallyYou dont care about all the extrastuff on a jQuery event object, aslong as its got what you need....
Treating Data Dynamically• In an Agile XML application, yourcode is also loosely coupled to itsresources• No need to care ...
Treating Data Dynamically• Your code doesnt care– Its not mapping data to objects– Its not schema-validating data• Your te...
Treating Data Dynamically• Manage change through tests– Unit tests where your changes originate(and wherever else you reme...
Chaos?
Resource Orientation = Chaos?Modularizing through resources can scatterbusiness logic.• Variety of solution technologies t...
BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueUser saving with "released" status means release, otherwi...
BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueSQL VenueUser saving with "released" status means release...
BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueSQL VenueUser saving with "released" status means release...
BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueSQL VenueUser saving with "released" status means release...
BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueSQL VenueUser saving with "released" status means release...
Case Study: Clinical Order View
Case Study: Clinical Order Viewchecklistsscopedinterventions etc.XQueryXSLTClient
Case Study: Clinical Order Viewchecklistsscopedinterventions etc.JavaScriptClientWhat if?
Fetching the Datadeclare private function enriched-performance-measure($perfMeasure as node()) {return element performance...
Fetching the Datadeclare private function enriched-performance-measure($perfMeasure as node()) {return element performance...
Generating the View<xsl:template name="intervention"><xsl:param name="intervention-group-key"/><xsl:param name="interventi...
<xsl:template name="intervention"><xsl:param name="intervention-group-key"/><xsl:param name="intervention-name" /><interve...
<xsl:with-param name="intervention-group-key"><xsl:text>section-</xsl:text><xsl:value-of select="normalize-space(current-g...
<xsl:for-each-group select="scopedInterventions/scopedIntervention"group-by="normalize-space(intervention/id)">var result ...
So, There are Trade-offs• Any XML-based architecture presents aminimum level of friction versus otherdocument NoSQL stacks...
72 © 2011 Zynx Health Incorporated | The information contained herein is confidential and proprietary to Zynx Health Incor...
Agile xml
Agile xml
Upcoming SlideShare
Loading in...5
×

Agile xml

1,091

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,091
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
7
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Agile xml

  1. 1. 1 © 2011 Zynx Health Incorporated | The information contained herein is confidential and proprietary to Zynx Health Incorporated and is intended for itsauthorized recipient. Unauthorized review, use, disclosure or distribution is strictly prohibited. All rights reserved.
  2. 2. 2 © 2011 Zynx Health Incorporated | The information contained herein is confidential and proprietary to Zynx Health Incorporated and is intended for itsauthorized recipient. Unauthorized review, use, disclosure or distribution is strictly prohibited. All rights reserved.Agile XMLThere is such a thing.
  3. 3. Agile developers like itdynamic.JavaScript, Ruby, NoSQLJava,.Net,SQL
  4. 4.  Strict types in static languages like C++ andJava make code more time-consuming towrite and verbose to read. Static code is harder to unit-test (typesystem fights mocks). Dynamic languages present a lower barrier toentry and the code often ends up more terseand expressive. Dynamic flexibility means no hoops to jumpthrough when you want to change things. Developers prefer to ensure integrity throughtests rather than type safety features.
  5. 5.  Mapping data to objects produces profusecode, mostly boilerplate but obligatorynevertheless Piles of model classes and mappingartifacts, often containing specializedconfigurations for indirectly tuning queries, addfriction to change. Abstracts code away from database interactionsin ways that can encourage sub-optimalbehavior (e.g., the "n+1 selects" problem). But still preferable to the drudgery andmaintenance nightmare of stored procedures.
  6. 6.  Static schema is strict and very difficult andcomplicated to change. Normalized relational models make complex datacumbersome to manipulate in native query language. Query language (SQL) is virtually impossible to unit-test.
  7. 7. Developers like NoSQL Low barrier to entry Scales horizontally Seamless programming language integration
  8. 8. Developers like NoSQL Low barrier to entry Scales horizontally Seamless programming language integration BUT MOSTLY because its dynamic Easier to change Easier to scale up Easier to test
  9. 9. But when you think XML,you dont think NoSQL.
  10. 10. When I think XML,I think Static XMLMapping to objects strikes again• Serialization libraries map schematic structuresto classes– Classes generated once from XML schemata andthen manually maintained (JAXB)– Manually mapped classes (XStream)• Many manually-maintained artifacts with brittledependencies on data• Lots of friction to change, just like SQL ORMs
  11. 11. When I think XML,I think Static XMLMapping to objects strikes again• Serialization libraries map schematic structuresto classes– Classes generated once from XML schemata andthen manually maintained (JAXB)– Manually mapped classes (XStream)• Many manually-maintained artifacts with brittledependencies on data• Lots of friction to change, just like SQL ORMs
  12. 12. When I think XML,I think Static XML• Pedantic namespace usage complicatescode, especially at the edges• Big, complicated, repetitive andimpenetrable XSLT code often a coreimplementation feature• Storage often still SQL-based (and slow)due to departmental culture/policy
  13. 13. And yet…• Nothing about XML requires that you map it toobjects– Plenty of support in programming languages formanipulation through other means• Namespaces can be walled off or eliminatedaltogether• XSLT (and XQuery) code can be designed withmodularity and expressiveness– Was your first LISP program modular?– Might your tenth one have been better?
  14. 14. Developers dont like XML itself(even though its a dynamic document format, just like JSON)Wordy and complicatedo Attributeso Namespaceso Mixed text/element contento WhitespaceTools and languages seem arcaneo XSLT / XPatho XML Schema / RelaxNGo XQueryLimited database optionsImpedance mismatch with JSON
  15. 15. Whats More…• XML provides a rich ecosystem• Rich transformation…– …with XQuery in the database– …with XSLT almost everywhere– …in code with rich, embedded DSLs• Rich query…– …with XQuery in the database– …with XPath almost everywhere– …with GPath in Groovy
  16. 16. Whats More…• XML provides multiple, rich schemastandards (unlike other document NoSQLformats)– Automated validation and even content repairat database level– Usage is completely optional; could be usedas a barrier, or just to generate informationabout schema violations
  17. 17. Whats More…• XML provides multiple facilities for dataintegration…– …XInclude for automated documentaggregation (including automated broken linkreporting)– …Attributes, including RDFA, for aspect-oriented tagging– …Namespaces for more aspect-orientedintegration
  18. 18. Whats More…• Breadth and depth of XML ecosystemprovides all sorts of network effect benefits– Multiple implementations of various strategiesfor dealing with large data sets(DOM, SAX, XPP, etc.)– Pipelining for faster, layered work on data– Schematrons for semantic validation– Schema-based editors likeInfoPath, Oxygen, XMLSpy, Arbortext, XMetaL and Xopus
  19. 19. Leverage Can Tip the Scale• Complex, modular data• Complex things being done with data• Integration in an XML-rich space– Healthcare, for exampleWhen is it enough?…to offset the additional complexity versus JSON/JavaScript
  20. 20. Flexibility (lack of resistance to change)Leverage(providedbyecosystem)SQLJSONNoSQLEnterpriseXMLAgileXML
  21. 21. The Methodology…
  22. 22. Dynamic•No knee-jerk object/data mapping•Limit friction (schemata, namespaces)Modular•Resource orientation•Layered, re-usable transformationsTestable•Assert data features as well as behavior•Unit-test XQuery, XSLT
  23. 23.  Treat data dynamically› Dont reflexively serialize to/from objects› Transform and aggregate resources asneeded for specific use cases (wrap dataaround problems)› Make a schema only when you really needone› Avoid or circumscribe high-friction features likenamespaces and attributes› Dont generate code based on XML datastructures (e.g., JAXB)
  24. 24.  Be resource-oriented› Implement use cases by transforming andassembling resources› Write transforms and other resource processingcode wherever its most maintainable› Favor functional approaches, whereapplicable, over imperative code and state› Seek re-use, granularity and clarity in yourresource transformations as you would seekthem in object-oriented abstractions
  25. 25.  Ensure integrity through tests› Test specific data features instead of broadlyschema-validating› Apply test-driven development practices toresource transformation and aggregationcode, including XSLT and XQuery› Run comprehensive data tests for continuousintegration and surveillance
  26. 26. Test-driving XSLT• My team attempted several approachesbefore we got this right• Lots of testing frameworks, not muchcommunity or clear adoption trends• Existing frameworks emphasize deepcomparison of output with expectedcontents (XML deep equals)• Most are based on XML-basedtesting DSLs
  27. 27. Test-driving XSLTTypical framework-based XSL unit test:<test><code>my-stylesheet.xsl</code><input>input-doc.xml</input><expect>output-doc.xml</expect></test><foo><bar /><baz /></foo>input-doc.xml<moe><larry /><curly /></moe>output-doc.xml<moe><larry /><shemp /></moe>
  28. 28. Test-driving XSLT• Problems with this approach:– Test input and output must be data-complete• Verbose, laborious and brittle• Easy to lose track of whats important in individual tests• Tests force a modularity that mightnt otherwise make sensein XSL code– XML-based testing DSLs limit flexibility• Limited set of assertions• No general-purpose programming languagefeatures available for writing test fixtures andother clever things• Even if JUnit output is supported, cantmake full use of JUnit features in IDE
  29. 29. Test-driving XSLT<output><stuff/></output><output><stuff/></output><output><stuff/></output><output><stuff/></output><output><stuff/></output><input><stuff/></input><input><stuff/></input><input<stuff/></input><input<stuff/></input><input<stuff/></input>TESTTESTTESTTESTTESTXSLT Stylesheetinputexpectationsoutputbehaviornew inputnew inputnew inputnew inputnew inputnew inputnew outputnew outputnew outputnew outputnew outputnew output• Burdensome• Discouragestest-writingTest SuiteThe Brittleness Problem
  30. 30. Test-driving XSLTThe Forced Modularity ProblemOutput-driven XSLT<html><body><xsl:for-each select="//item"><div><xsl:value-of select="text()"/></div></xsl:for-each></body></html>Input-driven XSLT<xsl:template match="/"><html><body><xsl:apply-templates select=".//item"/></body></html></xsl:template><xsl:template match="item"><div><xsl:value-of select="text()"/></div></xsl:template>• Need to simplify expected test outputs maypush you to the right• Many problems are simpler to solve on the left
  31. 31. Test-driving XSLT• We use code to simplify inputs and narrowdependencies on outputs– Focus on features, not unnecessary detail• We settled on straight JUnit for execution• Use test fixtures to manufacturecomplex inputs• Use GPath, etc., to assert onlywhat we care about in output
  32. 32. Test-driving XSLTExample<movieList><movie><title>Citizen Kane</title><genre>drama</genre></movie><movie><title>Tommy Boy</title><genre>comedy</genre><rating>R</rating></movie><movie><title>Annie Hall</title><genre>Comedy</genre></movie></movieList><catalog><genre name="Comedy"><film>Annie Hall</film><film mpaa="R">Tommy Boy</film></genre><genre name="Drama"><film>Citizen Kane</film></genre></catalog>XSLT
  33. 33. Test-driving XSLTTest fixtures simplify complex inputs:FragmentsString makeMovie(Map fields) {"""<movie><title>${fields?.title ?: Fake Title}</title><genre>${fields?.genre ?: fakumentary}</genre>${fields?.rating ?<rating> + fields.rating + </rating> : }</movie>"""}DocumentsString makeMovieList(List movies) {"""<movieList>${movies.join(n)}</movieList>"""}Usage@Testvoid shouldTransformMovies() {String input = makeMovieList([makeMovie(title: Primer)])// act, assert…}
  34. 34. Test-driving XSLTTests analyze specific features:@Testvoid shouldAggregateIntoGenres() {List movies = (1..2).collect {makeMovie(genre: drama)}movies << makeMovie(genre: comedy)def result =parseXml(transform(makeMovieList(movies)))assert result.genre.size() == 2}@Testvoid shouldCanonicalizeGenreNames() {String input = makeMovieList([makeMovie(genre: science fiction),makeMovie(genre: SCIENCE FICTION)])def result = parseXml(transform(input))assert result.genre.size() == 1assert result.genre.@name == Science Fiction}
  35. 35. Test-driving XSLTUse of rich language features can helpkeep tests short and expressive:@Testvoid shouldSortMovieTitles() {String input = makeMovieList([makeMovie(title: Zorro, rating: 2),makeMovie(title: Catching Fire, rating: 1),makeMovie(title: case insensitive, rating: 0)])def result = parseXml(transform(input))0..2.each {assertEquals(it.toString(),result.genre.film[it].@mpaa)}}
  36. 36. Test-driving XQuery• xray, xquery-unit, XQUT and others forMarkLogic• XQSuite for eXist-db• TDD works for developing XQuery code– My team does it (though we could be moredisciplined)• Same tools can be used for integration tests– Check features of data stored in database– Re-use for DB integrity checks, monitoring
  37. 37. Test-driving XQuery• HOWEVER: Functional language makes testdiagnosis more painful (no "print to console")– Alternatively, tests can produce diagnostic informationas query results on failure• Some messiness required to test code thatmodifies the database in MarkLogic
  38. 38. Test-driving XQueryQuery result contains diagnosticinformation to help understandtest failures.Tests a specificfeature, not just "XMLdeep equals"
  39. 39. Test-driving XQueryTesting side-effects ofcode that writes to thedatabase can betricky. Here, we useMarkLogicsxdmp:eval function tolaunch transactions insequence.
  40. 40. Writing Maintainable XSLT and XQuery• Test-driven development is critical– Well-written tests document the code theyretesting– Comprehensive tests documentcomprehensively– Without an infrastructure that at least supportstest-driven development, comprehensive testswill never be written
  41. 41. • Readable tests use names to tell a story– Test (function) names should follow someGiven-When-Then-like convention– Variable names should be thoughtfully chosenwith storytelling in mind– Add a variable, even if unneeded, just to givea name to something if it needs explanationWriting Maintainable XSLT and XQuery
  42. 42. • XSLT is a flexible language, so employ patternsthat work for your team• Most people find output-driven stylesheetseasier to read than input-driven ones– Easier to think in terms of end product– Named templates add more context– Imperative queries map more closely to imperativeprogramming experience– CAUTION: Performance cost can get significantWriting Maintainable XSLT
  43. 43. • Again, use variables to help tell stories evenwhen theyre unnecessary• Use xsl:include for modularity and re-use• Use modes only when necessary; they are easyto ignore and add to cognitive loadWriting Maintainable XSLT
  44. 44. • Ummm… variables!– Lift deeply nested expressions out into "let"variables, where possible• Use function modules for modularity and re-use– Try to curate them as deliberately as you do otherkinds of source modules• Prefer literal XML to element constructors whenelement names arent dynamicWriting Maintainable XQuery
  45. 45. Database Migrations• Migrations framework took only a few days towrite and integrate into our CI pipeline– Includes easy data ingestion facility based on filesystem• Arbitrary XQuery scripts can make whateverchanges they want• Migrations run in split seconds– If data size (running time) becomes an issue, theecosystem offers us several approaches
  46. 46. Database MigrationsOne day, we decided to stop version-managing acategory of documents. Heres what themigration looked like:for $doc in cts:search( /citation, dls:documents-query() )return dls:document-unmanage( fn:base-uri($doc), fn:false(), fn:true() )And heres a fix for some damaged data:for $empty-desc in /somePath/description[ fn:string-length() = 0 ]return xdmp:node-delete( $empty-desc )
  47. 47.  When we decided that we had a real need tomake ingestion ironclad for certain data, westarted using schema validation. XML Schema has rich features for validatingboth structure and values, though some findthe semantics cumbersome (thus, the existenceof a popular alternative, RELAX NG) Interactive editors provide gracefullyinterchangeable text and diagrammatic views Required namespaces, but we quarantinedtheir use at the DB layer (showcased)
  48. 48. Schema validation usually requires namespace usage. Wewanted schema validation in our database layer, so weimplemented namespaces in just the database layer andquarantined it there with simple transformations:<doc xmlns="…"><stuff></doc><doc><stuff></doc>Add namespace based onwhats being writtenStrip all namespaces onout-bound dataEasy for us, being XCC-based,but alternatives exist.
  49. 49. Treating Data DynamicallyYou dont care about all the extrastuff on a jQuery event object, aslong as its got what you need.If jQuery adds stuff, it wont affect you.If you owned this object and youchanged or removed stuff, youduse tests to make sure the rest ofyour code still works.
  50. 50. Treating Data Dynamically• In an Agile XML application, yourcode is also loosely coupled to itsresources• No need to care about data noiseor changes that dont affect you– Changes from/for other code– xml:base, xml:type and schemalocation attributes from othersystems
  51. 51. Treating Data Dynamically• Your code doesnt care– Its not mapping data to objects– Its not schema-validating data• Your tests dont care– Theyre not using "XML deep equals"– Theyre modeling and examiningonly whats important about the data• Dynamic data is changeable data!
  52. 52. Treating Data Dynamically• Manage change through tests– Unit tests where your changes originate(and wherever else you remember)– Integration tests cover data that crossboundaries (i.e., code you forgot)– Database-layer tests can cover persistentdata changes comprehensively• Continuous integration step• Integrity monitoring– Functional tests cover changed data asthey aremanufactured, stored, retrieved, transform
  53. 53. Chaos?
  54. 54. Resource Orientation = Chaos?Modularizing through resources can scatterbusiness logic.• Variety of solution technologies to handle varietyof problems• XQuery makes investment of logic at databaselayer more attractive– Real (though bizarre) functional programminglanguage– Proximity to data (reduction of round trips)
  55. 55. BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueUser saving with "released" status means release, otherwisesave.Both UI and Web APIcontrollerUser is not allowed to release a new checklist. UIWrap multiple write queries into a transaction, rolled back onerror.Checklist serviceGather PubMed citation IDs from scoped intervention outcomemeasurements.Checklist service +checklist DB libraryAcquire citation contents from PubMed Web API. Checklist service +PubMed serviceTransform (boil down) PubMed citations and store them indatabase.PubMed service +PubMed DB libraryChange status of referenced scoped interventions to "released"and save new versions of them.Checklist + scopedintervention DB librariesAdd released scoped intervention version # to references inchecklist.Checklist DB librarySave new version of checklist. Checklist DB libraryShared Feature Agile XMLVenueStored checklists contain distilled scoped interventionreferences.Checklist DB library
  56. 56. BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueSQL VenueUser saving with "released" status means release, otherwisesave.Both UI and Web APIcontrollerBoth UI and controller ormodelUser is not allowed to release a new checklist. UI UIWrap multiple write queries into a transaction, rolled back onerror.Checklist service Service/modelGather PubMed citation IDs from scoped intervention outcomemeasurements.Checklist service +checklist DB libraryService/modelAcquire citation contents from PubMed Web API. Checklist service +PubMed serviceServiceTransform (boil down) PubMed citations and store them indatabase.PubMed service +PubMed DB libraryService and maybe DB(XML ingestion)Change status of referenced scoped interventions to "released"and save new versions of them.Checklist + scopedintervention DB librariesService/model and DBAdd released scoped intervention version # to references inchecklist.Checklist DB library Service/modelSave new version of checklist. Checklist DB library Service/model and DBShared Feature Agile XMLVenueSQL VenueStored checklists contain distilled scoped interventionreferences.Checklist DB library Model
  57. 57. BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueSQL VenueUser saving with "released" status means release, otherwisesave.Both UI and Web APIcontrollerBoth UI and controller ormodelUser is not allowed to release a new checklist. UI UIWrap multiple write queries into a transaction, rolled back onerror.Checklist service Service/modelGather PubMed citation IDs from scoped intervention outcomemeasurements.Checklist service +checklist DB libraryService/modelAcquire citation contents from PubMed Web API. Checklist service +PubMed serviceServiceTransform (boil down) PubMed citations and store them indatabase.PubMed service +PubMed DB libraryService and maybe DB(XML ingestion)Change status of referenced scoped interventions to "released"and save new versions of them.Checklist + scopedintervention DB librariesService/model and DBAdd released scoped intervention version # to references inchecklist.Checklist DB library Service/modelSave new version of checklist. Checklist DB library Service/model and DBShared Feature Agile XMLVenueSQL VenueStored checklists contain distilled scoped interventionreferences.Checklist DB library ModelUI
  58. 58. BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueSQL VenueUser saving with "released" status means release, otherwisesave.Both UI and Web APIcontrollerBoth UI and controller ormodelUser is not allowed to release a new checklist. UI UIWrap multiple write queries into a transaction, rolled back onerror.Checklist service Service/modelGather PubMed citation IDs from scoped intervention outcomemeasurements.Checklist service +checklist DB libraryService/modelAcquire citation contents from PubMed Web API. Checklist service +PubMed serviceServiceTransform (boil down) PubMed citations and store them indatabase.PubMed service +PubMed DB libraryService and maybe DB(XML ingestion)Change status of referenced scoped interventions to "released"and save new versions of them.Checklist + scopedintervention DB librariesService/model and DBAdd released scoped intervention version # to references inchecklist.Checklist DB library Service/modelSave new version of checklist. Checklist DB library Service/model and DBShared Feature Agile XMLVenueSQL VenueStored checklists contain distilled scoped interventionreferences.Checklist DB library ModelUIAPP
  59. 59. BREAKING DOWN "CHECKLIST RELEASE"Exclusive Feature Agile XMLVenueSQL VenueUser saving with "released" status means release, otherwisesave.Both UI and Web APIcontrollerBoth UI and controller ormodelUser is not allowed to release a new checklist. UI UIWrap multiple write queries into a transaction, rolled back onerror.Checklist service Service/modelGather PubMed citation IDs from scoped intervention outcomemeasurements.Checklist service +checklist DB libraryService/modelAcquire citation contents from PubMed Web API. Checklist service +PubMed serviceServiceTransform (boil down) PubMed citations and store them indatabase.PubMed service +PubMed DB libraryService and maybe DB(XML ingestion)Change status of referenced scoped interventions to "released"and save new versions of them.Checklist + scopedintervention DB librariesService/model and DBAdd released scoped intervention version # to references inchecklist.Checklist DB library Service/modelSave new version of checklist. Checklist DB library Service/model and DBShared Feature Agile XMLVenueSQL VenueStored checklists contain distilled scoped interventionreferences.Checklist DB library ModelUIAPPDB
  60. 60. Case Study: Clinical Order View
  61. 61. Case Study: Clinical Order Viewchecklistsscopedinterventions etc.XQueryXSLTClient
  62. 62. Case Study: Clinical Order Viewchecklistsscopedinterventions etc.JavaScriptClientWhat if?
  63. 63. Fetching the Datadeclare private function enriched-performance-measure($perfMeasure as node()) {return element performanceMeasure {$perfMeasure/*,/performanceMeasure[fn:normalize-space(id) = fn:normalize-space($perfMeasure/*[fn:local-name() = id])]/abbreviation}};declare private function enriched-impact-threshold($impactThreshold as node()) {return element impactThreshold {$impactThreshold/*,element pubMedCitation {let $citation := /pubMedCitation[fn:normalize-space(id) = fn:normalize-space($impactThreshold/*[fn:local-name() = pubMedId]/text())]return (element title {zpmc:get-article-title($citation)},element journalInfo {zpmc:get-journal-info($citation)},element authorList {zpmc:get-authors-list($citation)})}}};declare function enrich-scoped-intervention($element as element()) as element() {return element { fn:node-name($element) } {$element/@*,for $n in $element/node()return typeswitch ($n)case element(si:performanceMeasure) return enriched-performance-measure($n)case element(si:impactThreshold) return enriched-impact-threshold($n)case element() return enrich-scoped-intervention($n)default return $n}};declare private function produce-enriched-checklist($element as element()) as element() {element { fn:node-name($element) } {$element/@*,for $n in $element/node()return typeswitch ($n)case $siRef as element(scopedIntervention) returnlet $original := zsi:get-scoped-intervention-by-id($siRef/id, $siRef/version/version-id cast as xs:unsignedInt)return zsi:enrich-scoped-intervention($original)case $e as element()return produce-enriched-checklist($e, $fields-to-include)default return $n}};declare function get-checklist($id as xs:string, $version as xs:unsignedInt) {let $uri := checklist-uri-from-id($id)let $doc := c:get-document-with-version-metadata-embedded($uri, $version)return produce-enriched-checklist($doc)};55 Xquery lines1 round trip
  64. 64. Fetching the Datadeclare private function enriched-performance-measure($perfMeasure as node()) {return element performanceMeasure {$perfMeasure/*,/performanceMeasure[fn:normalize-space(id) = fn:normalize-space($perfMeasure/*[fn:local-name() = id])]/abbreviation}};declare private function enriched-impact-threshold($impactThreshold as node()) {return element impactThreshold {$impactThreshold/*,element pubMedCitation {let $citation := /pubMedCitation[fn:normalize-space(id) = fn:normalize-space($impactThreshold/*[fn:local-name() = pubMedId]/text())]return (element title {zpmc:get-article-title($citation)},element journalInfo {zpmc:get-journal-info($citation)},element authorList {zpmc:get-authors-list($citation)})}}};declare function enrich-scoped-intervention($element as element()) as element() {return element { fn:node-name($element) } {$element/@*,for $n in $element/node()return typeswitch ($n)case element(si:performanceMeasure) return enriched-performance-measure($n)case element(si:impactThreshold) return enriched-impact-threshold($n)case element() return enrich-scoped-intervention($n)default return $n}};declare private function produce-enriched-checklist($element as element()) as element() {element { fn:node-name($element) } {$element/@*,for $n in $element/node()return typeswitch ($n)case $siRef as element(scopedIntervention) returnlet $original := zsi:get-scoped-intervention-by-id($siRef/id, $siRef/version/version-id cast as xs:unsignedInt)return zsi:enrich-scoped-intervention($original)case $e as element()return produce-enriched-checklist($e, $fields-to-include)default return $n}};declare function get-checklist($id as xs:string, $version as xs:unsignedInt) {let $uri := checklist-uri-from-id($id)let $doc := c:get-document-with-version-metadata-embedded($uri, $version)return produce-enriched-checklist($doc)};function enrichedScopedIntervention(id) {var si = db.scopedInterventions.findOne({id: id});si.performanceMeasures.forEach(function (pm) {pm.abbreviation = db.performanceMeasures.findOne({id: pm.id}).abbreviation;});si.impactThresholds.forEach(function (th) {var citation = db.pubMedCitations.findOne({id: th.pubMedId})th.pubMedCitation = {title: getArticleTitle(citation),journalInfo: getJournalInfo(citation),authorList: getAuthorList(citation)};});}function getChecklist(id, version) {var checklist = db.checklists.findOne({id: id + _ + version});checklist.groups.forEach(function (group) {for (i = 0; i < group.scopedInterventions.length; ++i) {group.scopedInterventions[i] =enrichedScopedIntervention(group.scopedInterventions[i].id);}});return checklist;}26 JavaScript lines> 200round trips
  65. 65. Generating the View<xsl:template name="intervention"><xsl:param name="intervention-group-key"/><xsl:param name="intervention-name" /><intervention><id><xsl:copy-of select="normalize-space($intervention-group-key)"/></id><displayName><xsl:value-of select="$intervention-name" /></displayName><xsl:copy-of select="current-group()[1]/shouldAvoid"/><hasOutcomes><xsl:value-of select="exists(current-group()/outcomes/outcomeContainer/outcome)" /></hasOutcomes><hasGuidelines><xsl:value-of select="exists(current-group()/guidelines/guideline)" /></hasGuidelines><scopes><xsl:for-each-group select="current-group()"group-by="concat(local:canonicalize-field-value-ids(., careSetting), _, local:canonicalize-field-value-ids(., ageGroup))"><xsl:sort><xsl:variable name="care-setting-names" select="local:canonicalize-field-values-for-sorting(., careSetting)" /><xsl:variable name="age-group-names" select="local:canonicalize-field-values-for-sorting(., ageGroup)" /><xsl:value-of select="concat($care-setting-names, __, $age-group-names)" /></xsl:sort><xsl:variable name="sub-group-key" select="current-grouping-key()"/><scope><xsl:variable name="first-si" select="current-group()[1]"/><ageGroupName><xsl:value-of select="local:format-field-values-for-display($first-si, ageGroup)"/></ageGroupName><careSettingName><xsl:value-of select="local:format-field-values-for-display($first-si, careSetting)"/></careSettingName><id><xsl:value-of select="$intervention-group-key"/><xsl:text>__</xsl:text><xsl:value-of select="$sub-group-key"/></id><scopedInterventions><xsl:for-each select="current-group()"><xsl:copy-of select="." /></xsl:for-each></scopedInterventions></scope></xsl:for-each-group></scopes></intervention></xsl:template>84 linesof XSLT
  66. 66. <xsl:template name="intervention"><xsl:param name="intervention-group-key"/><xsl:param name="intervention-name" /><intervention><id><xsl:copy-of select="normalize-space($intervention-group-key)"/></id><displayName><xsl:value-of select="$intervention-name" /></displayName><xsl:copy-of select="current-group()[1]/shouldAvoid"/><hasOutcomes><xsl:value-of select="exists(current-group()/outcomes/outcomeContainer/outcome)" /></hasOutcomes><hasGuidelines><xsl:value-of select="exists(current-group()/guidelines/guideline)" /></hasGuidelines><scopes><xsl:for-each-group select="current-group()"group-by="concat(local:canonicalize-field-value-ids(., careSetting), _, local:canonicalize-field-value-ids(., ageGroup))"><xsl:sort><xsl:variable name="care-setting-names" select="local:canonicalize-field-values-for-sorting(., careSetting)" /><xsl:variable name="age-group-names" select="local:canonicalize-field-values-for-sorting(., ageGroup)" /><xsl:value-of select="concat($care-setting-names, __, $age-group-names)" /></xsl:sort><xsl:variable name="sub-group-key" select="current-grouping-key()"/><scope><xsl:variable name="first-si" select="current-group()[1]"/><ageGroupName><xsl:value-of select="local:format-field-values-for-display($first-si, ageGroup)"/></ageGroupName><careSettingName><xsl:value-of select="local:format-field-values-for-display($first-si, careSetting)"/></careSettingName><id><xsl:value-of select="$intervention-group-key"/><xsl:text>__</xsl:text><xsl:value-of select="$sub-group-key"/></id><scopedInterventions><xsl:for-each select="current-group()"><xsl:copy-of select="." /></xsl:for-each></scopedInterventions></scope></xsl:for-each-group></scopes></intervention></xsl:template>Generating the Viewfunction makeScopeSubGroups(group, interventionGroupKey) {var result = [];var scopeSubGroups = [];var makePredicate = function (scopedIntervention) {return function (scopeSubGroup) {if (scopeSubGroup.id === makeScopeSubGroupKey(scopedIntervention)) {scopeSubGroup.members.push(scopedIntervention);return true;}else {return false;}}};section.scopedInterventions.forEach(function (si) {if (! scopeSubGroups.some(makePredicate(si))) {scopeSubGroups.push({id: makeScopeSubGroupKey(si),members: [si]});}});scopeSubGroups.sort(function (first, second) {var firstCanonical =canonicalizeFieldValuesForSorting(first.careSettings) + __ +canonicalizeFieldValuesForSorting(first.ageGroups);var secondCanonical =canonicalizeFieldValuesForSorting(second.careSettings) + __ +canonicalizeFieldValuesForSorting(second.ageGroups);return first.localeCompare(second);});scopeSubGroups.forEach(function (subGroup) {var firstSi = subGroup.members[0];var realSubGroup = {ageGroupName: formatFieldValuesForDisplay(firstSi.ageGroups),careSettingName: formatFieldValuesForDisplay(firstSi.careSettings),id: interventionGroupKey + __ + subGroup.id,scopedInterventions: []};subGroup.members.forEach(function (si) {realSubGroup.scopedInterventions.push(si);});result.push(realSubGroup);});return result;}118 lines ofJavaScript
  67. 67. <xsl:with-param name="intervention-group-key"><xsl:text>section-</xsl:text><xsl:value-of select="normalize-space(current-group()[1]/sections/section[1]/id)"/><xsl:text>-intervention-</xsl:text><xsl:value-of select="normalize-space(current-group()[1]/intervention/id)"/></xsl:with-param>var key = "section-" + interventionGroup.members[0].sections[0].id +"-intervention-" + interventionGroup.id;In XSLT, concatenating valueshappens to be wordy:VS.
  68. 68. <xsl:for-each-group select="scopedInterventions/scopedIntervention"group-by="normalize-space(intervention/id)">var result = [];var interventionGroups = [];var makePredicate = function (scopedIntervention) {return function (interventionGroup) {if (interventionGroup.id === scopedIntervention.intervention.id) {interventionGroup.members.push(scopedIntervention);return true;}else {return false;}}};section.scopedInterventions.forEach(function (si) {if (! interventionGroups.some(makePredicate(si))) {interventionGroups.push({id: si.intervention.id,members: [si]});}});interventionGroups.forEach(function (interventionGroup) {var key = "section-" + interventionGroup.members[0].sections[0].id + "-intervention-" + interventionGroup.id;result.push(makeInterventionGroup(interventionGroup.members, key, interventionGroup.members[0].scopedInterventionName));});But JavaScript lackstransformation features like"for-each-group" that reduce realcomplexity:VS.
  69. 69. So, There are Trade-offs• Any XML-based architecture presents aminimum level of friction versus otherdocument NoSQL stacks• The more complex your applications usecases become, the stronger the argumentfor agile XML• Integration with external XML data and/orservices (e.g., HIE) tips the scale
  70. 70. 72 © 2011 Zynx Health Incorporated | The information contained herein is confidential and proprietary to Zynx Health Incorporated and is intended for itsauthorized recipient. Unauthorized review, use, disclosure or distribution is strictly prohibited. All rights reserved.Thank You
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×