29.hotfix|Git

致命的な不具合が見つかった際に行うhotfix。
今の会社の開発においてはよく聞くけど、自分でリリースをしてないので流していた。
改めて正確な意味を確認しようと思う。

リリース後、不具合が見つかったらhotfixブランチを用いて修正を行うことができる。

流れとしては、master→hotfixブランチを切って緊急の修正。
修正完了後、下記のようにそれぞれのブランチにマージ。
hotfix→master
hotfix→develop
 ↑
このそれぞれのブランチにマージする必要があるというのが、少々手間ではある。

その後リリースタグを打ち、hotfixタグは削除する。

以上がhotfixの流れ。

28.Rails|binding.pry

これまで余り使ってこなかったbinding.pryを使いこなせるようにしていきたいので、整理。

使い方①

例えば今の開発環境では、処理を止めたい箇所にbinding.pryと記述すれば、
Dcokerを立ち上げているConsole上で、その処理が止められた位置の前後で定義されている変数の中身などを確認できる。

使い方としては、エラーが発生していると思われる前の箇所にbinding.pryと記述するだけ。

使い方②

またbinding.pryを操作して、前後の処理をより詳細に確認したいなら。

Railsでは事前準備としてpry-byebugというGemが必要となるのでインストールし、
require 'pry'で呼び出す。

更にDockerを立ち上げた状態で、下記を実行してpry consoleを立ち上げる。

docker attach [コンテナ名]
  • サンプルコード
    6:         a = 1
    7:         b = 2
    8:         c = 3
    9:         binding.pry
 => 10:         sample = a * b * c
    11:        p sample
  • コマンド実行例
[1] pry(#~略~)> next
    6:         a = 1
    7:         b = 2
    8:         c = 3
    9:         binding.pry
    10:        sample = a * b * c
 => 11:         p sample
  • 変数名を指定して、中身を確認
[2] pry(#~略~)> sample
=> 6
よく使うコマンド
  • 現在のメソッド内で一行処理を進める
next
  • 次のメソッド内部に入る
step
  • pry(処理の中断状態)を終了し、プログラムの続きを実行
continue
  • 現在のメソッドを抜ける
finish
コマンド一覧(help)
Byebug
  backtrace          Display the current stack.
  break              Set or edit a breakpoint.
  continue           Continue program execution and end the pry session.
  finish             Execute until current stack frame returns.
  next               Execute the next line within the current stack frame.
  step               Step execution into the next line or method.

Bindingとは

そもそもBindingメソッドは、Kernel(OS上の中核処理を担うソフトウェア)上に定義されている。

Rubyではそれを組み込んで使用している。

docs.ruby-lang.org

27.TypeScript|Optional Chaining

前回に引き続きTypeScriptの?関連について。

Optional Chainingは、?.という構文のこと。
最も基本的な用法はプロパティアクセスの.の代わりに?.を使うもの。

You might find yourself using ?. to replace a lot of code that performs repetitive nullish checks using the && operator.

// Before
if (foo && foo.bar && foo.bar.baz) {
    // ...
}

// After-ish
if (foo?.bar?.baz) {
    // ...
}
  • Nullish Coalescing(Null合体演算子

The nullish coalescing operator is another upcoming ECMAScript feature that goes hand-in-hand with optional chaining, and which our team has been involved with championing in TC39.

You can think of this feature - the ?? operator - as a way to “fall back” to a default value when dealing with null or undefined. When we write code like

let x = foo ?? bar();

this is a new way to say that the value foo will be used when it’s “present”; but when it’s null or undefined, calculate bar() in its place.

Again, the above code is equivalent to the following.

let x = (foo !== null && foo !== undefined) ?
    foo :
    bar();

www.typescriptlang.org

注意点としては、【null:明示的に未設定/undefined:valueが存在しないこと】はチェックしているが、【空文字や0】は考慮されていないこと。

26.TypeScript|Optional Property

TypeScript上でよく?が付けられているのを見掛けるので、きちんと理解する為に整理していく。

TypeScriptには、Objectの持つpropertyにOptional Propertyという機能がある。
propertyの末尾に?を付けることで、そのpropertyが無い場合もあるということを表現することができる。

Not all properties of an interface may be required. Some exist under certain conditions or may not be there at all. These optional properties are popular when creating patterns like “option bags” where you pass an object to a function that only has a couple of properties filled in.

Here’s an example of this pattern:

interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig): {color: string; area: number} {
    let newSquare = {color: "white", area: 100};
    if (config.color) {
        newSquare.color = config.color;
    }
    if (config.width) {
        newSquare.area = config.width * config.width;
    }
    return newSquare;
}

let mySquare = createSquare({color: "black"});

Interfaces with optional properties are written similar to other interfaces, with each optional property denoted by a ? at the end of the property name in the declaration.

The advantage of optional properties is that you can describe these possibly available properties while still also preventing use of properties that are not part of the interface. For example, had we mistyped the name of the color property in createSquare, we would get an error message letting us know:

interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
    let newSquare = {color: "white", area: 100};
    if (config.clor) {
        // Error: Property 'clor' does not exist on type 'SquareConfig'
        newSquare.color = config.clor;
    }
    if (config.width) {
        newSquare.area = config.width * config.width;
    }
    return newSquare;
}

let mySquare = createSquare({color: "black"});
Readonly properties #

www.typescriptlang.org

つまり?を必須でないpropertyに付けることで、「必須ではないが指定するならこの型」といった宣言ができる。
必須でないpropertyを普通に定義した場合、そのpropertyが指定されないとエラーになってしまう。

25.Ruby-Grape|declared

RubyAPIの処理中でよく出てくる。
ぼんやりした理解だったのでおさらい。

Grape allows you to access only the parameters that have been declared by your params block. It filters out the params that have been passed, but are not allowed. Consider the following API endpoint:

format :json

post 'users/signup' do
  { 'declared_params' => declared(params) }
end

If you do not specify any parameters, declared will return an empty hash.

  • Request
curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d '{"user": {"first_name":"first name", "last_name": "last name"}}'
  • Response
{
  "declared_params": {}
}

github.com

APIの定義時に指定するparamsに基づいて、そこで指定されていないものは落とす。

params do
  requires :title, type: String
  requires :content, type: String
  optional :published, type: Boolean
end
…
post do
  article = Article.new(declared(params, include_missing: false))
end

例えば上記の例で、paramsの中でもしtitleが定義されていなければ、
declared(params)の中でtitleのキーとバリューはレスポンスの中に含まれなくなる(落とされる)。
その場合、declared(params)[:title]nilで返ってくる。

24.React|Mount/Unmount

Unmount…って何やったっけ?ってなったのでおさらい…。

Mount

Unmount

ja.reactjs.org

UNSAFE_componentWillMount()

componentWillMountという名前から変更となった(componentWillMountはバージョン17まで機能し続ける)。
なお現在ではこのライフサイクルメソッドは非推奨となっている。
ES6以前のconstructorが存在しなかった時には、初期化処理を行うのに適していた。

ja.reactjs.org

下記のようにconstructorを使用するように修正すると良い。

  • 変更前
class Hello extends React.Component {
    componentWillMount() {
      doSomething();
    }

  render() {
    return <div>{this.state.name} </div>
  }
}
  • 変更後
class Hello extends React.Component {
    constructor(props) {
      super(props);

      doSomething();
    }

  render() {
    return <div>{this.state.name} </div>
  }
}

componentDidMount()

DOMに関わる初期化処理を行いたい時に便利。

ja.reactjs.org

23.React/Redux|async/await

asyncの処理の中で呼び出している関数の頭にawaitが抜けていて、他のawaitの処理と順番が入れ変わってしまうという問題があった。
今回はJavaScriptにおけるasync/awaitについて、React/Reduxでの書き方も含めて確認したいと思う。

まずはasync/awaitと密接に結び付いている、Promiseの処理から確認していく。

Promise

JavaScriptの非同期処理の仕組みであり、成功時と失敗時にそれぞれコールバック関数を渡しておくことで、
非同期処理の終了時にそれらを実行してくれる。

  • 下記のように非同期処理を実装することができる。
const promise = new Promise((resolve, reject) => {
  // 処理
  
  if (/* 成功したかどうかの判定 */) {
    resolve(/* 処理結果 */);
  } else {
    reject(/* エラーオブジェクト */);
  }
});
  • しかし複数の非同期処理を組み合わせる際に、このコールバック処理は複雑化しやすくバグを生みやすくなる。
fetch("/api/hoge")
.then(response => {
  // responseからidを抽出する
  const hogeId = translateResponse(response);
  // hogeIdを使って別のAPIを呼び出す
  return fetch(`/api/fuga?hogeId=${hogeId}`);
})
.then(response => {
  // responseからidを抽出する
  const fugaId = translateResponse(response);
  // hogeIdとfugaIdを使って別のAPIを呼び出したいが、
  // hogeIdがこのスコープにないのでエラーが起きる
  return fetch(`/api/piyo?hogeId=${hogeId}&fugaId=${fugaId}`);
})

そこで、async/awaitを用いる方法を見ていきたい。

async/await構文

JavaScriptのベース(技術標準)となっているECMASCript
その中でも2017年に公開されたECMAScript 2017(ES8)以降、JavaScriptでこのasync/await構文が使えるようになった。

asyncとは、非同期関数を定義する関数宣言を指す。

async function sample() {
  return 1;
}

awaitは、async function内でPromiseの結果(resolve/reject)が返されるまで待機する(処理を一時停止する)演算子のこと。
async関数の中でのみ動作する。

async function sample() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 1000)
  });

  let result = await promise; // promise が解決するまで待機

  alert(result); // "done!"
}

sample();

上記のように複数の非同期処理も組み合わせて簡潔に書くことができる。

ja.javascript.info

React/Redux:async/await

React/Reduxの中で使う場合にも考え方は同じ。
下記のように書くことができる。

import React, { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { unwrapResult } from '@reduxjs/toolkit'

import { addNewPost } from './postsSlice'

export const AddPostForm = () => {
  const [title, setTitle] = useState('')
  const [content, setContent] = useState('')
  const [userId, setUserId] = useState('')
  const [addRequestStatus, setAddRequestStatus] = useState('idle')

  // omit useSelectors and change handlers

  const canSave =
    [title, content, userId].every(Boolean) && addRequestStatus === 'idle'

  const onSavePostClicked = async () => {
    if (canSave) {
      try {
        setAddRequestStatus('pending')
        const resultAction = await dispatch(
          addNewPost({ title, content, user: userId })
        )
        unwrapResult(resultAction)
        setTitle('')
        setContent('')
        setUserId('')
      } catch (err) {
        console.error('Failed to save the post: ', err)
      } finally {
        setAddRequestStatus('idle')
      }
    }
  }

  // omit rendering logic
}

redux.js.org