Design Systems

What is it?

A design system is the reference manual or collection of rules for designing websites that all share a common look and feel.

It defines how space is used, which fonts and font sizes are used when and where, how input elements look and behave, which colors are used when and where and all other aspects that should be part of the common experience.

A design system should incorporate a Coorporate Identity design if it exists. A design system will extend the coorporate identity into the interactive digital space.

It should be based on the principals of human machine interactions based on computer science work to make it easy for a user to benefit from the digital system.

Examples

Tools

CSS Grid Systems

What is a Grid System?

A grid system is a layout mechanism, which makes it an alternative to the CSS Flexbox Layout (aka. flexbox) and the CSS Grid Layout (aka. CSS grid).

Whereas both the CSS Flexbox Layout and the CSS Grid Layout are part of the CSS specification, a grid system is built using CSS functionality and it does exist in the CSS specification. As such there are numerous frameworks that each come with their own implementation of a grid system.

Certain features are common to all grid system. The features are described in detail later.

Difference between Grid System, CSS Grid Layout and CSS Flexbox Layout

Despite the naming similarities, a grid system is not to be confused with the CSS Grid Layout.

I think they do similar things but I could not figure out how they differ or if CSS Grid Layout is there to replace custom grid systems. Need more expertise.

On the twitter boostrap page for their grid system, it says that the grid system is implemented using the CSS Flexbox Layout!

What does a Grid System do?

A Grid System ultimately sizes and positions elements in a responsive fashion. The promise is, when done right, all elements will be assigned appropriate screen space across all viewport size possible. The benefit is that there is always enough width assign so the use can consume the content with maximum convenience.

In a grid systen, elements are put into rows. All rows have the same amount of columns. The amount of columns in bootstrap’s grid system is 12 for example. Other amounts of columns are possible.

Elements are assigned (different) column widths based on media queries. On viewport size changes, elements will take up a dynamic amount of columns because of what the user has defined for each query. On large screen sizes, an element might take up 3 columns for example. In a media query for smaller device, it maybe takes up 6 columns so it is still visible. In a media query for smartphones, it might even take up all 12 columns so it stretches an entire row’s width and the user can still make out its content nicely even though the screen is very small.

Elements, once placed into a row, will never leave that row. If the amount of columns are used up and there are still more elements to place into a row, the row will break and elements will start to stack on top of each other so they do not leave the row.

This most often happens when elements are assign higher column counts on media queries for smaller screens. This keeps rows separate from other rows at all times.

In most grid systems, the media-queries are predefined with standard breakpoints and are called xs, s, m, l and xl similar to clothing sizes. The xs media-query is for very small screen sizes such as mobile phones, xl is for desktop screens.

To define the amount of columns per media-query, a grid system usually defines CSS classes. Several of those CSS classes are then assigned to elements until the user has described the element columns in all media-queries. The CSS classes have no effect unless their media-query actives, which is when the CSS class has an effect on the element. It will then tell the grid-system how many columns the element consumes. 

Angular Testing

Links

Introductory Rant

What happens when code is untested? At first, nothing major will happen. The first generation of team members knows the Ins- and Outs of the code. They created each part at their preferred speed. Large applications grow over several months or years and the knowledge is stored in the heads of the developers of the first generation. Due to untested code, there will be some bugs but the bugs can be solved by the devs because they know exactly who wrote the code, what causes the bugs and how to fix them quickly. 

Bad things happen months and years later. The price is paid by the second generation of developers. Once people leave for new jobs, the team eventually is cycled out and the second generation takes over. Or maybe the A-Team of developers is put onto another project and the B-Team takes over. Lack of knowledge transfer and documentation leads to a phase of utter chaos. A vast, undocumented, untested code base is dumped onto a team that has no experience in the field whatsoever. Unexperienced people now get the job assigned to reengineer complex interactions in a short amount of time and to quickly implement new working features in a potentially broken code base. I argue that this task is almost as difficult as creating the original project although the difficulties lie not in the engineering part but in the understanding of the existing codebase.

Now nobody knows, what the code is actually supposed to do as there are no constraints described by unit tests on what the code currently does. People do not know if after changing the code, the app still works at the customer’s site because there is no test coverage that checks if parts of the application broke due to unwanted side effects.

People will shy away from changing the application instead, they will leave the company in search for a sane working environment and the app will finally be replaced altogether, when yet another new generation of developers or managers step in.

One part of the solution is to start unit testing as early as possible and to add integration testing with automated tooling support.

Tests in Angular

Angular was designed to be testable when Angular was invented and developed.

In Angular, there are unit tests written with Jasmine and Karma and end-to-end (e2e) tests implemented with Protractor. Both can be executed by the continuous integration tool or on every save during development.

Coming from other programming languages where unit tests also exist, understanding Jasmine Behaviour Driven Tests is not that hard, because the concepts of test suite, a setup and a tear-down step and individual tests within a suite correspond with other languages.

Where it gets hard is when Angular specific parts are mixed into the Jasmine tests. Understanding those Angular specific parts that are involved in an Angular unit tests for components is hard, because these parts simply are not existent in other programming languages.

Testing with Jasmine and Karma

Jasmine is a behaviour driven testing framework for JavaScript. Karma is a test runner for JavaScript. It starts a web server serving the testing code and allows a browser to access the served code. The browser can be controlled by Jasmine using a web driver.

The combination of Jasmine and Karma are used extensively by Angular. Angular adds Angular specifics to the otherwise JavaScript base tools Jasmine and Karma.

Angular Specifics

The Angular specific parts in Jasmine Unit Tests are the ComponentFixture and the TestBed. The TestBed forms the environment for dependency injection by creating a NgModule just for running a test. The ComponentFixture wraps the component instance under test.

TestBed

The TestBed is used to create an Angular module on the fly. That module is only used for the unit test at hand in contrast to modules you use to organize your code. It is used to contain all the services, spies, mocks and all other resources needed to successfully run the unit test. When the unit test ends, that module is removed from memory, it only lives during the execution of the test suite. 

The TestBed will then be used to create the ComponentFixture through a call to it’s createComponent() method. (createComponent() is usually called in beforeEach()).

beforeEach(() => { 
fixture = TestBed.createComponent(ContactEditComponent);
component = fixture.componentInstance;
fixture.detectChanges();
...
}

The ComponentFixture is actually not the instance of the component, which is tested! It is not the system under test. In the snippet above, you can see the line of code:

component = fixture.componentInstance;

The ComponentFixture can be asked for the system under test using the componentInstance property. It will return the instance of the component under test.

It seems as if a ComponentFixture wraps the instance of the Component that is tested.

Here is what is so very confusing to me: The TestBed.createComponent() method, despite being named ‘createComponent’ does not return a component! Instead it returns a ComponentFixture!

Because the ComponentFixture was created from the TestBed, it will use the providers and services that have been configured into the TestingModule which was created in the first step. That means your spies and mocks are now used by the fixture.

The ComponentFixture is used to run changeDetection() manually because in UnitTests, the Angular ChangeDetection system is not running at all. You have to trigger the system manually so all changes are reflected in the DOM before you can query the changes in your assertions.

ComponentFixture

A ComponentFixture is an object, which wraps the instance of the Component under test. The component instance uses the mocks and spies configured into the TestBed it was created by.

In the individual unit tests, that is in the describe() and it() methods, the component is used to call methods on and to check how it’s state changes.

beforeEach(() => { 
fixture = TestBed.createComponent(ContactEditComponent);
component = fixture.componentInstance;
fixture.detectChanges();
...
}


describe('that, when using the FavoriteComponent', () => {
it('should display a star when clicked', fakeAsync(() => {
...
component.click();
...
expect(element.nativeElement.value).toBe('selected');
...
}
}

SCSS Cheatsheet

Comments

CSS comments use the /* … */ syntax. CSS comments are part of a CSS file and will be sent over the internet to the client.

SCSS adds another syntax // …

SCSS syntax are not copied into the resulting CSS. They are therefore not send to the client. This allows you to keep the CSS files as small as possible while still having good documentation in the source files.

Variables

When using the same value, instead of placing independant values all over the stylesheet, consider using a variable for easier maintenance in the future.

Variables start with the $ symbol. A variable definition creates a new variable identifier and assigns a value to that identifier.

$primary-color: #1875e7;
h1#brand { color: $primary-color; }
sidebar { background-color: $primary-color; }

Variables can be used after declaring them. To use a variable, add the $ followed by the identifier in place of a concrete value.

Variables have scope which means the location a variable where is declared determines it’s visibility. A variable can be defined outside any rule, which makes it globally visible amongst all SCSS files. Defining a variable inside a SCSS rule limits it’s visibility to the rule and the nested rules within that rule.

Nesting

SASS allows you to nest selectors and properties.

Nesting for Selectors

CSS allows to chain elements in selectors to specify how to style nested elements that match that path defined in the selector. Basically a selector is a flattened representation of a tree structure. SCSS brings back the tree structure using nesting and saves some redundant typing.

To style elements on several levels of the same nesting hierarchy, you have to write the path over and over to extend it by another level until you have written all rules for all hierarchy levels you want to apply styles to.

SCSS allows you to nest rules to more naturally work with nested elements and their CSS. Instead of 

header: { color: red; }
header a: {
font-weight: bold;
text-decoration: none;
}

you write

#header {
color:red;
a {
font-weight: bold;
text-decoration: none;
}
}

Nesting for Properties

Imagine styling a border with the exploded notation for demonstration purposes:

div {
border-width: 1px;
border-style: solid;
border-color: black;
}

The redundant part here is the border- prefix repeated for all properties.

With property nesting, you split at the dash and add a colon to the root property. Then write the part after the dash into the nested rule like so:

div { 
border: {
width: 1px;
style: solid;
color: black;
}
}

The Parent Operator &

The & operator refers the direct parent in nested rules.

Imageine to following HTML:

<ul>
<li>list element 1</li>
<li class="selected">list element 2</li>
<li>list element 3</li>
</ul>

The list element having the selected class should be displaying in a darker color. With CSS you write several rules, with SCSS, nesting can be used which also allows for the use of the & operator.

ul { border: 1px solid green; }
ul li { color: #DCDCDC; }
ul li.selected { color: #808080; }

In SCSS, the same can be written using nesting.

ul {
border: 1px solid green;
li {
color: #DCDCDC;
&.selected {
color: #808080;
}
}
}

Here, the & refers to the li element because li is the immediate parent for the rule where & was applied. & will be replaced by li after the SCSS compiler produced the output.

The & operator prevents SASS from adding a space between the parent and the child when flattening out the CSS. Adding the & operator will concatenate the elements instead of joining them with a space in between. This is useful for class-based selectors and for pseudo classes.

The CSS Operators >, + and ~

Without using the child combinator (>), CSS rules are applied over more than one level of nesting. Using the > operator, the CSS rule is applied over exactly one level of nesting, which introduces the concept of an immediate child.

The sibling operator (~) selects any following element regardless of how many elements are in between.

The adjacent sibling operator (+) introduces the concept of an immediate sibling, which is the sibling directly following an element.

With SASS, the operators >, + and ~ can be applied at the end of a parent element or at the beginning of a child element.

Mixins

Mixins are defined using the @mixin keyword and they are applied using the @include keyword.

A mixin is a container that can be filled with SCSS rules. When the mixin is applied, all SCSS rules inside it are pasted to that location. In a sense, mixins are similar to variables in that they are a central point to store information and allow for the reuse of that information in several locations.

To define a mixin container use the following syntax:

@mixin <MIXIN_IDENTIFIER>(<PARAMETER>: <DEFAULT-VALUE>, ..., <PARAMETER>: <DEFAULT-VALUE>) {
<SCSS-RULES GO HERE>
}

Applying the mixin is done like this:

@include <MIXIN_IDENTIFIER>(<VALUE>, ..., <VALUE>);

When you have no need to parameterize a mixin, you can leave out the parameter list as it is optional.

TODO: add an example for a beneficial, real-world use of mixins

Angular Data Flow

This post lists the ways you can send data around in a angular application which will be referred to as data flow.

Using interpolation, data in a component’s properties can be output to the HTML template. But then there is also property-, class- and other bindings such as two-way binding (Banana in a Box). Data can be exchanged between child (@ViewChild, @ViewChildren, @ContentChild, @ContentChildren decorators) and parent components. Events can be sent (EventEmitter). Forms can be used to submit data with validation. But why are forms needed in the first place, when we have data binding?

To a beginner all these concepts are confusing, this post lists all interactions and explains their major benefit and when to use them.

Interpolation

The value stored in a component’s property can be output on a template using the interpolation syntax.

import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'cockpit';
}
{{title}}

Interpolation also allows you to perform calculations and function calls.

{{10 + 20}}
{{functionCall()}}

The value can be placed anywhere in the template and is rendered as is. If you want to put a value from a component into an attribute of a DOM element or child component, do not use interpolation but use property binding.

Interpolation using getters

If your component contains a getter

import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'cockpit';
username = 'username';

get user(): string {
return this.username;
}
}

interpolation also works with the getter:

{{user}}

Getters and Change Detection

As angular uses an elaborate change detection mechanism, the getter should not return a new object each time it is called but instead should return an immutable object which remains identical unless the data actually did change.

For an object to be immutable, the object is never modified but recreated from scratch each time data changes. If the data stays the same, the getter will return the same immutable object instance instead of returning a new string or a new object every time it is called even if the data is the same.

That way, using immutable objects, change detection can compare objects returned by getters correctly an only redraw that part of the page, when a new object is present, which means that data did actually change.

Refrain from constructing new objects on the fly and returning them from a getter as this throws change detection into a loop and causes angular to perform unnecessary work when rendering the page.

Naming fields and their get and set methods

Coming from a Java background, where getters and setters are also available, the expectation is the following syntax:

public class MyClass {
private String fieldname;

public getFiendname() {
return this.fieldname;
}

public setFieldname(const String fieldname) {
this.fieldname = fieldname;
}
}

This means, getters and setters are in essence normal member functions or methods. They have the conventional set and get prefixes to make them immediately identifiable as getters and setters. This convention is also mandated by the definition of a Java bean.

In Angular/Typescript, the keywords get and set exist and they are special syntax for getters and setters. The downside of this explicit notation is that getters and setters basically use the identifier that would be used for the field itself! There is a naming conflict here! How to resolve that conflict? This depends on the conventions you agree upon in your project. There is an underscore convention which is outdated apparently. Then you can choose a different name for the field and use the compact identifier for the getters and setters. Ultimately there is no definite solution to the name conflict issue.

Event Binding – Calling methods in components from the UI

Event Binding uses braces around attributes like this: (attr)=”eventHandlerMethod()”

You can bind to the click event of a button and call a function in your component.

login() {
this.authService.login();
}

logout() {
this.authService.logout();
}

In the template:

<button (click)="login()">Login</button>
<button (click)="logout()">Logout</button>

Another example of EventBinding is to bind a method of a component to the submit event of an Angular template-driven form (https://angular.io/guide/forms).

<form (ngSubmit)="onSubmit()" #heroForm="ngForm"></form>

When the form is submitted using the submit button, the onSubmit() method in the component is called.

@Input – Property Binding – Passing data from a parent to a DOM element or child component

Property Binding uses square brackets like this: [attr]=”value”.

As the template of a component can contain other components, a parent child hierarchy is formed. The parent, the component owning the template can put a value into an attribute of a child component. The child component can make use of the attribute by mapping that attribute to a field in it’s own class.

The mapping is created by annotating a field using the @Input() annotation. Now that field is mapped to an attribute of the same name in the template. To pass a value to the child, the attribute has to be surrounded by square brackets (= the binding operator).  The binding operator takes the value inside the square brackets and tries to find a matching field in the component. It will then set the value to that field. 

Imagine a DetailsComponent that is supposed to display a model object. An example could be a UserDetailsComponent displaying a user domain model.

@Input()
user: User;

The template of the parent component contains:

<user-details [user]="user"></user-details>

In this example, the user variable used as value can be created by a *ngFor directive or can come from somewhere else. It will be supplied by the parent component in most cases.

The NgClass Directive

The NgClass directive can add or remove CSS classes to a DOM element. It expects an object as a parameter. The object contains the intividual CSS classes as properties and boolean values that either add that particular class when the boolean value is true or remove that class when the value is false. Instead of hardcoded booleans, the boolean value can be returned from a method in the component.

<div [ngClass]="{selected: selected(), alarm: alarm()}"></div>

Two-way Data Binding

Two-way Binding uses square brackets containing braces, containing the value like this: [(attr)]=”value”

The banana-in-a-box syntax is used to send data from the frontend to the component and also from the component to the ui.

<input type="text" class="form-control" id="name" required       [(ngModel)]="model.name" name="name">

The code snippet above contains an input field from a template-driven form. The two-way binding is applied to the ngModel directive which is defined in the FormsModule. ngModel connects input from the template to the component.

The assignment to the Two-way data bound ngModel is using model.name as a value. model.name refers to the name field in the model field in the component that houses the template form.

This is a sentence that nobody will understand ever, so let me rephrase it. model.name refers to application defined fields. model is not a special keyword. It use a convention to name the target object that the form input is stored into, model. model.name is an example for a field of the model, which is called name. The two-way binding to model.name will store the user input into the model field of the component and inside the model it will store the input into the name property of the model object. If the object you store your data in is not called model, that is fine too, just specify the correct names in the two-way binding value.

Sending Events from a child to a Parent

Difference between a Content Child and a View Child

Angular ultimately renders a tree of components. A tree data structure defines nodes and their children. Children are nested into their parent nodes. In Angular components are nested into components.

There are two ways to nest components in Angular:

  1. View Children
  2. Content Children

Nesting a child component into a parent component is done by using the child components selector / tag in a template.

The distinction between view and component child is made by where, in which template the child component is used.

If the child component is used directly in the parent’s template, then the nesting is view nesting and the child is a ViewChild.

If the parent component is used in some “third-party” template and child components are used inside the opening and closing tag of the parent in the same arbitrary “third-party” template, then this is referred to as content nesting and the children are content children.

An example for view nesting is a fixed combination of components. A ColorPicker component might have a nested view child that draws the color space into a square or circle for the user to click into to select color in a explorative manner. Lets call this component ColorField. The ColorPicker component might have another nested view that represents the current color using sliders for the color’s red, green, blue and alpha values. Let’s call this component ColorCoordinates. In ColorPicker’s own template, the ColorField and ColorCoordinates components are  used, which by definition makes them view children.

An example for content nesting is a Tab component which is used in the template of a Dashboard component. As content children, the Tab component will have several TabPane components, that the user can switch between. Instead of inserting TabPane components directly into the Tab component’s template as view children, the TabPane components are added as nested tags to the Tab-tag in the Dashboard component’s template. This allows the user of the Dashboard component to add as many TabPanes to the Tab component as they want or need. Applying this idea further, the content on the TabPane components again is added directly in the Dashboard component’s template which makes it another example for content nesting.

A component can have View and Content children at the same time. A component can also have neither View nor Component children at all.

The interesting question is, when a component has ViewChild or Content components, what can it do with those? The answer is that the component class will have references to those children and call call methods on those children components inside it’s own code.

Sometimes, classes annotated with the @Component decorator are refered to as the component’s controllers. Having View- or Content-Children is a way for the parent component’s controller to access the controllers of the component’s children.

Angular Deep Dive

In Angular you define components and their templates in Angular’s syntax. The browser understands JavaScript. How does Angular translate all your components, bindings and templates to typescript and from typescript to JavaScript? This article contains the information I could find.

Links

Ahead-of-time (AOT) compilation
Explanation Video of the Angular Compiler
Angular Code on GitHub

The need for a Compiler

The answer to the question how Angular converts the Angular syntax to JavaScript is that Angular contains it’s own compiler. This compiler converts templates to TypeScript and feeds that TypeScript to a TypeScript compiler for finding type errors. It will then output messages for mistakes you did in writing your templates. This is necessary because Angular templates can contain logic such as referencing variables defined elsewhere, using pipes or using directives (ngIf, ngFor, ngSwitch, ngModel, ngStyle, …). The code generated for type checking templates is never going to be executed in the browser, it is purely for outputting errors to the user!

Also the compiler will generate typescript code for the components you write. This code will actually run inside the browser.

The need for a Runtime

The compiler takes a component definition including the template and after type checking (see above) turns it into a ComponentDefinition. The runtime can execute the ComponentDefinition inside the browser.

The runtime can understand the and execute the ComponentDefinitions. The question is, why is a ComponentDefinition not capable of running by itself as it is converted to JavaScript from TypeScript and JS is runnable in a browser!

The answer why a runtime is required is: