# Frontend Back to the Basics

# 1. How a frontend engineer should work

# How frontend have changed

The term 'frontend' only appeared in 2010. Before that, web-developer did everything from front to back. Studying companies that survived the dot com bubble, Web 2.0 was made. These companies also used Ajax technology making it popular. In 2004, gmail was made with Ajax. It was extremely convenient. In 2006, Naver decided to make a similar mail system. Javascript became very popular during this time.

# FE Environment

  • Learn vi or vim. VScode might be restricted due to security policy. You could do simple edits using only vim and ipad in case of emergency.

  • Learn how to write good commit messages. NHN tech blog 좋은 커밋을 작성하기 위한 7가지 약속.

  • 생활코딩 지옥에서 온 GIT

  • Package manager : linux-aptitude, mac-homebrew, windows-chocolatte

  • Devdocs : 공식문서 레퍼런스만 모아놓았다. Dash-mac, Gill-windows

  • Shell : zet shell 을 쓴다.

  • terminal client : mac-iterm, windows-putty

  • virtual box : to test IE on mac. vmware and parallel is better but expensive.

  • N, MVN : manages multiple versions of node.js. Company projects tend to use older version of Node.js and personal projects use newer version. MVN has more users but N is more intuitive. Only for mac and linux. On windows you must use MVN for windows.

  • Ricecake : To make GIF. Github does not support mp4 or webm. But sometimes you need videos to explain how the code works. Recommends 8fps and only capturing needed area. Also can highlight mouse position and clicks. Can be used on windows and mac.

# What is a Frontend Engineer

  • Builds the meeting point between application and user.
  • Requires you to learn very diverse area. Photoshop, sketch, zeppelin.. Deploy.. UI UX
  • Is responsible for use convenience .
  • More and more function is moving to frontend domain.
  • HTML5 and CSS3 does not exist. After 2014, WHATWG makes HTML instead of W3C. There are no more version upgrades. But keeps updating as living standard.
  • You must constantly study to keep up.

# How to study as a FE Engineer

  • Too much to learn, can't learn all at once
  • Expand your domain, but go deeply only if you need.
  • There are 145 HTML tags. But only 40 of them are commonly used. Naver main page has only 30 HTML tags. Thus, you must focus on what to study instead of trying to do everything.
  • Read the documentation. Mozilla doc is good. Don't try to read everything perfectly at the first time. Come back often and read again. Reading unnecessary parts decreases interest. Repetition gives you much more insight (like games and movies).
  • Experience a lot. Companies are always looking for 'experienced' people. Work on personal projects to experience new technologies to prepare for the future.
  • Make what you need right now when you decide to do a personal project. This gives you motivation.
  • Write a blog to share knowledge. This solidifies your knowledge. Only share if you are 'certain'. Don't post wrong information. Takes time, but stays in your memory. Use short and exact sentences.
  • Check Github trending to see what technology is on the rise.
  • Follow mailing list and SNS to check trend
  • All framework has philosophy, understand it.
  • Atomic Design : Having components.
  • Coop with backend : Agree on API form and work independently. FE should come up with API input output structure.

# 2. Back to the Basics

  • Learn the jargons. 용어에 대한 지식이 실력에 대한 인상을 준다.
  • Learn the reason why you chose the framework. Don't say 'because its in fashion'.

# How a webpage is loaded

image-20201227004058155

image-20201227002649535

  • Unload : I will move to a different page. window:beforeunload can prompt the user asking 'will you leave this page?'.
  • Redirect : This part is optional. The server must send redirect signal for this event to happen.
  • AppCache : Before getting data from the server, check the browser for cache.
  • DNS TCP Request Response : Network. Check nameserver, get actual IP, request and response. Finally receives HTML.
  • Processing : HTML, CSS, JS, Images are all parsed and rendered. document:readystatechange shows domInteractive and domComplete.
  • document:DOMContentLoaded : HTML is read, parsed and DOM is completed. Before its painted to screen, JS adds functionality to the DOM. Images and videos are not loaded yet.
  • Load : Resources such as CSS, images, videos are loaded. These resources are loaded later than the DOM.

# Main components of Browser

image-20201227004605223

User Interface : The top part where you can type address, tabs, and other buttons.

Browser Engine : Bridge between UI and rendering engine.

Rendering Engine : The part that we see. Interprets HTML, CSS, JS and paints on the screen. Chrome has rendering engine for each tab.

Networking : HTTP request, response.

JS Interpreter : To interpret JS.

Data Persistence : Cookie and others

# Rendering Engine 동작 과정

image-20201227012909303

  1. Parsing : Browser reads HTML, CSS, JS and parses to understand. Stops parsing when it meets the <script> tag. Resume parsing when JS interpretation is finished. JS uses document write method to change the document's composition, so the parsing stops to wait. This is why the <script> tag should be at the end. Although not so important in modern web development. There are ways to not stop parsing even when the browser meets the <script> tag.
  2. DOM, CSSOM : Changes the HTML and CSS into object model to use in browser.
  3. Render Tree : DOM and CSSOM are combined to decide what element should be drawn in what style.
  4. Layout : Calculates each elements location and size. Not actually rendered yet.
  5. Render : Also known as paint and rasterize. Changes elements to pixel
  6. Compositing : Multiple layers are mixed together. This layer is not the z-index layer. When some conditions are met, layer are automatically made.
  • Skipping certain procedures is vital for maximum performance.

  • These steps are incrementally executed. Meaning it does not wait until the entire step is finished to go to the next step. For better UX.

# HTML

Originally, HTML was primarily designed as a language for semantically describing scientific documents.

HTML is semantic from the start. Don't spam divs and spans.

image-20201227013831215

Like Windows 10, HTML no longer have versions. Its now a living standard and keep updating its current version.

Using the right tags can also improve performance.

# Progressive Enhancement vs Graceful Degradation

With smartphones it became more and more difficult to fit every browser environment.

Graceful Degradation : Having a backup plan in case of failure. ex) Having a link to the video in case <video> tag is not supported

Progressive Enhancement : Hidden by default, checks if environment allows certain function. If allowed, adds function.

These are used in complement.

# CSS

There will never be a CSS4

CSS is now being updated by modules.

There are over 533 CSS properties. There's a need to focus on important ones. Most used CSS properties (opens new window).

# Layout

  1. Layout : Practice size and location often.

  2. Box-model : Every element is basically a box model. Content-box vs border-box. Default box-model is content-box, so the behavior may be different from what you think.

    image-20201227200310715

  3. Flexbox : New convenient way. Even Naver uses float on their layouts.

    image-20201227200706397

    The holy grail layout was notoriously hard to achieve before flexbox came out.

    display:flex or display:inline-flex makes the element into a flex container. Child elements (direct child, not descendant) are turned into flex item automatically.

    flex-direction:row The meaning of row is same as the 'writing direction'. If you use row in vertical writing environment, the row direction is vertical. This can be changed with writing-mode or direction.

    flex-wrap : how to position elements that go over the width? If wrap, positioned on the next line, if wrap-reverse, positioned on the upper line.

  4. Grid Layout : Unlike 1 dimensional flexbox, grid is about 2 dimension (such as the holy grail layout).

  5. Where to study layout :

    1. Flexbox Froggy
    2. learnlayout.com

# Logical properties and values

image-20201227202459104

image-20201227210631180

  1. CSS Logical Properties and Values Module : Uses logical properties to customize layout instead of physical properties.
  2. Inline and block :
    • Inline : Text writing direction
    • Block : Vertical to text writing direction
  3. Changes in 용어
    • size : used instead of width and height.
    • start : beginning of text direction.
    • end : end of text direction.

# BEM

https://naradesign.github.io/bem-by-example.html

# Margin Collapsing

image-20201227212335054

  1. Neighboring sibling elements' margin are collapsed
  2. Parent-child's shared margin is collapsed.
  3. Empty block's top-margin and bottom-margin is collapsed.

# JavaScript

  1. ECMA Script : ES6 means ES6 and after.
  2. ESM became the standard.
  3. Future : Third decade of JS. As browser and Node.js evolves, the need for Babel is decreasing. TypeScript, WebASM, Rust is on the rise. Webpack is dominating among bundlers.

# Lexical Environment

A lexical environment is a data structure that holds identifier-variable mapping. (here identifier refers to the name of variables/functions, and the variable is the reference to actual object [including function type object] or primitive value).

image-20201228125419547

  1. Definition : A Lexical Environment is a specification type used to define the association of Identifier (opens new window)s to specific variables and functions based upon the lexical nesting structure of ECMAScript code
  2. Includes environment record and outer property.
    1. The environment record is the actual place where the variable and function declarations are stored.
    2. The reference to the outer environment means it has access to its outer (parent) lexical environment.
  3. Execution context : Where JS code is executed. Every JS code is executed inside a execution context.
    1. Global execution context :
    2. Functional execution context :
    3. Eval function execution context : This sucks and there's no need for it anymore

image-20201228130213529

  • Function is null because its not a function context
  • hello function has an environment which is identical to the lexical environment.
  • There is no outer for GEC.

image-20201228130335263

  • Identifier is searched gradually from inner execution context to outer execution context

  • If identifier cannot be found even on the global execution context, uncaught reference error will happen.

  • Lexical scope can be approached from inner to outer but not vice versa.

  • Do not use var because lexical scope works differently.

# Closure

A closure is a function that has access to its outer function scope even after the outer function has returned. This means a closure can remember and access variables and arguments of its outer function even after the function has finished.

function person() {
  let name = 'Peter';
  
  return function displayName() {
    console.log(name);
  };
}
let peter = person();
peter(); // prints 'Peter'
1
2
3
4
5
6
7
8
9

This function can somehow access the variable of its outer function person even after that function has returned. So the displayName function is actually a closure.

function getCounter() {
  let counter = 0;
  return function() {
    return counter++;
  }
}
let count = getCounter();
console.log(count());  // 0
console.log(count());  // 1
console.log(count());  // 2


1
2
3
4
5
6
7
8
9
10
11
12
getCounterLexicalEnvironment = {
  environmentRecord: {
    counter: 0,
    <anonymous function> : < reference to function>
  }
  outer: <globalLexicalEnvironment>
}
1
2
3
4
5
6
7
countLexicalEnvironment = {
  environmentRecord: {
  
  }
  outer: <getCountLexicalEnvironment>
}
1
2
3
4
5
6

At let count = getCounter(); part, when the getCounter function finishes, its execution context is removed from the stack. But its lexical environment is still in the memory because its lexical environment is referenced by the lexical environment of its inner anonymous function. So its variables are still available in the memory.

Storing the anonymous inner function returned by getCounter function into the count variable. As count function is now a closure, it can access the counter variable of getCounter function even after getCounter() has returned.

At each call of count(), a new scope for the function is created, but there is only single scope created for getCounter function, because the counter variable is defined in the scope of getCounter(), it would get incremented on each count function call instead of resetting to 0.

When the count function is called, the JavaScript engine will look into the lexical environment of this function for the counter variable. Again as its environment record is empty, the engine will look into the outer lexical environment of the function.

The engine finds the variable, prints it to the console and will increment the counter variable in the getCounter function lexical environment.

# Execution Context

There can only be one currently running execution context (Because JavaScript is single threaded language), which is managed by a stack data structure known as Execution Stack or Call Stack.

# Strict Mode

Check scope.

# Asynchronous JavaScript

  • Functionality of JS mostly comes from external APIs. Asynchronous handling is a must.

  • JS is a single thread language. One action at a time.

  • Event loop and stack is used for scheduling.

# Event Loop

image-20201228130335263

  • 동시성 = concurrency : What to do when you want to do multiple things at once.
  • Each frame in Call Stack makes one execution context.
  • Call stack is LIFO, ;queue is FIFO
  • Event loop only works when call stack is empty.
  • UI update and user events are all handled in the same call stack. Having too much stacked could cause callback queues to be postponed for a long time -> Lagging experience

# Promise

A promise is an object which represents the result of an asynchronous operation which is either resolved or rejected. Promise is a returned object to which you attach callbacks, instead of passing callbacks into a function.

  • Three states : pending, fulfilled, rejected

    image-20201228142621080

  • Old style

    function successCallback(result) {
      console.log("Audio file ready at URL: " + result);
    }
    
    function failureCallback(error) {
      console.error("Error generating audio file: " + error);
    }
    
    createAudioFileAsync(audioSettings, successCallback, failureCallback);
    
    //Had to add success callback and failure callback as parameters each time, resulting in callback hell
    
    doSomething(function(result) {
      doSomethingElse(result, function(newResult) {
        doThirdThing(newResult, function(finalResult) {
          console.log('Got the final result: ' + finalResult);
        }, failureCallback);
      }, failureCallback);
    }, failureCallback);
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
  • Returning promise object

    const promise = createAudioFileAsync(audioSettings);
    promise.then(successCallback, failureCallback);
    
    //shorthand
    createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
    
    //We can use chaining to avoid callback hell
    doSomething()
    .then(function(result) {
      return doSomethingElse(result);
    })
    .then(function(newResult) {
      return doThirdThing(newResult);
    })
    .then(function(finalResult) {
      console.log('Got the final result: ' + finalResult);
    })
    .catch(failureCallback);
    
    //Using arrow function makes it simpler
    doSomething()
    .then(result => doSomethingElse(result))
    .then(newResult => doThirdThing(newResult))
    .then(finalResult => {
      console.log(`Got the final result: ${finalResult}`);
    })
    .catch(failureCallback);
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
  • resolve & reject

    function getData() {
      return new Promise(function(resolve, reject) {
        var data = 100;
        resolve(data);
      });
    }
    
    // resolve()의 결과 값 data를 resolvedData로 받음
    getData().then(function(resolvedData) {
      console.log(resolvedData); // 100
    });
    
    //reject
    function getData() {
      return new Promise(function(resolve, reject) {
        reject(new Error("Request is failed"));
      });
    }
    
    // reject()의 결과 값 Error를 err에 받음
    getData().then().catch(function(err) {
      console.log(err); // Error: Request is failed
    });
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

# Async Await

await can be only used inside async function.

# method vs function

In short: a method is a function that belongs to a class. In JavaScript, however, a method is a function that belongs to an object.

Another way to say it, it’s that a method is a function with a defined this

# Arrow function

  • Does not have its own bindings to this or super, and should not be used as methods.
  • One reason arrow functions were introduced was to alleviate scope ( this ) complexities and make executing functions much more intuitive.

Traditional functions default this to the window scope

window.age = 10; // <-- notice me?
function Person() {
  this.age = 42; // <-- notice me?
  setTimeout(function () { // <-- Traditional function is executing on the window scope
    console.log("this.age", this.age); // yields "10" because the function executes on the window scope
  }, 100);
}

var p = new Person();
1
2
3
4
5
6
7
8
9

Arrow functions do not default this to the window scope (opens new window), rather they execute in the scope (opens new window) they are created:

window.age = 10; // <-- notice me?
function Person() {
  this.age = 42; // <-- notice me?
  setTimeout(() => { // <-- Arrow function executing in the "p" (an instance of Person) scope
    console.log("this.age", this.age); // yields "42" because the function executes on the Person scope
  }, 100);
}

var p = new Person();
1
2
3
4
5
6
7
8
9

# viewport vs document vs window

# 3. Writing sustainable codes

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. - Martin Fowler

  • Intentions must be clear.
  • Easy to understand.
  • Dependency must be minimum.

# Debugging

  • Solve the reason, not the symptom.
  • Must have expected behavior
  • undefined errors are mostly from typos.
  • Typescript 는 정적에러가 있어서 미리 확인이 가능하다.
  • Unlike backend, frontend does not keep all the error logs.

# Testing

  • Edge case testing : Input improbable but possible values to see the result.
  • Plain goal
  • Fast and rapid
  • Find bugs

# TDD

  • Test Driven Development

  • TDD

    1. Make test first. Which obviously fails. Only make tests that will fail.
    2. Make code that passes test. Only make codes that will pass the test.
    3. Refactor to make code better. Delete duplicate etc
  • ODA principal

    1. Observation : Observe before you do anything.
    2. Decision : Decide how to fix
    3. Action : Actually fix
  • Repeat ODA until test passes.

# Refactoring

Leaving the function intact, changing the code to understand better. - Martin Fowler

  • When you're doing the same thing three times, its time for refactoring
  • Smelly codes
    • Huge function or class,
    • long function and class names,
    • duplicate codes,
    • Global variables
    • 과도한 중첩문
    • Too long identifiers
  • Before refactoring, test must be made first to ensure that function is intact.

How to refactor

  1. Divide and separate.

  2. Introduce medium variables.

  3. Using pipes instead of for loops

    image-20201228172252002

image-20201228172343383

  1. Use object literal instead of switch

    image-20201228172446334

image-20201228172457546

  1. When making changes to array, make a new one so its easy to trace the changes
  2. Use $ instead of + to combine strings.

# 4. How to improve your web-app performance by 200%

Make it work, Make it right, Make it fast -Kent Beck

  • Performance does not have high priority in the frontend area.

  • Knowledge of CDN and HTTP header overlaps with BE.

  • Performance = 1/ (Time * Resource)

  • Time : 초기구동시간 계산시간 반응시간

    • 초기구동시간

      image-20201228174329906

      image-20201228174356795

      image-20201228174414103

      • File download : Modern browser supports 6 동시 download per domain. More than that is sent to queue. If there are too many images and videos, these are slowly downloaded. Even JS and CSS files are downloaded entities. Slow loading of JS and CSS is very bad UX. Naver uses different domain for images files and script files for faster download. But from HTTP 2.0, this does not matter. Google uses HTTP 3.0 but most Korean government sites still uses HTTP 1.0. Also, keep file numbers low and sizes small. Use WebP images instead of JPEGs. ABIF is 50% of JPEGs. Google font provides great cache. WOFF2 is 30% smaller than WOFF1. You can also cherry pick only the letters you will use in case of Korean.

      • Contents Rendering : image-20201228175516234

      Users perceive left side to be faster. Always remember human experience matters most. Advertisements, comments, header, footer are not primary contents. It's ok to load asynchronously in that case. Also images/iframe/scripts should be lazy loaded. image-20201228175901223

      This is implemented natively in modern HTML.

      Use placeholders if loading takes time.

      • 인터랙션
    • Computation time

      • JS is single thread. Keep functions short so UI can respond under 0.1s in any case.
      • But JS can be multi thread. Worker thread can be used for longer functions.image-20201228180949895
      • Memoization : In case of same computations, remember the results.
    • Response Time : Slow animation is bad for UX. Doherty Threshold (under 400ms). Animations should be 60fps(modern monitors).

      • Rendering Order
        • JavaScript
        • Style
        • Layout
        • Paint
        • Composite
      • JS, style, layout, paint uses the main thread while composite uses compositor thread.
      • We should aim to use compositor thread instead of main thread. Check here (opens new window)
      • Use CSS instead of JavaScript when using animation.
      • Transform, translate, scale, rotate, opacity uses GPU acceleration.
      • width, height, padding, margin ,display changes layouts and uses many resources
      • color, background, outline, box-shadow uses paint and also uses many resources
      • Use requestAnimationFrame, Web animations instead of setTimeout
      • three.js and velocity.js are high performance animation library.
      • Minimize DOM access and update. This is very slow.
  • Resource : CPU, memory, network traffic

    • Using less resource is better
    • Not much to worry about CPU, power usage, storage.
    • Memory leak should be cared for. JS engine does garbage collecting by reference counting. Engine counts how many variable is referencing this object. If there is 0, the engine deletes it. Mark and sweep algorithm is used.
      • Allocate memory
      • Use memory
      • Release memory
    • Global variable and closure should be used with care because it can cause memory leak. Divide to smaller functions and modules.
    • Network traffic
      • Use minified JS and CSS
      • Use one or less framework. Don't use React and jQuery at one site.
      • Browser uses address name to store cache. Be careful not to add cache buster by mistake to the address. They will block cache.
Last Updated: 3/1/2021, 9:19:08 PM