Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CSS for Software Engineers for CSS Developers

Harry Roberts
September 15, 2015

CSS for Software Engineers for CSS Developers

Applying traditional software engineering principles directly (or indirectly) to CSS.

Harry Roberts

September 15, 2015
Tweet

More Decks by Harry Roberts

Other Decks in Design

Transcript

  1. CSS for Software Engineers for CSS Developers Harry Roberts –

    SmashingConf Freiburg – September 2015
  2. “ FLOW-MATIC FLOW-MATIC, originally known as B-0, was the first

    English-like data processing language. It was developed for the UNIVAC I at Remington Rand under Grace Hopper during the period from 1955 until 1959.
  3. The First Programming Language FLOW-MATIC. The first modern, electronic programming

    language. 1955–1959. Developed by Grace Hopper. wikipedia.org/wiki/FLOW-MATIC
  4. “ FLOW-MATIC … Rand management considered the idea unfeasible. In

    early 1955, she and her team wrote a specification for such a programming language and implemented a prototype.
  5. A 37-Year Head Start All that wisdom! We should get

    as much from their head start as we can. The time between the first modern programming language and CSS is greater than the time between CSS and now. Software engineers have been writing code for 37 years longer than front-end developers have.
  6. “ Don’t Repeat Yourself Every piece of knowledge must have

    a single, unambiguous, authoritative representation within a system. — wikipedia.org/wiki/Don't_repeat_yourself
  7. Don’t Repeat Yourself Every discrete piece of information should exist

    only once. You shouldn’t need to make the same change several times. Repetition is extra overhead: more to maintain, to go wrong. Increases cognitive overhead. Contributes to bloat.
  8. Don’t Repeat Yourself .u-margin-top { margin-top: 12px; } .u-margin-right {

    margin-right: 12px; } .u-margin-bottom { margin-bottom: 12px; } .u-margin-left { margin-left: 12px; }
  9. Don’t Repeat Yourself .u-margin-top { margin-top: 12px; } .u-margin-right {

    margin-right: 12px; } .u-margin-bottom { margin-bottom: 12px; } .u-margin-left { margin-left: 12px; } We’ve typed the same value four times.
  10. Don’t Repeat Yourself $unit: 12px; .u-margin-top { margin-top: $unit; }

    .u-margin-right { margin-right: $unit; } .u-margin-bottom { margin-bottom: $unit; } .u-margin-left { margin-left: $unit; } Much better! A single source of truth.
  11. Don’t Repeat Yourself .page-title { font-family: "Custom Font", sans-serif; font-weight:

    700;
 } .btn { font-family: "Custom Font", sans-serif; font-weight: 700;
 } .pagination { font-family: "Custom Font", sans-serif; font-weight: 700;
 }
  12. Don’t Repeat Yourself .page-title { font-family: "Custom Font", sans-serif; font-weight:

    700;
 } .btn { font-family: "Custom Font", sans-serif; font-weight: 700;
 } .pagination { font-family: "Custom Font", sans-serif; font-weight: 700;
 } Thematically related but repeated.
  13. Don’t Repeat Yourself @mixin custom-font() { font-family: "Custom Font", sans-serif;

    font-weight: 700; } 
 .page-title { @include custom-font();
 } .btn { @include custom-font();
 } .pagination { @include custom-font();
 } Argumentless mixins are perfectly okay.
  14. Don’t Repeat Yourself @mixin custom-font() { font-family: "Custom Font", sans-serif;

    font-weight: 700; } 
 .page-title { @include custom-font();
 } .btn { @include custom-font();
 } .pagination { @include custom-font();
 } Gives the exact same output, but at least we haven’t duplicated anything manually.
  15. “ Single Source of Truth […] the practice of structuring

    information models and associated schemata such that every data element is stored exactly once. — wikipedia.org/wiki/Single_Source_of_Truth
  16. Single Source of Truth The more philosophical principle behind DRY.

    Key data should only exist once in source. Increases confidence. Prevents anomalies and disparity. Makes changes simpler. Keeps your house in order.
  17. Confusion DRY in source, not in production. Not about avoiding

    repetition… It’s about avoiding repeating yourself. Automation of repetition is fine.
  18. “ Confusion If you manually type a declaration 50 times

    in a project, you are repeating yourself: this is not DRY. If you can generate that declaration 50 times without having to manually repeat it, this is DRY: you are generating repetition without actually repeating yourself. This is quite a subtle but important distinction to be aware of. — csswz.it/1ytQkxp
  19. Confusion .btn { color: white; font-weight: bold;
 } .calendar__title {

    font-size: 14px; font-weight: bold; } .message { font-weight: bold; }
  20. Confusion .btn { color: white; font-weight: bold;
 } .calendar__title {

    font-size: 14px; font-weight: bold; } .message { font-weight: bold; } This is purely coincidental. Don’t try to DRY it out.
  21. Confusion Don’t DRY if it’s repeated coincidentally. Repetition in compiled

    code is fine. Just avoid duplicating data in source. Going too far creates awkward and confusing structures in your code.
  22. DRY/Single Source of Truth Use a preprocessor to store key

    data in variables. Make use of mixins to generate repetition for you. Abstract design patterns out into reusable objects. Do not DRY anything that is purely coincidental. Repetition is better than the wrong abstraction.
  23. “ The Single Responsibility Principle […] the single responsibility principle

    states that every class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class. — wikipedia.org/wiki/Single_responsibility_principle
  24. The Single Responsibility Principle AKA: Do one thing, one thing

    only, and one thing well. Break bigger monoliths down into individual concerns. Easier to reason about. Provides higher composability.
  25. The Single Responsibility Principle Subway is the epitome of SRP.

    Break things down into their smallest possible parts. Ensure each part fulfils its responsibility very well. Combine responsibilities to create complex components. Swap out, remove, or add discrete parts. Helps you Separate your Concerns. Gives you incredible opportunity and flexibility.
  26. 6,442,450,944 6.4bn possible sandwich combinations. All by offering individual ingredients.

    Smaller pieces allow for greater composition. csswz.it/1XKydl8
  27. The Single Responsibility Principle #sandwich {
 bread: white; meat: chicken;

    salad: lettuce, onion, tomato; sauce: mayonnaise;
 } <div id="sandwich">...</div>
  28. The Single Responsibility Principle #sandwich {
 bread: white; meat: chicken;

    salad: lettuce, onion, tomato; sauce: mayonnaise;
 } <div id="sandwich">...</div> This is a monolith. It’s difficult to change, swap, or remove things.
  29. The Single Responsibility Principle .bread, .bread--white {} .chicken {}
 .lettuce

    {} .onion {} .tomato {} .mayonnaise {} <div class="bread bread--white chicken lettuce onion tomato mayonnaise">...</div> Perfect! Now we can make our own sandwich from the ingredients we want.
  30. The Single Responsibility Principle .bread, .bread--white {} .chicken {}
 .lettuce

    {} .onion {} .tomato {} .mayonnaise {} <div class="bread bread--white chicken lettuce onion mayonnaise">...</div> No tomato? No problem!
  31. The Single Responsibility Principle Provide developers with the ingredients. Let

    them make the meals. Let’s look at a more realistic example…
  32. The Single Responsibility Principle .btn-login { display: inline-block; padding: 2em;

    background-color: green; color: white;
 } Mixing responsibilities. Base. Structural. Cosmetic.
  33. The Single Responsibility Principle .btn { display: inline-block;
 } .btn--large

    { padding: 2em; } .btn--positive { background-color: green; color: white;
 }
  34. The Single Responsibility Principle .btn { display: inline-block;
 } .btn--large

    { padding: 2em; } .btn--positive { background-color: green; color: white;
 } That’s better.
  35. The Single Responsibility Principle .btn { ... } .btn--large {

    ... } .btn--small { ... } .btn--positive { ... } .btn--negative { ... } .btn--full { ... } Plus now we can combine these classes with others to make lots of varieties of button.
  36. “ The Separation of Concerns […] It is, that one

    is willing to study in depth an aspect of one’s subject matter in isolation for the sake of its own consistency […] But nothing is gained—on the contrary! —by tackling these various aspects simultaneously. It is what I sometimes have called ‘the separation of concerns’ […] it does not mean ignoring the other aspects, it is just doing justice to the fact that from this aspect’s point of view, the other is irrelevant. It is being one- and multiple-track minded simultaneously. — wikipedia.org/wiki/Separation_of_concerns
  37. The Separation of Concerns Each thing responsible for itself and

    nothing more. Reason about and study features in isolation. In CSS: Only bind CSS onto CSS-based classes only. Don’t write DOM-like selectors. Don’t bind CSS onto data-* attributes. Don’t bind JS onto CSS classes.
  38. The Separation of Concerns // Binding CSS onto accessibility hints.

    [role="nagivation"] { ... } // Putting DOM information into our CSS. header nav ul li a { ... } // Using HTML to provide cosmetics. <font color="red"> // Binding JS onto styling hooks. document.getElementsByClassName('nav');
  39. The Separation of Concerns [role="navigation"] { ... } [role="navigation"] >

    ul { ... } [role="navigation"] > ul > li { ... }
  40. The Separation of Concerns [role="navigation"] { ... } [role="navigation"] >

    ul { ... } [role="navigation"] > ul > li { ... } Ewww! Loading our CSS with DOM information.
  41. The Separation of Concerns <nav class="site-nav js-site-nav"
 role="navigation">
 <ul class="site-nav__list">

    <li class="site-nav__item">
 <a class="site-nav__link">...</a>
 </li> <li class="site-nav__item">
 <a class="site-nav__link
 is-active">...</a>
 </li> </ul>
 </nav>
  42. The Separation of Concerns <nav class="site-nav js-site-nav"
 role="navigation">
 <ul class="site-nav__list">

    <li class="site-nav__item">
 <a class="site-nav__link">...</a>
 </li> <li class="site-nav__item">
 <a class="site-nav__link
 is-active">...</a>
 </li> </ul>
 </nav> Semantic concerns.
  43. The Separation of Concerns <nav class="site-nav js-site-nav"
 role="navigation">
 <ul class="site-nav__list">

    <li class="site-nav__item">
 <a class="site-nav__link">...</a>
 </li> <li class="site-nav__item">
 <a class="site-nav__link
 is-active">...</a>
 </li> </ul>
 </nav> Accessibility concerns.
  44. The Separation of Concerns <nav class="site-nav js-site-nav"
 role="navigation">
 <ul class="site-nav__list">

    <li class="site-nav__item">
 <a class="site-nav__link">...</a>
 </li> <li class="site-nav__item">
 <a class="site-nav__link
 is-active">...</a>
 </li> </ul>
 </nav> Stylistic concerns.
  45. The Separation of Concerns <nav class="site-nav js-site-nav"
 role="navigation">
 <ul class="site-nav__list">

    <li class="site-nav__item">
 <a class="site-nav__link">...</a>
 </li> <li class="site-nav__item">
 <a class="site-nav__link
 is-active">...</a>
 </li> </ul>
 </nav> Behavioural concerns.
  46. The Separation of Concerns Grid systems are a great example.

    Handle your layout completely separately to your components. Writing CSS in JS breaks the Separation of Concerns. Can’t reconsider your JS architecture without having to reconsider your CSS architecture.
  47. “ The Separation of Concerns If in 14 months you

    find a new view library or framework you want to try out, you’re out of luck. You will have to invest a lot of time into pulling styles back out of JavaScript modules and into stylesheets again. — keithjgrant.com/posts/against-css-in-js.html
  48. “ Immutability …an immutable object is an object whose state

    cannot be modified after it is created. — wikipedia.org/wiki/Immutable_object
  49. Immutability .col-6 { width: 50%; } @media screen and (max-width:

    480px) { .col-6 { float: none; width: 100%; } }
  50. Immutability .col-6 { width: 50%; } @media screen and (max-width:

    480px) { .col-6 { float: none; width: 100%; } } This has mutated!
  51. Immutability .col-6 has one input, but two potential outputs. Outcome

    depends on how/when you observe it. It has been mutated. Mutable state leads to confusion and unexpected outcomes. Particularly common in CSS.
  52. Immutability .col-6 { width: 50%; } @media screen and (max-width:

    480px) { .col-6@sm { float: none; width: 100%; } } Use a different class.
  53. Immutability .sub-content h2 { text-align: left;
 } .u-text-center { text-align:

    center; } <section class="sub-content"> <h2 class="u-text-center">...</h2> </section>
  54. Immutability .sub-content h2 { text-align: left;
 } .u-text-center { text-align:

    center; } <section class="sub-content"> <h2 class="u-text-center">...</h2> </section> Specificity mismatch. This will be aligned left!
  55. Immutability Parts of the codebase are able to mutate other

    parts. Unpredictable outcomes. Unexpected side effects. This is fixable.
  56. Immutability .sub-content h2 { text-align: left;
 } .u-text-center { text-align:

    center !important; } <section class="sub-content"> <h2 class="u-text-center">...</h2> </section> The only time to use it.
  57. Immutability Don’t have several states of the same thing. Use

    Modifiers or Responsive Suffixes. Use !important to force immutability. Brings us nicely onto…
  58. “ Cyclomatic Complexity Cyclomatic complexity is a software metric used

    to indicate the complexity of a program. It is a quantitative measure of the number of linearly independent paths through a program’s source code. — wikipedia.org/wiki/Cyclomatic_complexity
  59. Cyclomatic Complexity M = E - N + 2P Basically

    just the number of IFs/ELSEs. A form of static analysis. Counting the number of paths through a program. The amount of potential outcomes given certain conditions. Higher complexity is bad: simpler is always better.
  60. Cyclomatic Complexity M = E - N + 2P Basically

    just the number of IFs/ELSEs. A form of static analysis. Counting the number of paths through a program. The amount of potential outcomes given certain conditions. Higher complexity is bad: simpler is always better. Whut?!
  61. Cyclomatic Complexity @if div { @if .main { @if section

    { @if .content { @if h1 { @if a { @if span { // Do stuff. } } } }
 } } }
  62. Cyclomatic Complexity Deeply nested or qualified selectors are bad. They

    carry a higher Cyclomatic Complexity. Reduce by using much shorter selectors. Get straight to the point. Remove as many conditions and caveats as possible. Start with the correct subject.
  63. “ The Open/Closed Principle Software entities (classes, modules, functions, etc.)

    should be open for extension, but closed for modification. — wikipedia.org/wiki/Open/closed_principle
  64. The Open/Closed Principle Never change anything at its source. Avoid

    the Domino Effect. Doing so causes visual regressions. Hard to keep track of the knock-on effects. Always make changes via extension (i.e. addition). Possibly the most useful principle for dealing with other peoples’ code.
  65. “ The Open/Closed Principle […] once completed, the implementation of

    a class could only be modified to correct errors; new or changed features would require that a different class be created. That class could reuse coding from the original class through inheritance. — wikipedia.org/wiki/Open/closed_principle
  66. The Open/Closed Principle .btn { ... padding: 1em 2em; }

    Once this is out there, we can’t risk changing it directly.
  67. The Open/Closed Principle .btn { ... padding: 1em 2em; }

    .promo .btn { padding: 1.5em 2.5em; }
  68. The Open/Closed Principle .btn { ... padding: 1em 2em; }

    .promo .btn { padding: 1.5em 2.5em; } Even this is risky as we’re still modifying the base button class.
  69. The Open/Closed Principle .btn { ... padding: 1em 2em; }

    .btn--large { padding: 1.5em 2.5em; } Perfect! A brand new class adds the changes that we want to safely opt in to.
  70. The Open/Closed Principle A safe way to make changes. Everything

    gets opted into explicitly. Prevents changes from happening one-sidedly; the developer has to add the class into the markup as well. A second layer of safety: changes can’t be actioned from one place alone. Build things forward. Analogous to rewriting Git history. Safe way of working with legacy.
  71. “ Orthogonality Orthogonality in programming language design is the ability

    to use various language features in arbitrary combinations with consistent results. — wikipedia.org/wiki/Orthogonality
  72. Orthogonality (How well) can we arbitrarily combine things? The implication

    is that they don’t rely on one another. The hallmarks of a flexible and modular system.
  73. Orthogonality Another good test: will it nest? Can things be

    combined in the DOM? Well-scoped selectors improve orthogonality.
  74. “ The Moustache Principle Just because you can, it doesn’t

    mean that you should. — Harry Roberts