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

    View full-size slide

  2. The First Modern
    Programming Language

    View full-size slide


  3. 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.

    View full-size slide

  4. The First Programming Language
    FLOW-MATIC.
    The first modern, electronic programming language.
    1955–1959.
    Developed by Grace Hopper.
    wikipedia.org/wiki/FLOW-MATIC

    View full-size slide


  5. 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.

    View full-size slide

  6. 1959 2015
    1990
    1996

    View full-size slide

  7. 1959 2015
    1990
    1996
    FLOW-MATIC
    Me
    CSS
    Mum and Dad
    Sister

    View full-size slide

  8. 1959 2015
    1990
    1996
    FLOW-MATIC
    Me
    CSS
    Mum and Dad
    Sister

    View full-size slide

  9. 1959 2015
    1996

    View full-size slide

  10. 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.

    View full-size slide

  11. DRY/Single Source of Truth

    View full-size slide


  12. 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

    View full-size slide

  13. 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.

    View full-size slide

  14. 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; }

    View full-size slide

  15. 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.

    View full-size slide

  16. 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.

    View full-size slide

  17. 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;

    }

    View full-size slide

  18. 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.

    View full-size slide

  19. 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.

    View full-size slide

  20. 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.

    View full-size slide


  21. 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

    View full-size slide

  22. 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.

    View full-size slide

  23. Confusion
    DRY in source, not in production.
    Not about avoiding repetition…
    It’s about avoiding repeating yourself.
    Automation of repetition is fine.

    View full-size slide


  24. 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

    View full-size slide

  25. Confusion
    .btn {
    color: white;
    font-weight: bold;

    }
    .calendar__title {
    font-size: 14px;
    font-weight: bold;
    }
    .message {
    font-weight: bold;
    }

    View full-size slide

  26. 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.

    View full-size slide

  27. 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.

    View full-size slide

  28. 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.

    View full-size slide

  29. The Single
    Responsibility Principle

    View full-size slide


  30. 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

    View full-size slide

  31. 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.

    View full-size slide

  32. 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.

    View full-size slide

  33. 6,442,450,944

    View full-size slide

  34. 6,442,450,944
    6.4bn possible sandwich combinations.
    All by offering individual ingredients.
    Smaller pieces allow for greater composition.
    csswz.it/1XKydl8

    View full-size slide

  35. The Single Responsibility Principle
    #sandwich {

    bread: white;
    meat: chicken;
    salad: lettuce, onion, tomato;
    sauce: mayonnaise;

    }
    ...

    View full-size slide

  36. The Single Responsibility Principle
    #sandwich {

    bread: white;
    meat: chicken;
    salad: lettuce, onion, tomato;
    sauce: mayonnaise;

    }
    ...
    This is a monolith.
    It’s difficult to change,
    swap, or remove things.

    View full-size slide

  37. The Single Responsibility Principle
    .bread, .bread--white {}
    .chicken {}

    .lettuce {}
    .onion {}
    .tomato {}
    .mayonnaise {}
    ...
    Perfect! Now we
    can make our own
    sandwich from the
    ingredients we want.

    View full-size slide

  38. The Single Responsibility Principle
    .bread, .bread--white {}
    .chicken {}

    .lettuce {}
    .onion {}
    .tomato {}
    .mayonnaise {}
    ...
    No tomato?
    No problem!

    View full-size slide

  39. The Single Responsibility Principle
    Provide developers with the ingredients.
    Let them make the meals.
    Let’s look at a more realistic example…

    View full-size slide

  40. The Single Responsibility Principle
    .btn-login {
    display: inline-block;
    padding: 2em;
    background-color: green;
    color: white;

    }

    View full-size slide

  41. The Single Responsibility Principle
    .btn-login {
    display: inline-block;
    padding: 2em;
    background-color: green;
    color: white;

    }
    Mixing responsibilities.
    Base.
    Structural.
    Cosmetic.

    View full-size slide

  42. The Single Responsibility Principle
    .btn {
    display: inline-block;

    }
    .btn--large {
    padding: 2em;
    }
    .btn--positive {
    background-color: green;
    color: white;

    }

    View full-size slide

  43. The Single Responsibility Principle
    .btn {
    display: inline-block;

    }
    .btn--large {
    padding: 2em;
    }
    .btn--positive {
    background-color: green;
    color: white;

    }
    That’s better.

    View full-size slide

  44. 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.

    View full-size slide

  45. The Separation of Concerns

    View full-size slide


  46. 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

    View full-size slide

  47. 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.

    View full-size slide

  48. 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.

    // Binding JS onto styling hooks.
    document.getElementsByClassName('nav');

    View full-size slide

  49. The Separation of Concerns



    ...



    ...




    View full-size slide

  50. The Separation of Concerns



    ...



    ...




    View full-size slide

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

    View full-size slide

  52. The Separation of Concerns
    [role="navigation"] { ... }
    [role="navigation"] > ul { ... }
    [role="navigation"] > ul > li { ... }
    Ewww!
    Loading our
    CSS with
    DOM information.

    View full-size slide

  53. The Separation of Concerns
    role="navigation">



    ...



    ...




    View full-size slide

  54. The Separation of Concerns
    role="navigation">



    ...



    ...




    Semantic
    concerns.

    View full-size slide

  55. The Separation of Concerns
    role="navigation">



    ...



    ...



    Accessibility
    concerns.

    View full-size slide

  56. The Separation of Concerns
    role="navigation">



    ...



    ...



    Stylistic
    concerns.

    View full-size slide

  57. The Separation of Concerns
    role="navigation">



    ...



    ...




    Behavioural
    concerns.

    View full-size slide

  58. 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.

    View full-size slide


  59. 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

    View full-size slide

  60. Immutability

    View full-size slide


  61. Immutability
    …an immutable object is an object whose
    state cannot be modified after it is created.
    — wikipedia.org/wiki/Immutable_object

    View full-size slide

  62. Immutability
    Provides confidence.
    Makes things predictable.
    Helps debugging.
    Reduces cognitive overhead.
    Removes caveats, states, and conditions.

    View full-size slide

  63. Immutability
    .col-6 {
    width: 50%;
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  66. 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.

    View full-size slide

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

    View full-size slide

  68. Immutability
    .sub-content h2 {
    text-align: left;

    }
    .u-text-center {
    text-align: center;
    }

    ...

    View full-size slide

  69. Immutability
    .sub-content h2 {
    text-align: left;

    }
    .u-text-center {
    text-align: center;
    }

    ...

    Specificity
    mismatch.
    This will be
    aligned left!

    View full-size slide

  70. Immutability
    Parts of the codebase are able to mutate other parts.
    Unpredictable outcomes.
    Unexpected side effects.
    This is fixable.

    View full-size slide

  71. Immutability
    .sub-content h2 {
    text-align: left;

    }
    .u-text-center {
    text-align: center !important;
    }

    ...

    The only time
    to use it.

    View full-size slide

  72. Immutability
    .btn {
    font-size: 1em;
    }
    .promo .btn {
    font-size: 1.2em;
    }

    View full-size slide

  73. Immutability
    .btn {
    font-size: 1em;
    }
    .promo .btn {
    font-size: 1.2em;
    }
    One class,
    two outcomes.

    View full-size slide

  74. Immutability
    .btn {
    font-size: 1em;
    }
    .btn--large {
    font-size: 1.2em;
    }
    Two classes,
    two outcomes.

    View full-size slide

  75. Immutability
    Don’t have several states of the same thing.
    Use Modifiers or Responsive Suffixes.
    Use !important to force immutability.
    Brings us nicely onto…

    View full-size slide

  76. Cyclomatic Complexity

    View full-size slide


  77. 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

    View full-size slide

  78. 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.

    View full-size slide

  79. 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?!

    View full-size slide

  80. Cyclomatic Complexity
    div.main section.content h1 a span {}

    View full-size slide

  81. Cyclomatic Complexity
    @if div {
    @if .main {
    @if section {
    @if .content {
    @if h1 {
    @if a {
    @if span {
    // Do stuff.
    }
    }
    }
    }

    }
    }
    }

    View full-size slide

  82. Cyclomatic Complexity
    div.main section.content h1 a span {}
    Subject.
    This is the
    bit we actually
    care about.

    View full-size slide

  83. Cyclomatic Complexity
    div.main section.content h1 a span {}
    Conditions.
    All of this is
    just complexity.

    View full-size slide

  84. Cyclomatic Complexity
    .text-highlight {}
    Start off
    explicitly.
    Don’t add
    needless
    complexity.

    View full-size slide

  85. 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.

    View full-size slide

  86. Cyclomatic Complexity
    div#body section.container section.main
    div.categories ul li a.product-title {}

    View full-size slide

  87. Cyclomatic Complexity
    div#body section.container section.main
    div.categories ul li a.product-title {}

    View full-size slide

  88. The Open/Closed Principle

    View full-size slide


  89. 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

    View full-size slide

  90. 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.

    View full-size slide


  91. 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

    View full-size slide

  92. The Open/Closed Principle
    .btn {
    ...
    padding: 1em 2em;
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  95. 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.

    View full-size slide

  96. 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.

    View full-size slide

  97. 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.

    View full-size slide

  98. Orthogonality

    View full-size slide


  99. Orthogonality
    Orthogonality in programming language
    design is the ability to use various language
    features in arbitrary combinations with
    consistent results.
    — wikipedia.org/wiki/Orthogonality

    View full-size slide

  100. Orthogonality
    Reduces interdependence.
    Improves composability.
    Separates concerns.
    Reduces collisions.
    Removes side effects.
    Good litmus test: can we reorder imports?

    View full-size slide

  101. 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.

    View full-size slide

  102. Orthogonality
    Another good test: will it nest?
    Can things be combined in the DOM?
    Well-scoped selectors improve orthogonality.

    View full-size slide

  103. Proper scoping
    provides orthogonality

    View full-size slide

  104. The Moustache Principle

    View full-size slide


  105. The Moustache Principle
    Just because you can, it doesn’t
    mean that you should.
    — Harry Roberts

    View full-size slide

  106. Thank You
    Harry Roberts
    csswizardry.com
    [email protected]
    @csswizardry
    speakerdeck.com/csswizardry

    View full-size slide