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.

Architecting well-structured Java applications

5,867 views

Published on

Software developers spend most of their time working with code on literal level. Unfortunately, vast amount of design flaws hides behind hundreds of interrelated packages, classes and methods, destroying your system deliberately. In this talk will supply you with knowledge necessary to manage complexity of your logical design from theoretical, practical and tooling perspectives. Time to keep architecture in predictable and manageable state!

Published in: Software

Architecting well-structured Java applications

  1. 1. ARCHITECTING WELL-STRUCTURED JAVA APPLICATIONS Eduards Sizovs @eduardsi
  2. 2. MOST APPS BEGIN LIFE SMALL AND NEAT.
  3. 3. TIME GOES BY...
  4. 4. HELLO. I AM YOUR ROTTING ENTERPRISE APP.
  5. 5. - RIGIDITY - FRAGILITY - IMMOBILITY - VISCOSITY - OPACITY - NEEDLESS COMPLEXITY - NEEDLESS REPITITION SMELLING SYMPTOMS ->
  6. 6. HIBERNATE CORE V4.3.8.FINAL
  7. 7. JDK V1.7.0_51
  8. 8. A JDK CODE BASE IS DEEPLY INTERCONNECTED AT BOTH THE API AND THE IMPLEMENTATION LEVELS, HAVING BEEN BUILT OVER MANY YEARS PRIMARILY IN THE STYLE OF A MONOLITHIC SOFTWARE SYSTEM. WE’VE SPENT CONSIDERABLE EFFORT ELIMINATING OR AT LEAST SIMPLIFYING AS MANY API AND IMPLEMENTATION DEPENDENCES AS POSSIBLE, SO THAT BOTH THE PLATFORM AND ITS IMPLEMENTATIONS CAN BE PRESENTED AS A COHERENT SET OF INTERDEPENDENT MODULES, BUT SOME PARTICULARLY THORNY CASES REMAIN. (C) MARK REINHOLDS, CHIEF ARCHITECT OF THE JAVA PLATFORM
  9. 9. SPRING V4.1.6
  10. 10. PRINCIPLES.
  11. 11. PACKAGE IS THE FIRST-CLASS CITIZEN AND KEY ELEMENT OF LOGICAL DESIGN.
  12. 12. TREAT PACKAGES AS A HIERARCHY EVEN IF THEY’RE REPRESENTED FLAT.
  13. 13. io.shwitter.user io.shwitter.user.registration io.shwitter.user.profile io.shwitter.timeline  
  14. 14. io.shwitter.user (part of) io.shwitter.user.registration io.shwitter.user.profile io.shwitter.timeline  
  15. 15. io.shwitter.user io.shwitter.user.registration (part of) io.shwitter.user.profile io.shwitter.timeline  
  16. 16. io.shwitter.user io.shwitter.user.registration io.shwitter.user.profile (part of) io.shwitter.timeline  
  17. 17. io.shwitter.user io.shwitter.user.registration io.shwitter.user.profile io.shwitter.timeline (part of)  
  18. 18. USE PACKAGES TO GROUP FUNCTIONALLY- RELATED ARTIFACTS. DO NOT GROUP ARTIFACTS THAT DO THE SAME THING, BUT ARE DIFFERENT BY NATURE.
  19. 19. io.shwitter.controller io.shwitter.dao io.shwitter.domain io.shwitter.services io.shwitter.exceptions
  20. 20. io.shwitter.controller io.shwitter.dao io.shwitter.domain io.shwitter.services io.shwitter.exceptions io.shwitter.user io.shwitter.user.registration io.shwitter.user.profile io.shwitter.timeline  
  21. 21. - ABILITY TO DISTRIBUTE YOUR LAYERS OVER MULTIPLE PHYSICAL TIERS (HA-HA)
  22. 22. - ABILITY TO DISTRIBUTE YOUR LAYERS OVER MULTIPLE PHYSICAL TIERS (HA-HA) - DECOUPLING / ABSTRACTING FOR EXHANGEABILITY (HA-HA)
  23. 23. - ABILITY TO DISTRIBUTE YOUR LAYERS OVER MULTIPLE PHYSICAL TIERS (HA-HA) - DECOUPLING / ABSTRACTING FOR EXHANGEABILITY (HA-HA) - DECOUPLING / ABSTRACTING FOR INDEPENDENT EVOLUTION (HA-HA)
  24. 24. - ABILITY TO DISTRIBUTE YOUR LAYERS OVER MULTIPLE PHYSICAL TIERS (HA-HA) - DECOUPLING / ABSTRACTING FOR EXHANGEABILITY (HA-HA) - DECOUPLING / ABSTRACTING FOR INDEPENDENT EVOLUTION (HA-HA) - DECOUPLING FOR REUSE (HA-HA)
  25. 25. - ABILITY TO DISTRIBUTE YOUR LAYERS OVER MULTIPLE PHYSICAL TIERS (HA-HA) - DECOUPLING / ABSTRACTING FOR EXHANGEABILITY (HA-HA) - DECOUPLING / ABSTRACTING FOR INDEPENDENT EVOLUTION (HA-HA) - DECOUPLING FOR REUSE (HA-HA) - SEPARATION OF CONCERNS (IS PARTICULAR LAYER OUR CONCERN?)
  26. 26. - ABILITY TO DISTRIBUTE YOUR LAYERS OVER MULTIPLE PHYSICAL TIERS (HA-HA) - DECOUPLING / ABSTRACTING FOR EXHANGEABILITY (HA-HA) - DECOUPLING / ABSTRACTING FOR INDEPENDENT EVOLUTION (HA-HA) - DECOUPLING FOR REUSE (HA-HA) - SEPARATION OF CONCERNS (IS PARTICULAR LAYER OUR CONCERN?) - RELATED STUFF CO-LOCATION (ARE DAOS REALLY RELATED?)
  27. 27. - ABILITY TO DISTRIBUTE YOUR LAYERS OVER MULTIPLE PHYSICAL TIERS (HA-HA) - DECOUPLING / ABSTRACTING FOR EXHANGEABILITY (HA-HA) - DECOUPLING / ABSTRACTING FOR INDEPENDENT EVOLUTION (HA-HA) - DECOUPLING FOR REUSE (HA-HA) - SEPARATION OF CONCERNS (IS PARTICULAR LAYER OUR CONCERN?) - RELATED STUFF CO-LOCATION (ARE DAOS REALLY RELATED?) - CONSTRAINT ENFORCEMENT (IS THERE A BETTER WAY?)
  28. 28. APPLY SERVICE-ORIENTED MINDSET TO SOFTWARE STRUCTURE.
  29. 29. LAYERING IS YOUR SERVICE'S DETAIL AND IS INTERNAL TO THE SERVICE.
  30. 30. GROUP TIGHTLY COUPLED CLASSES TOGETHER. IF CLASSES THAT CHANGE TOGETHER ARE IN THE SAME PACKAGE, THEN THE IMPACT OF CHANGE IS LOCALIZED. - THE COMMON CLOSURE PRINCIPLE
  31. 31. MAKE PACKAGES HIGHLY COHESIVE BY FOLLOWING SINGLE RESPONSIBILITY PRINCIPLE.
  32. 32. io.shwitter.user.registration io.shwitter.user.notifications io.shwitter.user.profile io.shwitter.user.profile.blocking
  33. 33. io.shwitter.user.registration io.shwitter.user.notifications io.shwitter.user.profile io.shwitter.user.profile.blocking io.shwitter.user :(  
  34. 34. KEEP PACKAGES LOOSELY COUPLED, IDEALLY – COMPLETELY INDEPENDENT. REFLECTION DOESN’T COUNT.
  35. 35. package io.shwitter.user @Entity class User { // name, password etc. } package io.shwitter.timeline @Entity class Timeline { @OneToOne User user; }
  36. 36. package io.shwitter.user @Embeddable class UserId { Long value; } package io.shwitter.timeline @Entity class Timeline { @Embedded UserId userId; }
  37. 37. PROVIDE SLIM PACKAGE INTERFACE AND HIDE IMPLEMENTATION DETAILS.
  38. 38. AVOID DEPENDENCY MAGNETS. SOMETIMES DUPLICATION IS NOT THAT EVIL.
  39. 39. MANAGE RELATIONSHIPS. EVERY DEPENDENCY ARROW HAS A REASON.
  40. 40. FINDBUGS V1.0 - A GREAT START
  41. 41. FINDBUGS V1.1 – IMPERFECTION CREEPS IN
  42. 42. FINDBUGS V1.2 – IMPERFECTION TAKES HOLD
  43. 43. FINDBUGS V1.3 – CHAOS BEGINS
  44. 44. FINDBUGS V1.4 – EXPLOSION
  45. 45. THE DEPENDENCIES BETWEEN PACKAGES MUST NOT FORM CYCLES. BURN BI- DIRECTIONAL DEPENDENCES IN FIRE.
  46. 46. HOW?
  47. 47. MERGING package io.shwitter.user class User { void register(RegistrationNotifier notifier) {} } package io.shwitter.user.notify class RegistrationNotifier { void notify(User user) {} }
  48. 48. MERGING - REPACKAGING package io.shwitter.user class User { void register(RegistrationNotifier notifier) {} } class RegistrationNotifier { void notify(User user) {} }
  49. 49. DEPENDENCY INVERSION package io.shwitter.user class User { void register(RegistrationNotifier notifier) {} } package io.shwitter.user.notify class RegistrationNotifier { void notify(User user) {} }
  50. 50. DEPENDENCY INVERSION - REFACTORING STEP 1 package io.shwitter.user class User { void register(RegistrationNotifier notifier) {} } package io.shwitter.user.notify class RegistrationNotifier implements UserNotifier { void notify(User user) {} } interface UserNotifier { void notify(User user) {} }
  51. 51. DEPENDENCY INVERSION - REFACTORING STEP 2 package io.shwitter.user class User { void register(UserNotifier notifier) {} } package io.shwitter.user.notify class RegistrationNotifier implements UserNotifier { void notify(User user) {} } interface UserNotifier { void notify(User user) {} }
  52. 52. DEPENDENCY INVERSION - REFACTORING STEP 3 package io.shwitter.user class User { void register(UserNotifier notifier) {} } interface UserNotifier { void notify(User user) {} } package io.shwitter.user.notify class RegistrationNotifier implements UserNotifier { void notify(User user) {} }
  53. 53. ESCALATION package io.shwitter.user class User { void register(Notifier n) { n.notify(this); } } package io.shwitter.user.notify class Notifier { void notify(User user) { sendEmailTo(user.email()); } }
  54. 54. ESCALATION - REFACTORING STEP 1 package io.shwitter.user class User { void register(Notifier n) { n.notify(this); } } package io.shwitter.user.notify class Notifier { void notify(User user) { sendEmailTo(user.email()); } } package io.shwitter.user.registration class Registrator { void register(User user, Notifier n) {}
  55. 55. ESCALATION - REFACTORING STEP 2 package io.shwitter.user class User { void register() { } } package io.shwitter.user.notify class Notifier { void notify(User user) { sendEmailTo(user.email()); } } package io.shwitter.user.registration class Registrator { void register(User user, Notifier n) { n.notify(user); }
  56. 56. ESCALATION - REFACTORING STEP 3 package io.shwitter.user class User { void register() { } } package io.shwitter.user.notify class Notifier { void notify(String emailAddress) { sendEmailTo(emailAddress); } } package io.shwitter.user.registration class Registrator { void register(User user, Notifier n) { n.notify(user.email()); }
  57. 57. DEMOTION package io.shwitter.user class User { void register(Notifier n) { n.notify(this); } } package io.shwitter.user.notify class Notifier { void notify(User user) { sendEmailTo(user.email()); } }
  58. 58. DEMOTION - REFACTORING STEP 1 package io.shwitter.user class User implements EmailHolder { void register(Notifier n) { n.notify(this); } } package io.shwitter.user.notify class Notifier { void notify(User user) { sendEmailTo(user.email()); } } package io.shwitter.emailer interface EmailHolder { String email();
  59. 59. DEMOTION - REFACTORING STEP 2 package io.shwitter.user class User implements EmailHolder { void register(Notifier n) { n.notify(this); } } package io.shwitter.user.notify class Notifier { void notify(EmailHolder emailHolder) { sendEmailTo(emailHolder.email() } package io.shwitter.emailer interface EmailHolder { String email();
  60. 60. TOOLS
  61. 61. OO Design Principles & Metrics, Jason Gorman http://goo.gl/RTW9GT The Economics of Software Design, J.B. Rainsberger http://goo.gl/ra7Q8Q SOLID Principles, Eduards Sizovs http://goo.gl/Rpxavd Designing Object-Oriented Software, Jouni Smed http://goo.gl/iyE1R2 Grand Unified Theory Of Software Design, Jim Weirich http://goo.gl/ASqyAs Fun With Modules, Kirk Knoernschild http://goo.gl/i8jx8Y Patterns of Modular Architecture http://goo.gl/yFqmZO Let’s turn packages into a module system! http://goo.gl/Mzco8F MORE
  62. 62. EITHER YOU WORK TO CREATE A SOFTWARE STRUCTURE OR YOU DON'T. EITHER WAY A STRUCTURE WILL EMERGE. @EDUARDSI
  63. 63. THANK YOU

×