Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Weiterentwicklung von APIs inder Praxis

114 views

Published on

Wenn ein API erst einmal live ist, ist es nicht mehr so einfach, es zu ändern. Doch jede noch so gut definierte Schnittstelle kommt irgendwann an den Punkt, an dem sie weiterentwickelt werden muss; sei es nur, weil sich die Anforderungen geändert haben. Dann stellt sich die Frage, ob die Schnittstelle abwärtskompatibel weiterentwickelt werden kann oder ob eine neue Version gebaut werden muss. Wie muss sich dann der Client verhalten, damit er weiter funktioniert? Neben den technischen Herausforderungen, die zu meistern sind, stellt diese Session aus der Praxiserfahrung heraus vor, welche Konzepte in Entwicklung, Dokumentation und Deployment verwendet werden können, um client- und serverseitig nicht in der Versionshölle zu landen.

Published in: Software
  • Be the first to comment

  • Be the first to like this

Weiterentwicklung von APIs inder Praxis

  1. 1. @ArneLimburg @_openknowledge #WISSENTEILEN Weiterentwicklung von APIs in der Praxis
  2. 2. ÜBER MICH • Enterprise Architect bei der OPEN KNOWLEDGE GmbH • Themen • Microservices • APIs • Architektur • Technologie (Java EE) Arne Limburg
  3. 3. @ArneLimburg @_openknowledge #WISSENTEILEN Code First
  4. 4. @ArneLimburg @_openknowledge #WISSENTEILEN API First
  5. 5. @ArneLimburg @_openknowledge #WISSENTEILEN Breaking Change à Neue Version Version 1
  6. 6. Wie implementiere ich möglichst einfach eine neue Version?
  7. 7. KLASSISCHE ARCHITEKTUR Business Frontend Client
  8. 8. VERSCHIEDENE MODELLE Mapping Schnittstelle
  9. 9. ATTRIBUT-ÄNDERUNG Mapping Schnittstelle
  10. 10. BREAKING CHANGE Mapping Schnittstelle
  11. 11. Schnittstelle DTO-SCHICHT TO THE RESCUE? Mapping
  12. 12. DTO-SCHICHT TO THE RESCUE? Mapping Mapping
  13. 13. DTO-SCHICHT TO THE RESCUE? Mapping
  14. 14. JEDER VERSION IHRE DTO-SCHICHT Mapping Mapping
  15. 15. @ArneLimburg @_openknowledge #WISSENTEILEN Mapping-Schichten sind das Tor zur Versionierungshölle
  16. 16. KLASSISCHE ARCHITEKTUR Database Business Frontend
  17. 17. KLASSISCHE ARCHITEKTUR Database Business Frontend OR-Mapping DTO-Mapping JSON-Mapping
  18. 18. VIER MODELLE OR-Mapping DTO-Mapping JSON-Mapping { "parent": {...} ...}
  19. 19. { "parent": {...} ...}
  20. 20. VERSCHIEDENE MODELLE Mapping Schnittstelle
  21. 21. ATTRIBUT-ÄNDERUNG Mapping Schnittstelle
  22. 22. Schnittstelle JUST ANOTHER DTO-LAYER Mapping
  23. 23. JUST ANOTHER DTO-LAYER Mapping Mapping
  24. 24. JUST ANOTHER DTO-LAYER Mapping
  25. 25. JEDEM CLIENT SEINE SCHNITTSTELLE Mapping Mapping
  26. 26. JEDEM CLIENT SEINE SCHNITTSTELLE Mapping Mapping Mapping Mapping
  27. 27. @ArneLimburg @_openknowledge #WISSENTEILEN Willkommen in der Versionierungshölle
  28. 28. VERSCHIEDENE SCHNITTSTELLEN Mapping Mapping Mapping Mapping
  29. 29. VERSCHIEDENE SCHNITTSTELLEN Mapping Mapping Mapping Mapping
  30. 30. How to escape from Versioning Hell?
  31. 31. ABWÄRTSKOMPATIBILITÄT Mapping Schnittstelle
  32. 32. Tolerant Reader Pattern Tolerant gegenüber unbekannten Feldern Umgang mit x-extensible-enum http://zalando.github.io/restful-api-guidelines
  33. 33. EXKURS X-EXTENSIBLE-ENUM Beispiel address_type: type: string x-extensible-enum: - private - business
  34. 34. Tolerant Reader Pattern Tolerant gegenüber unbekannten Feldern Umgang mit x-extensible-enum http://zalando.github.io/restful-api-guidelines Tolerant gegenüber unbekannten Statuscodes HTTP Status 301 folgen
  35. 35. TOLERANT READER PATTERN http://www.example.com/addresses/42 àLiefert Addresse { street: { "name": "Poststraße", "number": "1", }, "city": "26122 Oldenburg" }
  36. 36. TOLERANT READER PATTERN http://www.example.com/addresses/42 Attribut hinzufügen { street: { "name": "Poststraße", "number": "1", "additionalAdressLine": "2. Obergeschoss" }, "city": "26122 Oldenburg" }
  37. 37. TOLERANT READER PATTERN Server schickt { street: { "name": "Poststraße", "number": "1", "additionalAdressLine": "2. Obergeschoss" }... } http://www.example.com/addresses/42 Client erwartet { street: { "name": "Poststraße", "number": "1", }... }
  38. 38. TOLERANT READER PATTERN http://www.example.com/addresses/42 Attribut-Umbenennung { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", }, "city": "26122 Oldenburg" }
  39. 39. TOLERANT READER PATTERN http://www.example.com/addresses/42 àAbwärtskompatible Änderungen: Umbenennen durch Kopieren { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", }, "city": "26122 Oldenburg" }
  40. 40. Und was ist, wenn der Client kein Tolerant Reader ist?
  41. 41. PROJEKTIONEN // Client kann entscheiden, welche Felder er bekommen möchte // Facebook Style GET /addresses/3?fields=street,city GET /addresses/3?fields=street.name,street.number,city // LinkedIn Style GET /addresses/3?fields=street:(name,number),city
  42. 42. OK, so soll sich der Client verhalten. Aber was ist mit dem Server?
  43. 43. Photo by Irene Fertik, USC News Service. Copyright 1994, USC. „Be conservative in what you do, Be liberal in what you accept from others“ RFC 793, Robustness Principal (John Postel)
  44. 44. Es darf nichts entfernt werden Keine Veränderung von Verarbeitungsregel Optionales darf nie Required werden http://zalando.github.io/restful-api-guidelines Alles was hinzugefügt wird, muss optional sein
  45. 45. MAGNANIMOUS WRITER PATTERN Server schickt { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1“ }... } http://www.example.com/addresses/42 Client erwartet { street: { "name": "Poststraße", "number": "1", }... } http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
  46. 46. MAGNANIMOUS WRITER PATTERN Server schickt { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1“ }... } http://www.example.com/addresses/42 Client erwartet { street: { "streetName": "Poststraße", "houseNumber": "1", }... } http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
  47. 47. MAGNANIMOUS WRITER PATTERN Server erwartet PUT http://www.example.com/addresses/42 Client schickt { street: { "name": "Poststraße", "number": "1", }... } http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
  48. 48. MAGNANIMOUS WRITER PATTERN PUT http://www.example.com/addresses/42 Client schickt { street: { "name": "Poststraße", "number": "1", }... } http://tenderware.blogspot.de/2011/05/magnanimous-writer.html Server erwartet { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1“ }... } oder oder
  49. 49. MAGNANIMOUS WRITER PATTERN PUT http://www.example.com/addresses/42 Client schickt { street: { "streetName": "Poststraße", "houseNumber": "1", }... } http://tenderware.blogspot.de/2011/05/magnanimous-writer.html Server erwartet { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1“ }... } oder oder
  50. 50. MAGNANIMOUS WRITER UND XML http://www.example.com/.../street àAbwärtskompatible Änderungen <street> <name>Poststraße</name> <houseNumber>0815</...> </customer> <xs:schema xmlns:xs:="..."> <xs:complexType name="streetType"> <xs:sequence> ... <xs:element name="houseNumber" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:schema>
  51. 51. MAGNANIMOUS WRITER UND XML http://www.example.com/.../street àAbwärtskompatible Änderungen àVersion 1.1 <customer> <name>Max Mustermann</name> <houseNumber>0815</...> <number>0815</number> </customer> <xs:sequence> ... <xs:element ... name="houseNumber“ minOccurs="0"/> <xs:element ... name="number“ minOccurs="0"/> </xs:sequence>
  52. 52. MAGNANIMOUS WRITER UND XML http://www.example.com/.../street àAbwärtskompatible Änderungen àVersion 1.1 <customer> <name>Max Mustermann</name> <houseNumber>0815</...> <number>0815</number> </customer> <xs:sequence> ... <xs:element ... name="houseNumber“ minOccurs="0"/> <xs:element ... name="number“ minOccurs="0"/> <xs:any minOccurs="0"/> <xs:anyAttribute processContents="lax"/>
  53. 53. MAGNANIMOUS WRITER UND XML àOffizieller Versionssupport seit XML-Schema 1.1 <schema ... xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"> <complexType name="street" vc:maxVersion="1.3"> ... </complexType> <complexType name="street" vc:minVersion="2.0"> ... </complexType> </schema>
  54. 54. MAGNANIMOUS WRITER UND JAVA public String getName() { return getStreetName(); } public void setName(String name) { setStreetName(name); }
  55. 55. PUT UND NULL VALUES public String getName() { return getStreetName(); } public void setName(String name) { setStreetName(name); }
  56. 56. MERGE PATCH UND NULL VALUES PATCH /addresses/42 HTTP/1.1 Content-Type: application/merge-patch+json Client schickt { street: { "name": null, }... } https://tools.ietf.org/html/rfc7396
  57. 57. MERGE PATCH UND NULL VALUES public class Street { private String streetName; private String streetNumber; public void setName(String name) { setStreetName(... public void setNumber(String number) { setStreetNum... } Wird mit null aufgerufen Wird gar nicht aufgerufen
  58. 58. MERGE PATCH UND NULL VALUES public class Street { private String streetName; // = null private String streetNumber; // = null public void setName(String name) { setStreetName(... public void setNumber(String number) { setStreetNum... }
  59. 59. MERGE PATCH UND NULL VALUES public class Street { private String streetName; // = null private String streetNumber; // = null public void setName(String name) { setStreetName(... public void setNumber(String number) { setStreetNum... } Simple Solution: Don‘t use PATCH at all
  60. 60. MERGE PATCH UND NULL VALUES public class Street { private String streetName; // = null private String streetNumber; // = null public void setName(String name) { setStreetName(... public void setNumber(String number) { setStreetNum... } Advanced Solution: Use initial values
  61. 61. MERGE PATCH UND NULL VALUES public class Street { private String streetName = "<initial value>"; private String streetNumber = "<initial value>"; public void setName(String name) { setStreetName(... public void setNumber(String number) { setStreetNum... }
  62. 62. MERGE PATCH UND NULL VALUES public class Street { private String streetName = "<initial value>"; private String streetNumber = "<initial value>"; public void setName(String name) { setStreetName(... public void setNumber(String number) { setStreetNum... } Wird mit null aufgerufen Wird gar nicht aufgerufen
  63. 63. MERGE PATCH UND NULL VALUES public class Street { private String streetName; // = null private String streetNumber = "<initial value>"; public void setName(String name) { setStreetName(... public void setNumber(String number) { setStreetNum... } Wird mit null aufgerufen Wird gar nicht aufgerufen
  64. 64. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àAbwärtskompatible Änderungen: Umbenennen durch Kopieren { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", }, "city": "26122 Oldenburg" } Geht da noch mehr?
  65. 65. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àZusammenführen und Teilen von Attributen { street: { ... "streetName": "Poststraße", "houseNumber": "1", "addressLine1": "Poststraße 1", } ... }
  66. 66. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àHerausforderungen: Zusammenführen von Attributen { street: { ... "streetName": "Poststraße", "houseNumber": "1", "addressLine1": "Poststraße 1", } ... }
  67. 67. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àHerausforderungen: Teilen von Attributen { street: { ... "addressLine1": "Poststraße 1", } "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg" }
  68. 68. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àHerausforderungen: Ebene von Attributen ändern { street: { ... "addressLine1": "Poststraße 1" } "addressLine1": "Poststraße 1", ... }
  69. 69. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àHerausforderungen: Ebene von Attributen ändern { ... "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } }
  70. 70. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àHerausforderungen: Ebene von Attributen ändern { ... "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } } Bei jeder Modelländerung muss eine Migrationsstrategie einbezogen werden!
  71. 71. ABWÄRTSKOMPATIBILITÄT public String getCity() { return getZipCode() + " " + getCityName(); } public void setCity(String city) { setZipCode(city.substring(0, 5)); setCityName(city.substring(5).trim()); }
  72. 72. Was ist daran jetzt besser als an einer Mapping-Schicht?
  73. 73. Migrations-Strategie für jede Attributänderung Migrations-Regeln im Objekt
  74. 74. ABWÄRTSKOMPATIBILITÄT { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" } "addressLine1": "Poststraße 1", "addressLine2": "", "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } } http://www.example.com/v1/addresses/42 àBisher nur abwärtskompatible Änderungen
  75. 75. ABWÄRTSKOMPATIBILITÄT { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" } "addressLine1": "Poststraße 1", "addressLine2": "", "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } } http://www.example.com/v1/addresses/42 àViele Attribute deprecated
  76. 76. Wie kann ich Attribute entfernen?
  77. 77. Incompatible Change vs. Breaking Change http://zalando.github.io/restful-api-guidelines
  78. 78. WELCHE CLIENTS NUTZEN MICH?
  79. 79. API (PROVIDER CONTRACT)
  80. 80. CONSUMER CONTRACT
  81. 81. CONSUMER CONTRACT – YAGNI
  82. 82. CONSUMER-DRIVEN CONTRACT TEST Consumer Contract Consumer Provider Consumer Tests Provider Tests
  83. 83. PIPELINE TO DEPLOY TO STAGE Execute Own Provider Tests Generate Consumer Contract Execute Depending Provider Tests Deploy to Stage
  84. 84. PIPELINE TO DEPLOY TO STAGE Execute Own Provider Tests Generate Consumer Contract Execute Depending Provider Tests Deploy to Stage Achtung: Abwärtskompatibilität ist trotzdem notwendig!
  85. 85. BREAKING CHANGE VOM PROVIDER Execute Own Provider Tests Generate Consumer Contract Execute Depending Provider Tests Deploy to Stage
  86. 86. BREAKING CHANGE VOM CONSUMER Execute Own Provider Tests Generate Consumer Contract Execute Depending Provider Tests Deploy to Stage
  87. 87. Und wenn ich meine Consumer nicht kenne?
  88. 88. VERSIONSSPRUNG { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" } "addressLine1": "Poststraße 1", "addressLine2": "", "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } } http://www.example.com/v1/addresses/42 àBisher nur abwärtskompatible Änderungen
  89. 89. INKOMPATIBLE ÄNDERUNG http://www.example.com/v2/addresses/42 àVersionssprung { "addressLine1": "Poststraße 1", "addressLine2": "", "location": { "zipCode": "26122", "cityName": "Oldenburg" } }
  90. 90. INKOMPATIBLE ÄNDERUNG
  91. 91. Version 2.0 ist nur inkompatibel zu 1.0! Version 2.0 ist identisch zu 1.x! Das erleichtert das Mapping zwischen den Versionen!
  92. 92. Ein solcher Versionssprung ist nicht anforderungsgetrieben, sondern viel besser und langfristiger planbar
  93. 93. Wenn eine neue Version nicht auf die alte abbildbar ist, ist es keine neue Version, sondern eine neue Schnittstelle!
  94. 94. • Über URL-Pfad /v2/addresses • Über Query-Parameter /addresses?version=v2 • Über Version-Header X-Api-Version: v2 • Über Version-Attribut am Media-Type application/xml;version=v2 • Über Media-Type application/vnd.de.openknowledge+v2+json ERMITTELN DER VERSION
  95. 95. ABWÄRTSKOMPATIBILITÄT Schnittstelle Schnittstelle { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" } "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "addressLine1": "Poststraße 1", "addressLine2": "", "location": { "zipCode": "26122", "cityName": "Oldenburg" } } { "addressLine1": "Poststraße 1", "addressLine2": "“, "location": { "zipCode": "26122", "cityName": "Oldenburg" } } V1 V2-SNAPSHOT
  96. 96. ABWÄRTSKOMPATIBILITÄT Schnittstelle Schnittstelle { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" }, "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "addressLine1": "Poststraße 1", "addressLine2": "“, "location": { "zipCode": "26122", "cityName": "Oldenburg" } } { "addressLine1": "Poststraße 1", "addressLine2": "", "location": { "zipCode": "26122", "cityName": "Oldenburg" } } V1 V2-SNAPSHOT
  97. 97. AUTOMATISIERTES MAPPING Schnittstelle Schnittstelle { "street": { "name": "Poststraße", "number": "1", }, "city": "26122 Oldenburg" } { "street": { "name": "Poststraße", "number": "1" }, "city": "26122 Oldenburg" } V1 V2-SNAPSHOT
  98. 98. WEITERENTWICKLUNG Schnittstelle Schnittstelle { "street": { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", }, "city": "26122 Oldenburg" } { "street": { "streetName": "Poststraße", "houseNumber": "1" }, "city": "26122 Oldenburg" } V1 V2-SNAPSHOT
  99. 99. WEITERENTWICKLUNG Schnittstelle Schnittstelle { "street": { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" }, "city": "26122 Oldenburg" } { "street": { "addressLine1": "Post… 1", "addressLine2": "" }, "city": "26122 Oldenburg" } V1 V2-SNAPSHOT
  100. 100. WEITERENTWICKLUNG Schnittstelle Schnittstelle { "street": { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" }, "addressLine1": "Poststraße 1", "addressLine2": "", "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", } { "addressLine1": "Poststraße 1", "addressLine2": "", "zipCode": "26122", "cityName": "Oldenburg" } V1 V2-SNAPSHOT
  101. 101. WEITERENTWICKLUNG Schnittstelle Schnittstelle { "street": { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" }, "addressLine1": "Poststraße 1", "addressLine2": "", "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } } { "addressLine1": "Poststraße 1", "addressLine2": "", "location": { "zipCode": "26122", "cityName": "Oldenburg" } } V1 V2-SNAPSHOT
  102. 102. ABWÄRTSKOMPATIBILITÄT Schnittstelle Schnittstelle { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" }, "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "addressLine1": "Poststraße 1", "addressLine2": "“, "location": { "zipCode": "26122", "cityName": "Oldenburg" } } { "addressLine1": "Poststraße 1", "addressLine2": "", "location": { "zipCode": "26122", "cityName": "Oldenburg" }, "city": { "zipCode": "26122", "cityName": "Oldenburg" } } V1 V2-SNAPSHOT
  103. 103. ABWÄRTSKOMPATIBILITÄT Schnittstelle Schnittstelle { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" } ... } { "addressLine1": "Poststraße 1", "addressLine2": "", "location": { "zipCode": "26122", "cityName": "Oldenburg" } } V1 V3-SNAPSHOT Schnittstelle { "addressLine1": "Poststraße 1", "addressLine2": "“, "location": { "zipCode": "26122", "cityName": "Oldenburg" } } V2
  104. 104. ABWÄRTSKOMPATIBILITÄT Schnittstelle Schnittstelle { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" } ... } { "addressLine1": "Poststraße 1", "addressLine2": "", "city": { "zipCode": "26122", "cityName": "Oldenburg" } } V1 V3-SNAPSHOT Schnittstelle { "addressLine1": "Poststraße 1", "addressLine2": "“, "location": { "zipCode": "26122", "cityName": "Oldenburg" }, "city": { "zipCode": "26122", "cityName": "Oldenburg" }} V2
  105. 105. Migrations-Strategie für jede Attributänderung Migrations-Regeln im Objekt Mapping zwischen Objekten immer 1:1 Code unabhängig
  106. 106. FAZIT Schnittstelle Schnittstelle { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" } ... } { "addressLine1": "Poststraße 1", "addressLine2": "", "city": { "zipCode": "26122", "cityName": "Oldenburg" } } V1 V3-SNAPSHOT Schnittstelle { "addressLine1": "Poststraße 1", "addressLine2": "“, "location": { "zipCode": "26122", "cityName": "Oldenburg" }, "city": { "zipCode": "26122", "cityName": "Oldenburg" }} V2 Behalte alte Versionen
  107. 107. FAZIT Schnittstelle Schnittstelle { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" } ... } { "addressLine1": "Poststraße 1", "addressLine2": "", "city": { "zipCode": "26122", "cityName": "Oldenburg" } } V1 V3-SNAPSHOT Schnittstelle { "addressLine1": "Poststraße 1", "addressLine2": "“, "location": { "zipCode": "26122", "cityName": "Oldenburg" }, "city": { "zipCode": "26122", "cityName": "Oldenburg" }} V2 Behalte alte Versionen Plane neue Versionen Don‘t break the Client Keine Mapping-Schichten
  108. 108. FRAGEN & DISKUSSION ? ? ?
  109. 109. KONTAKT Arne Limburg, Software Architekt OFFENKUNDIGGUT arne.limburg@openknowledge.de +49 (0)441 4082 – 0 / 154 Icons in this presentation designed by “Freepik”, “Nice and Serious” and “Elegant Themes” from www.flaticon.com Photos in this presentation are from pixabay.com

×