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.

From Monolith to Modules - breaking apart a one size fits all product into modules

186 views

Published on



Adobe Experience Manager as the biggest enterprise application built on the Apache Sling stack over the years was built with a monolithic product perspective. Taming the growth over time and tackling upcoming challenges led to a situation were a transition towards a modular product, where large features can be gracefully removed at runtime, becomes unavoidable.

With this talk we want to provide insights on how Adobe uses the available technologies in the stack, extends the stack and transforms the own practices to cut the product in loosely coupled modules with minimal impact on existing consumers. We will be identifying patterns on OSGi, content and scripting side to eliminate and prevent hard wiring and highlight pending challenges and our thoughts on how to resolve that. Last but not least we will share our experience on how such a transition impacts our engineering flow and quality assurance practices.

Published in: Software
  • Be the first to comment

  • Be the first to like this

From Monolith to Modules - breaking apart a one size fits all product into modules

  1. 1. APACHE SLING & FRIENDS TECH MEETUP 2-4 SEPTEMBER 2019 From monolith to modules Dominik Süß, Robert Munteanu, Adobe 1
  2. 2. Welcome 2
  3. 3. About us Dominik Süß Software Engineer Robert Munteanu Senior Computer Scientist 3
  4. 4. Outline Benefits vs cost of modularization Decoupling patterns Tooling support Keeping QA effort under control 4
  5. 5. Modularisation 5
  6. 6. Benefits SlimmerSlimmerSlimmerSlimmerSlimmer SimplerSimplerSimplerSimplerSimpler Reduced impact of bugsReduced impact of bugsReduced impact of bugsReduced impact of bugsReduced impact of bugs Clear dependenciesClear dependenciesClear dependenciesClear dependenciesClear dependencies Decoupled module lifecyclesDecoupled module lifecyclesDecoupled module lifecyclesDecoupled module lifecyclesDecoupled module lifecycles 6
  7. 7. Costs Complexity of API GovernanceComplexity of API GovernanceComplexity of API GovernanceComplexity of API GovernanceComplexity of API Governance Planning & Testing for absence of modulesPlanning & Testing for absence of modulesPlanning & Testing for absence of modulesPlanning & Testing for absence of modulesPlanning & Testing for absence of modules Complexity & Fragmentation of deployment &Complexity & Fragmentation of deployment &Complexity & Fragmentation of deployment &Complexity & Fragmentation of deployment &Complexity & Fragmentation of deployment & maintenance proceduresmaintenance proceduresmaintenance proceduresmaintenance proceduresmaintenance procedures Additional aspect to development flow & toolingAdditional aspect to development flow & toolingAdditional aspect to development flow & toolingAdditional aspect to development flow & toolingAdditional aspect to development flow & tooling 7
  8. 8. We need a plan... Global API to modularized APIGlobal API to modularized APIGlobal API to modularized APIGlobal API to modularized APIGlobal API to modularized API Extend & integrate toolingExtend & integrate toolingExtend & integrate toolingExtend & integrate toolingExtend & integrate tooling Start cuttingStart cuttingStart cuttingStart cuttingStart cutting 8
  9. 9. Decoupling patterns - OSGi 9
  10. 10. Glue bundles Billing MessagingBilling Messages 10
  11. 11. Glue bundles  Encapsulates the dependencies  Refactoring to a glue bundle can be difficult  Glue bundles need to be explicitly deployed when needed 11
  12. 12. Optional dependencies <Import-Package> com.example.billing.api;resolution:=optional ,* <Import-Package> 12
  13. 13. Optional dependencies @Component(enabled=false) public class MyComponent { /* ... */ } @Component public class MyComponentStarter { protected void activate(ComponentContext ctx) { try { log.info("Found class {}", BarImpl.class); ctx.enableComponent(MyComponent.class.getName()); } catch ( Throwable t) { log.info("Foo component unavailable due to missing Bar module", t); } } } 13
  14. 14. Optional dependencies  Minimal impact on existing code bases  Unnatural pattern to prevent ERROR log entries  Indicator of low cohesion 14
  15. 15. Overlays public interface Foo { } @Component public class MyConsumer { @Reference(policyOption = ReferencePolicyOption.GREEDY) private Foo foo; } @Component // default service.ranking of 0 public class DefaultFooImpl implements Foo { } @Component(property = { Constants.SERVICE_RANKING +":Integer=100" }) public class MyBetterFooImpl implements Foo { } 15
  16. 16. Overlays  Simple and well-understood mechanism of overriding service references  Requires consumers to mark references as greedy  Service ranking are complicated to manage for large numbers of implementations 16
  17. 17. Feature extraction 17
  18. 18. Feature extraction  Usually cleans up incorrect layering  Dependencies can spiral out of control 18
  19. 19. Decoupling patterns - content 19
  20. 20. Glue components private static final RenderCondition INSTANCE = new RenderCondition() { @Override public boolean check() { try { new Handlebars(); return true; } catch (NoClassDefFoundError e) { return false; } } }; 20
  21. 21. Glue components  Minimal impact on existing code bases  Established AEM pattern  Pushes modularity at the class, instead of the bundle level 21
  22. 22. Overlays <execute jcr:primaryType="nt:unstructured" sling:resourceType="some/workflow/step"> <executor jcr:primaryType="nt:unstructured" className="com.adobe.foreign.module.ExecutorImpl"/> </execute> 22
  23. 23. Overlays  Minimal impact on existing code bases  Can lead to surprising behaviour at runtime 23
  24. 24. Decoupling patterns - generic 24
  25. 25. Inlining Rule of three → write, duplicate, refactor Code duplication is a smell, not a crime Refactoring and abstractions are costly 25
  26. 26. Decoupling patterns - generic 26
  27. 27. Moving checks at build time Build time  Test Time  Run Time [ERROR] Bundle org.apache.sling.caconfig.spi:1.3.4 is importing package(s) org.apache.sling.api.resource in start level 20 but no bundle is exporting these for that start level. 27
  28. 28. Potential areas for extension Validate content-package Java imports are satisfied Generate constraints for discovered workflow steps 28
  29. 29. Modularised testing 29
  30. 30. Modularised testing Combinatorial nightmareCombinatorial nightmareCombinatorial nightmareCombinatorial nightmareCombinatorial nightmare Optimize CI/CD pipeline to act on module levelOptimize CI/CD pipeline to act on module levelOptimize CI/CD pipeline to act on module levelOptimize CI/CD pipeline to act on module levelOptimize CI/CD pipeline to act on module level 30
  31. 31. Summary 31
  32. 32. Impact of AEM modularisation  Reduced API surface  Faster install and startup times  Lower memory usage  Reduced disk footprint  More complex development and testing scenarios 32

×