{"id":12187,"date":"2016-04-19T19:12:20","date_gmt":"2016-04-19T16:12:20","guid":{"rendered":"https:\/\/mozaicworks.com\/?p=9272"},"modified":"2016-04-19T19:12:20","modified_gmt":"2016-04-19T16:12:20","slug":"software-design-consistency-real-life-examples","status":"publish","type":"post","link":"https:\/\/mozaicworks.com\/blog\/software-design-consistency-real-life-examples","title":{"rendered":"Software Design: Consistency & real life examples"},"content":{"rendered":"

While a lot of the design principles that we use in software can be found in other design disciplines, there is one very present in UX and graphical design that is very rarely discussed in software circles: consistency.<\/p>\n

It\u2019s not because we weren\u2019t trying. The system metaphor idea from XP and the conceptual integrity idea from Frederick Brooks are just two of the notable essays for consistency. Yet there are very few systems who achieve a good level of consistency. The UNIX file system with its \u201ceverything is a file\u201d philosophy is one of them. Eclipse, with \u201ceverything is a plugin\u201d is another.<\/p>\n

There are various levels of consistency, and I place the conceptual integrity and system metaphor very high on the hierarchy. I honestly don\u2019t know a simple way to get there. Microservices seem to promise consistency at architectural level, but I have yet to be convinced.<\/p>\n

My experience with Usable Software Design has shown that there are many other levels of consistency that can be achieved and are very useful for the daily development work. They can all be derived from one principle:<\/p>\n

Clearly define your design entities<\/b><\/h2>\n

\u00a0Design Entities\u00a0<\/b><\/h4>\n

What artifacts can we use to design software? Simple: methods (or functions), classes and modules. Depending on your language, one or more of the above.<\/p>\n

Classes are great because they can express a lot of different types. That\u2019s also their problem. What if we don\u2019t want everything a class can do? After all, your knife has limited uses, it doesn\u2019t do everything you can do with steel.<\/p>\n

Limiting behavior may sound scary to developers, but it\u2019s actually in their favour. Imagine that your controller doesn\u2019t let you save to the database; this means you know to not search for the save code in the controller. What if the only place where you can save to the database is a command object? Then you know to search in command objects for the save code. The code is smaller and therefore less prone to errors. It will be easier to change the save user code without changing anything else. And so on.<\/p>\n

We want to constrain classes.\u00a0<\/i>We need to constrain classes. I call these constrained classes\u00a0design entities<\/b>.<\/p>\n

\u00a0Examples of Design Entities\u00a0<\/b><\/h4>\n

I\u2019ve recently redefined the design entities for our product, eventrix.co. I\u2019ve defined in total 6 different design entities:<\/p>\n

    \n
  • Controller<\/li>\n
  • Command Object<\/li>\n
  • Application Service<\/li>\n
  • Database Service (Command)<\/li>\n
  • Database Query<\/li>\n
  • View Model<\/li>\n<\/ul>\n
    \n
    \n
    \n

    I used CRC cards to define these entities, and I also added how to test them. Here are just a couple of examples:<\/p>\n

    Controller<\/strong><\/p>\n

    Responsibilities:<\/p>\n

      \n
    • Delegate the operations on the request input<\/li>\n
    • Render the correct view \/ template \/ error<\/li>\n<\/ul>\n

      Collaborators:<\/p>\n

        \n
      • Command Objects<\/li>\n
      • Application Services<\/li>\n
      • View Models<\/li>\n<\/ul>\n

        How To Test:<\/p>\n

          \n
        • Component Tests<\/li>\n<\/ul>\n

          Command Object<\/strong><\/p>\n

          Responsibilities:<\/p>\n

            \n
          • Validate the request<\/li>\n
          • Delegate update \/ delete operations<\/li>\n<\/ul>\n

            Collaborators:<\/p>\n

              \n
            • Database Services<\/li>\n
            • Database Queries<\/li>\n<\/ul>\n

              How to test:<\/p>\n

                \n
              • Unit tests<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n

                These entities are great for a number of reasons:<\/p>\n

                  \n
                • consistency: all features are implemented in the same way<\/li>\n
                • less decisions to make when implementing: decision fatigue can appear when making a lot of difficult choices; there still a lot of things the developers have to decide<\/li>\n
                • improved conversation: we have names for these design entities, and we can use them when discussing design or testing<\/li>\n
                • fit for the framework: they were tested with our framework of choice, grails, and they work great<\/li>\n<\/ul>\n

                  However, these design entities are by no means fixed and exhaustive. When defining them, I focused on covering 80% of the features we are implementing. When things will change, more design entities will appear and some might go away.<\/p>\n

                  But isn\u2019t this up-front design? It can be, if you\u2019re doing it up-front. In my case, I came up with these design entities for this specific project after about 6 months of implementing various features. They also come from a very good knowledge of the framework and libraries we\u2019re using. If you start by defining design entities, it\u2019s very possible they will slow down the teams instead of helping them speed up.<\/p>\n

                  The only way I know to come up with good design entities is by seeing many examples of features, (I estimate at least 10). So don\u2019t start with design entities; start by implementing features and refactoring; soon enough you will start to see some patterns that will lead to more complete sets of constraints. And once you found them, don\u2019t be afraid to change them when other situations appear.<\/p>\n

                  These are just a few examples of constraints that you can apply on classes. Let\u2019s explore other types of constraints.
                  \n<\/b><\/p>\n

                  \u00a0Constraints You Can Use Today\u00a0<\/b><\/h4>\n

                  Constraining design entities is not a new idea. In fact, you can use certain constraints right now:<\/p>\n

                    \n
                  • Functional programming uses immutability as a constraint for functions and, therefore, most classes \/ objects<\/li>\n
                  • Design by Contract is a way of designing in which each method defines a contract of things that should be true before calling it (preconditions), things that should be true after calling it (postconditions) and things that shouldn\u2019t change during its execution
                    \n(invariants).<\/li>\n
                  • UML stereotypes are a way of describing constraints on classes.<\/li>\n<\/ul>\n

                    The issue is with large scale use of constraints. Developers tend to shy away from constraints, fearing that they make development less creative and less interesting. I have yet to work in a project that wasn\u2019t interesting or creative, no matter how many and what types of constraints we used.<\/p>\n

                    Constraints are however unpopular. The typical project has no constraints, while some projects use unit testing to constrain the classes behavior. Immutability seems to catch on, while Design by Contract is rarely used. It\u2019s a pitty; we have a lot of design challenges ahead of us, if only we could create more consistent code.<\/p>\n

                    \u00a0A Plea For More Constraints\u00a0<\/b><\/h4>\n

                    I not only think that immutability, design by contract, unit tests or CRC cards for design entities (equivalent with UML stereotypes) should be used more. I\u2019m advocating even more types of constraints. Here are a couple of examples:<\/p>\n

                    Constrained inheritance<\/strong><\/p>\n

                    Too often we use generic classes such as String, Int or List to represent more specific things like name, duration or bag of cells (for code retreat participants).<\/p>\n

                    The typical way to represent this in code is by encapsulating the primitive type and add constraints. But what if we could inherit instead from the primitive type and restrict access to the base methods?<\/p>\n

                    Example:<\/p>\n

                    class MyList extends List restrictedTo {add, remove, first, moveNext()}<\/em><\/p>\n

                    Explanation:<\/p>\n

                    restrict usage of base class methods for the callers of the derived class<\/em><\/p>\n

                    Reasoning:<\/p>\n

                    to reduce primitive obsession problems<\/em><\/p>\n

                    Constrained collaboration<\/strong><\/p>\n

                    As you\u2019ve seen in the eventrix.co design entities, an important part is restricting collaboration. I\u2019ve seen too often database queries in the controller or even in the view. What if we could restrict what a controller can do so that the compiler tells us when someone breaks the rules?<\/p>\n

                    Example:<\/p>\n

                    \/\/ DesignEntities.java<\/p>\n

                    designEntity Controller<\/p>\n

                    can render, redirect<\/p>\n

                    canCall service, command<\/p>\n

                    \/\/ MyController.java<\/p>\n

                    Controller MyController{<\/p>\n

                    \/\/ Implement controller methods here<\/p>\n

                    }<\/p>\n

                    Explanation:<\/p>\n

                      \n
                    • define what a design entity can do and what it can call<\/li>\n
                    • it won\u2019t compile or throw an exception if something happens that\u2019s not allowed<\/li>\n<\/ul>\n

                      Reasoning:<\/p>\n

                        \n
                      • to enforce separation of concerns<\/li>\n<\/ul>\n

                        Discipline<\/strong><\/p>\n

                        Since we lack these capabilities in our languages, we have to constrain ourselves through discipline. I try to define as much as possible our design entities and make it very clear how to use them: how to name them, when to throw exceptions, what they can and cannot do, what are the collaboration patterns that apply to them etc.<\/p>\n

                        This is only the beginning. I found that a team debate and agreement on the usage of the design constraints helps a lot. Code and design reviews then help everyone keeping others honest about this agreement.<\/p>\n

                        Overall, anything that makes usage of design entities easier than the alternative helps. For example: code samples, usable code generation, support for testing are all good things to have that reduce the cost of using these entities over their alternatives.<\/p>\n

                        \u00a0Constraints and Consistency\u00a0<\/b><\/h4>\n

                        You can probably see now how well defined design entities lead to the various levels of consistency. For example: consistency in naming, contracts, collaboration etc. Well defined design entities really mean that you know exactly where to go when you search a bit of code, where to write a certain part of the implementation, how to test it etc.<\/p>\n

                        The best correspondent of design entities I found is in UI and it\u2019s called \u201cgraphical language\u201d. It\u2019s a set of widgets a designer creates that are reused throughout the graphical interface to maintain consistency. If you are a web developer, you\u2019ve probably seen one already.<\/p>\n

                        \u00a0What If We Find A Use Case That Doesn\u2019t Match?\u00a0<\/b><\/h4>\n

                        I rarely meet this problem. Yet when I do, it\u2019s usually time to create a new module.<\/p>\n

                        Consistency doesn\u2019t have to apply in the same way at all the code from your product. As I said, conceptual integrity and system metaphor are levels of consistency that I find very difficult to attain. However, consistency at the module level is easier. It will require some adjustments, refactoring and decisions, but it can be maintained without much effort.<\/p>\n

                        So my advice is: consider extracting the offending code into a small library or plugin for your application, where you use different consistency rules.<\/p>\n

                        Alex is currently writing a book on Usable Software Design and explores with other interested people these ideas. If you’re interested in becoming a reviewer of the book, or just in exploring these ideas, just let him know at alex.bolboaca@mozaicworks.com or @alexboly.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"

                        While a lot of the design principles that we use in software can be found in other design disciplines, there is one very present in UX and graphical design that is very rarely discussed in software circles: consistency. It\u2019s not because we weren\u2019t trying. The system metaphor idea from XP and the conceptual integrity idea […]<\/p>\n","protected":false},"author":1,"featured_media":9278,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"footnotes":""},"categories":[1147,1103,1125,1126],"tags":[1314,1167,1178,1110,1227,1315,1252],"acf":[],"_links":{"self":[{"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/posts\/12187"}],"collection":[{"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/comments?post=12187"}],"version-history":[{"count":0,"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/posts\/12187\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/media\/9278"}],"wp:attachment":[{"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/media?parent=12187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/categories?post=12187"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mozaicworks.com\/wp-json\/wp\/v2\/tags?post=12187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}