Michele Riva
Senior Software Architect @NearForm
Google Developer Expert
Microsoft MVP
MicheleRivaCode
Build scalable, high performances and modern web applications using Next.js, the React framework for production
MicheleRivaCode
MicheleRivaCode
MicheleRivaCode
node -p "Promise.reject()"Node 14.x
[DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated.
In the future, promise rejections that are not handled will terminate
the Node.js process with a non-zero exit code.MicheleRivaCode
node -p "Promise.reject()"Node 16.x
[UnhandledPromiseRejection: This error originated either by throwing inside of
an async function without a catch block,
or by rejecting a promise which was not handled with .catch().
The promise rejected with the reason "undefined".]MicheleRivaCode
const user = {
  data: {
    name: {
      first: "Michele",
      last: "Riva"
    }
  }
}
const middleName = user.data
  && user.data.name
  && user.data.name.middle
  || "No middle name";
console.log(middleName);Node 12.x
No middle nameMicheleRivaCode
const user = {
  data: {
    name: {
      first: "Michele",
      last: "Riva"
    }
  }
}
const middleName = user.data?.name?.middle ?? "No middle name";
console.log(middleName);Node 12.x
SyntaxError: Unexpected token '.'MicheleRivaCode
const user = {
  data: {
    name: {
      first: "Michele",
      last: "Riva"
    }
  }
}
const middleName = user.data?.name?.middle ?? "No middle name";
console.log(middleName);Node >14.x
"No middle name"MicheleRivaCode
import get from 'lodash/get';
const user = {
  data: {
    name: {
      first: "Michele",
      last: "Riva"
    }
  }
}
const middleName = get(user, "data.name.middle", "No middle name");
console.log(middleName);"No middle name"MicheleRivaCode
import reverse from 'lodash/reverse';
import isString from 'lodash/isString';
import isFunction from 'lodash/isFunction';
import isNull from 'lodash/isNull';
import split from 'lodash/split';
import filter from 'lodash/filter';
import map from 'lodash/map';
import keys from 'lodash/keys';
// and so on...MicheleRivaCode
import reverse from 'lodash/reverse';
// Array.reverse()
import isString from 'lodash/isString';
// typeof
import isFunction from 'lodash/isFunction';
// typeof
import isNull from 'lodash/isNull';
// typeof
import split from 'lodash/split';
// Array.split()
import filter from 'lodash/filter';
// Array.filter
import map from 'lodash/map';
// Array.map
import keys from 'lodash/keys';
// Object.keys
// and so on...MicheleRivaCode
MicheleRivaCode
MicheleRivaCode
Approach #1
MicheleRivaCode
1. Divide the codebase with codeowners
MicheleRivaCode
*                              @org/platform-team
# Design System
/packages/design-system/**     @org/fe-team
# Machine Learning models
/packages/machine-learning/**  @org/ml-team @org/data-science-team
# QA
/tests/cypress/**              @JohnDoe @JaneDoe
# Libraries, utilities
/packages/lib/**               @MicheleRiva @org/platform-team @org/arch-teamMicheleRivaCode
1. Divide the codebase with codeowners
2. Create/install linting rules (warning stage)
MicheleRivaCode
1. Divide the codebase with codeowners
2. Create/install linting rules (warning stage)
3. Create/install linting rules (error stage)
MicheleRivaCode
1. Divide the codebase with codeowners
2. Create/install linting rules (warning stage)
3. Create/install linting rules (error stage)
4. Assign the remaining parts to codeowners
MicheleRivaCode
1. Divide the codebase with codeowners
2. Create/install linting rules (warning stage)
3. Create/install linting rules (error stage)
4. Assign the remaining parts to codeowners
5. Run linter on the entire project an fix remaining parts
MicheleRivaCode
Pros
Cons
- Ensures correctness
- Incremental adoption
- Everyone is responsible
- Future-proof
MicheleRivaCode
Pros
Cons
- Ensures correctness
- Incremental adoption
- Everyone is responsible
- Future-proof
- Requires time
- Great team effort
- Needs a coordinator
MicheleRivaCode
Approach #2
codemod -m -d /home/jrosenstein/www --extensions php,html \
    '<font *color="?(.*?)"?>(.*?)</font>' \
    '<span style="color: \1;">\2</span>'"Codemod is a tool/library to assist you with large-scale codebase refactors that can be partially automated but still require human oversight and occasional intervention."
MicheleRivaCode
MicheleRivaCode
MicheleRivaCode
Parsing
Transformation
Codegen
MicheleRivaCode
Parsing
Transformation
Codegen
MicheleRivaCode
Step 1
Tokenization
var foo = 10var
foo
=
10input
tokens
MicheleRivaCode
Step 2
Syntactic Analysis
var foo = 10            =
           / \
          /   \
        var   10
         |
        fooinput
parse tree
(aka concrete syntax tree)
MicheleRivaCode
Step 2
Syntactic Analysis
var foo = 10       variableDeclaration
               |
               |
       vairiableDeclarator
          /         \
         /           \
   Identifier   NumericLiteralinput
abstract syntax tree (AST)
MicheleRivaCode
MicheleRivaCode
{
   "body":[
      {
         "type":"VariableDeclaration",
         "declarations":[
            {
               "type":"VariableDeclarator",
               "id":{
                  "type":"Identifier",
                  "name":"foo",
                  "loc":{
                     "identifierName":"foo"
                  }
               },
               "init":{
                  "type":"NumericLiteral",
                  "extra":{
                     "rawValue":10,
                     "raw":"10"
                  },
                  "value":10
               }
            }
         ],
         "kind":"var"
      }
   ]
}MicheleRivaCode
MicheleRivaCode
export const parser = "babel";
export default function transformer(file, api) {
  const j = api.jscodeshift;
  return j(file.source)
    .find(j.Identifier)
    .forEach((path) => {
      if (j(path).get().value.name.includes("oldName")) {
        j(path).replaceWith(
          j.identifier(path.node.name.replace("oldName", "newName"))
        );
      }
    })
    .toSource();
}
MicheleRivaCode
const oldNameFactory = () => {/* */};const newNameFactory = () => {/* */};input
output
MicheleRivaCode
import MyHeader from 'components/MyHeader';
export function MyApp(props) {
  return (
    <div>
      <MyHeader {...props.headerProps} />
      <p> Hello, {props.name}!</p> 
    </div>
  )
}export function MyApp(props) {
  return (
    <div>
      <p> Hello, {props.name}!</p> 
    </div>
  )
}input
output
MicheleRivaCode
export const parser = 'babel'
export default function transformer(file, api) {
  const j = api.jscodeshift;
  const withoutElement = j(file.source)
    .find(j.JSXElement)
    .forEach(function (path) {
      if (path.value.openingElement.name.name === "MyHeader") {
        path.prune();
      }
    })
    .toSource();
  const withoutImport = j(withoutElement)
    .find(j.ImportDefaultSpecifier)
    .forEach(function (path) {
      if (path.value.local.name === "MyHeader") {
        path.parentPath.parentPath.prune();
      }
    })
    .toSource();
  return withoutImport;
};MicheleRivaCode
export default function(context) {
  return {
    TemplateLiteral(node) {
      context.report({
        node,
        message: 'Do not use template literals',
        fix(fixer) {
          if (node.expressions.length) {
            // Can't auto-fix template literal with expressions
            return;
          }
          
          return [
            fixer.replaceTextRange([node.start, node.start + 1], '"'),
            fixer.replaceTextRange([node.end - 1, node.end], '"'),
          ];
        },
      });
    }
  };
};
MicheleRivaCode
MicheleRivaCode
Pros
Cons
- Quick action
- Requires less team effort
- Won't affect other teams directly
MicheleRivaCode
Pros
Cons
- Quick action
- Requires less team effort
- Won't affect other teams directly
- Requires good CS skills
- Tests are absolutely needed
- QA is a must
MicheleRivaCode
MicheleRivaCode
MicheleRivaCode
MicheleRivaCode
@MicheleRiva
@MicheleRivaCode
/in/MicheleRiva95
www.micheleriva.dev