Slide 1

Slide 1 text

Future Proof Frontend Coding De-couple Your Dependencies

Slide 2

Slide 2 text

Bilal Çınarlı Frontend Architect Software Engineer @Adidas @bcinarli github.com/bcinarli bcinarli.com

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Frontend Development

Slide 5

Slide 5 text

Some think, it is an art Some think, it is the biggest pain

Slide 6

Slide 6 text

However, everybody agrees on the constant change in our landscapes

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Keys to keep up with the change; Organization, Standardisation, De-coupling

Slide 11

Slide 11 text

Organization

Slide 12

Slide 12 text

Define your folder structure based on their functionalities

Slide 13

Slide 13 text

Think of everything is sort-of a pluggable component. In most cases, when you remove the folder, you should expect no traces left.

Slide 14

Slide 14 text

// DON’T . ├── controllers | ├── cart.js | └── checkout.js ├── models | ├── cart.js | └── checkout.js └── views ├── cart.pug └── checkout.pug // DO . ├── cart | ├── index.js | └── template.pug └── checkout ├── index.js └── template.pug

Slide 15

Slide 15 text

…and tests are a part of your components.

Slide 16

Slide 16 text

// add test specs . ├── cart | ├── index.js | ├── test.spec.js | └── template.pug └── checkout ├── index.js ├── test.spec.js └── template.pug

Slide 17

Slide 17 text

Separate config and scripts away from your components.

Slide 18

Slide 18 text

. ├── config | ├── index.js | └── server.js ├── scripts | ├── build.sh | └── post-install.sh ├── test | ├── index.js | └── setup.spec.js ├── cart | ├── index.js | ├── test.spec.js | └── template.pug └── checkout ├── index.js ├── test.spec.js └── template.pug

Slide 19

Slide 19 text

Standardisation

Slide 20

Slide 20 text

Standards help to keep your code in order.

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

Test different coding standards, pick the best according to your needs.

Slide 23

Slide 23 text

Idiomatic.js

Slide 24

Slide 24 text

Use linters to have a shared, automatically controlled coding style across the project.

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

Use babel to get the benefits of modern coding

Slide 27

Slide 27 text

[1, 2, 3].map(n => n ** 2); [1, 2, 3].map(function (n) { return Math.pow(n, 2); });

Slide 28

Slide 28 text

Clean Coding reduces your technical debt

Slide 29

Slide 29 text

Cost of Chance (CoC) Time Actual CoC Responsiveness to Change Optimal Responsiveness Optimal CoC Responsiveness Technical
 Debt

Slide 30

Slide 30 text

Follow a naming convention, be concise, stay DRY, and constantly refactor your code

Slide 31

Slide 31 text

De-Coupling

Slide 32

Slide 32 text

JavaScript projects have and average of 650 to 1000 dependent modules

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

In each method you add to your app, keep in your mind if it is reusable?

Slide 35

Slide 35 text

Pipe method is a way to have an abstraction with different operations in a function

Slide 36

Slide 36 text

const toSlug = input => { let str = input.toLowerCase(); str = str.split(' ').join('-'); str = encodeURIComponent(str); return str; };

Slide 37

Slide 37 text

const toSlug = input => encodeURIComponent( join('-')( map(toLowerCase)( split(' ')( input ) ) ) ); toSlug('Hello World’); // hello-world

Slide 38

Slide 38 text

const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x); const toSlug = pipe( split(' '), map(toLowerCase), join('-'), encodeURIComponent ); toSlug('Hello World’); // hello-world

Slide 39

Slide 39 text

const toSlug = pipe( trace(input), split(' '), map(toLowerCase), trace('Mapped String'), join('-'), trace('Joined String'), encodeURIComponent );

Slide 40

Slide 40 text

Rule of thumb: Separate your code from your dependent codes.

Slide 41

Slide 41 text

Create wrappers for third-party codes that you are going to use

Slide 42

Slide 42 text

const {logs: showLogs} = require('./config'); const chalk = require('chalk'); const log = (...args) => { if(showLogs === 'none') { return; } console.log(...args); }; const info = (...message) => { log(chalk.blue('info'), ...message); }; const success = (...message) => { log('', chalk.green('success'), ...message); }; const error = (...message) => { log(chalk.red('error'), ...message); }; const warn = (...message) => { log(chalk.yellow('notice'), ...message); }; module.exports = { log, info, success, error, warn };

Slide 43

Slide 43 text

const depend = require('depended-module'); const getResource = url => { // your logic // depended code let fetched = depend.get(url, options); // some more logic return data; }; const putData = (url, data) => { // your logic // depended code let fetched = depend.put(url, dataToStore); // some more logic return result; }; module.exports = { getResource, putData };

Slide 44

Slide 44 text

Proxy can be used for between your code and your dependency code for having a standardised set of methods.

Slide 45

Slide 45 text

Proxies are middleware for JavaScript objects

Slide 46

Slide 46 text

const wrap = obj => { return new Proxy(obj, { get(target, propKey) { console.log(`Reading property "${propKey}"`); return target[propKey]; } }); }; const object = {message: 'hello world'}; const wrapped = wrap(object); console.log(wrapped.message); // Reading property "message" // hello world

Slide 47

Slide 47 text

const {METHODS} = require('http'); const api = new Proxy({}, { get(target, propKey) { const method = METHODS.find(method => propKey.startsWith(method.toLowerCase())); if (!method) { return; } const path = '/' + propKey .substring(method.length) .replace(/([a-z])([A-Z])/g, '$1/$2') .replace(/\$/g, '/$/') .toLowerCase(); return (...args) => { const finalPath = path.replace(/\$/g, () => args.shift()); const queryOrBody = args.shift() || {}; // You could use fetch here // return fetch(finalPath, { method, body: queryOrBody }) info(method, finalPath, queryOrBody); }; } } );

Slide 48

Slide 48 text

const {METHODS} = require('http'); const api = new Proxy({}, { get(target, propKey) { const method = METHODS.find(method => propKey.startsWith(method.toLowerCase())); if (!method) { return; } const path = '/' + propKey .substring(method.length) .replace(/([a-z])([A-Z])/g, '$1/$2') .replace(/\$/g, '/$/') .toLowerCase(); return (...args) => { const finalPath = path.replace(/\$/g, () => args.shift()); const queryOrBody = args.shift() || {}; // You could use fetch here // return fetch(finalPath, { method, body: queryOrBody }) info(method, finalPath, queryOrBody); }; } } );

Slide 49

Slide 49 text

const {METHODS} = require('http'); const api = new Proxy({}, { get(target, propKey) { const method = METHODS.find(method => propKey.startsWith(method.toLowerCase())); if (!method) { return; } const path = '/' + propKey .substring(method.length) .replace(/([a-z])([A-Z])/g, '$1/$2') .replace(/\$/g, '/$/') .toLowerCase(); return (...args) => { const finalPath = path.replace(/\$/g, () => args.shift()); const queryOrBody = args.shift() || {}; // You could use fetch here // return fetch(finalPath, { method, body: queryOrBody }) info(method, finalPath, queryOrBody); }; } } );

Slide 50

Slide 50 text

const {METHODS} = require('http'); const api = new Proxy({}, { get(target, propKey) { const method = METHODS.find(method => propKey.startsWith(method.toLowerCase())); if (!method) { return; } const path = '/' + propKey .substring(method.length) .replace(/([a-z])([A-Z])/g, '$1/$2') .replace(/\$/g, '/$/') .toLowerCase(); return (...args) => { const finalPath = path.replace(/\$/g, () => args.shift()); const queryOrBody = args.shift() || {}; // You could use fetch here // return fetch(finalPath, { method, body: queryOrBody }) info(method, finalPath, queryOrBody); }; } } );

Slide 51

Slide 51 text

// GET / api.get(); // GET /users api.getUsers(); // GET /users/1234/likes api.getUsers$Likes('1234'); // GET /users/1234/likes?page=2 api.getUsers$Likes('1234', { page: 2 }); // POST /items with body api.postItems({ name: 'Item name' }); // api.foobar is not a function api.foobar();

Slide 52

Slide 52 text

What About HTML & CSS?

Slide 53

Slide 53 text

Keep HTML and CSS separate in your source code 
 and never inline manually

Slide 54

Slide 54 text

// DON’T

Hello World!

// DO .content-text { margin: 10px 0; padding: 0; }

Hello World!

Slide 55

Slide 55 text

Always think about specificity in CSS, try to avoid creating specific selectors

Slide 56

Slide 56 text

// DON’T #main .article .title span { font-size: 32px; font-weight: bold; } // DO .main-article-title { font-size: 32px; font-weight: bold; }

Slide 57

Slide 57 text

Do not write the code you are going to overwrite

Slide 58

Slide 58 text

// DON’T .content { display: flex; max-width: 1280px; margin: 0 auto; } .article { width: 900px; } .supplementary { width: 380px; } @media screen and (min-width: 48.0625em) and (max-width: 64em) { .article { width: 644px; } } @media screen and (max-width: 48em) { .content { flex-direction: column; } .article, .supplementary { width: 100%; } } // DO .content { max-width: 1280px; margin: 0 auto; } @media screen and (min-width: 48.0625em) { .content { display: flex; } .article { flex: 1; } .supplementary { width: 380px; } }

Slide 59

Slide 59 text

Use Postcss, Autoprefixer, and Variables that you can update your support by compiling

Slide 60

Slide 60 text

// In your CSS ::placeholder { color: gray; } // Output after compiling ::-webkit-input-placeholder { color: gray; } :-ms-input-placeholder { color: gray; } ::-ms-input-placeholder { color: gray; } ::placeholder { color: gray; }

Slide 61

Slide 61 text

Your app should not know what the dependencies are in behind the curtains you are using.

Slide 62

Slide 62 text

It should only aware of which functions are available for a particular action.

Slide 63

Slide 63 text

Every dependency comes with a technical debt for the future.

Slide 64

Slide 64 text

Thank you @bcinarli