The Design of Web APIsの読書感想文(7章まで)

www.manning.com

The Design of Web APIsは我流でAPI設計をやってしまっていた自分にとって良書でした。 知らなかった事・気がついた事等を忘れないように箇条書きにしました。 7章以降も少しずつ読んでいこうと思います。

ch1: what is api design?

  • APIの基礎的な部分を説明した章
  • 酷いドローンのコントローラ設計を題材にして話が進んでいく
  • public apiの場合、コロコロ使い勝手を変えることが出来ないし収益に関わる部分だから、設計がより一層シビアになる
  • RPC, SOAP, REST, gRPC, GraphQL等いろいろな通信のための手段があるが、そこだけを勉強しても良いAPI設計を作ることが出来ない
  • APIを使う側のユーザが達成したいゴールを意識することが大事
  • どのように使われるのか、誰が使うのかといったユースケース的な情報が大事になってくる

ch2: Designing an api for its users

  • ずっと押しっぱなしにしとかないと動かない酷い設計の電子レンジとショッピングサイトのwebAPIが題材になっている
  • ユーザー目線を持つことが大事
  • 内部の仕様を漏らすようなことをしない。ユーザーが知らなくていい部分には蓋をして見えなくする
  • APIの実装漏れや分かりやすさを追求するために「API goals canvas」を作成する
  • API goals canvas: Whos, Whats, Hows, Inputs, Output, Goalに着目する
  • コンウェイの法則(組織内部でとっているコミュニケーションがシステム設計に現れる法則)
  • ビジネスロジックアーキテクチャ、DBの名前等がAPIに漏れ出していたら注意。※ ユーザのゴールに着目すること

画像は自分で作ってみた動物園APIAPI goals canvas

ch3: Designing a programming interface

  • RESTの説明から入る
  • ch2で作ったAPI goals canvasをもとにRESTに書き起こしていく
  • リソースの関係性を洗い出すことが大事。has a, has many
  • goalを書いてその動詞に注目する。add, replace, create, delete等
  • addとsearchの関連性に注目
  • 例えば、productにitemを追加する。productからitemが検索される。productとitemを親子関係で表現できる
  • itemを作ったらIDを返却する
  • PATCHは部分更新
  • PUTは更新だけでなく存在しない場合に作成しにかかる。save的な感じ。
  • DELETEは更新をかけてユーザから見えなくする"ソフトデリート"でもDELETEを使ってOK
  • ユーザーが達成したいゴールを見直してパラメータを削っていく
  • HTTP メソッドにマッピングできなかった場合 => アクションリソース(checkoutみたいな)
  • 名詞ではなくcheckoutのような動詞混ざりのエンドポイントの場合RESTで表現するのが難しくなる
  • 無理やりRESTに全てハメこむのはユーザフレンドリーではない。アクションリソースで整えるのも大事。
  • RESTの原則と可読性のバランスを取ることが大事。

ch4: Describing an API with an API description format

  • OASを紹介する章
  • スプレッドシートを使うよりOASを使った方が他のライブラリを適用できるため恩恵がある
  • swagger以外にもReDocなどOASファイルを表示するUIに関しては複数ある
  • 以降記述の仕方等は前職で使っていたので流し読み
  • 次の職場で使う時に以下のopenapi-mapに目を通しておいた方がよさそう

openapi-map.apihandyman.io

ch5: Designing a straightforward API

  • 使いやすく・分かりやすいAPIを定義するためにどうすればいいのかを考える章
  • バックエンド側でenumを変換してnameに変換する(前職ではフロントで実施してしまっていた。フロントの責務が増えるので確かに微妙だった)
  • フォーマット関連の処理はMUIのDataGrid等のライブラリで提供されてはいるもののバック側でやってしまった方がいいかも。(SPA構造にする時だけ使うものだった?)
  • この章ではエラーを3つに分離(Surface: 400, Business: 403, InnerControl and Unexpected: 500)
  • 前職では、SurfaceとBusinessを同じステータスで返却してしまっていた
  • 分かりやすいエラーメッセージを返却するために要素ごとに情報を作成する
{
  message: XXX,
  errors: [
    {
      要素名: A,
      エラー種別: XXX,
      メッセージ: XXX
    },
    {
      要素名: B,
      エラー種別: XXX,
      メッセージ: XXX
    },
  ]
}
  • 成功ステータスは200以外にも201と202が存在する
  • 作成した時は201を返却する
  • 遅延処理が発生するかもしれない処理が成功した事に対して202を使用する
  • 201の場合、すぐに完了したことを表現し202の場合、まだ処理中のことを表現する(送金中とかメール送信中とか)
  • 前職では全て200で返却してしまっていた
  • 遅延処理の場合、HTTPステータスだけでは不十分なので別途通知を送るなど対応が必要なので注意

ch6: Designing a predictable API

  • 5章に引き続きさらにAPIを使いやすくする方法が掲載されている
  • 命名規則の統一(createdAt,DateTimeOfUpdateなどごちゃつかせない)
  • Formatの統一(色々な時間フォーマットで返さない)
  • データ構造の統一
  • content negotiationに包めるものは、parameterに入れない

developer.mozilla.org

  • ページネーションにRangeヘッダーを使う例も乗っていたがバイナリーファイルを扱うのが目的なのでpageSizeとpageで管理した方がよさそう

developer.mozilla.org

  • ソートパラメータの指定方法の一例: sort=-amount,+date
  • meta_data: paginationに必要なデータやアクションが実行可能なことを表現するデータ。返却するデータの本質とは関係ない。操作に関連する物。
  • hypermedia APIs: レスポンスの中にurlが入っているAPI
  • URLを事前に知らなくても情報に辿り着ける。利用者(フロント側)でURLを定義しないくていいので改修がスムーズになる。
{
  _links:{
    self:{ 
      href: "url",
    },
  
    next: {
      href: "URL"
    },
    prev: {
      href: "URL"
    }
  },

  properties:{
    ...
  }
}

stateless.co

ch7: Designing a concise and well-organized API

  • データ構造のまとめ方について紹介する章
  • ネストさせてデータをグループ化させ可読性を向上
{
  memberName: xxxx,
  school:{
    name: xxxx,
    address: xxxx
  }
}
  • 重要なプロパティを上にする
  • OAS: タグ付けしてAPIをグループ化
  • 入力は可能な限り少なくネストも少なくする(推奨3段階まで)
  • 出力のネストも可能なら三段階までを推奨
  • Avoid creating does-it-all goals(何でも出来るゴールの設定をしない)

「Rubyで実装するフルスクラッチ三目並べ」という名前でgitbook書いてみました

1 ~ 2年前に研修用に作ってWEB公開するのを忘れていたので、さっき公開してきました。
今見ると結構荒削りな所がある(変数名とか内容とか)ので気が向いたら直していこうと思います。

kashiwara.gitbook.io

対象は誰なのか

  • プログラミングに興味があって基礎構文をやった方
  • dockerを使って開発してみたい方
  • 簡単なゲームを作ってみたい方
  • 単体テストを実装してみたい方 などなど

何で作ったのか

以下のような悩みを持つ人が前職場に多かったからです

  • 社内にプログラミングのチームに入りたいけど何から勉強したらいいか分からない
  • プログラミングスクールに通っていて成果物が出来上がってるのに、何故か現場のコードが読めない

元々僕がdiscord上で教えていましたが、誰でもトライできるように本にしました。

まとめ

本の途中で静的解析ツールを入れてコードをフォーマットさせるのですが フォーマットさせる前とさせた後のコードを管理しなければならず結構大変でした。 本を書くのって結構体力がいるのだなと思いました。

HaskellでLeetCodeのTwoSumを解いてみた

転職活動を終えて時間に余裕が出てきたので、最近Haskellで遊んでいます。
LeetCodeのTwoSumをHaskellで解いてみました。

TwoSum

今回トライした問題

leetcode.com

レポジトリ

Haskell勉強用に作ったレポジトリです。
docker-compose upで環境が立ち上がりテストコードを実行することができます。

github.com

回答

リスト内包表記を使ってみました。
遅延評価使ってるのとzipでindex値を出すところがミソです。

module TwoSum where
    pickIndex' :: [(Int, Int)] -> [Int]
    pickIndex' [] = []  
    pickIndex' (x:xs) = [fst x, snd x]

    twoSum :: [Int] -> Int -> [Int]
    twoSum xs num = pickIndex' [ (i, j) | (x, i) <- zip xs [0..], (y, j) <- zip xs [0..], x + y == num, i /= j]

テストコード

TwoSumのテストコードです。

import Test.HUnit
import TwoSum

testTwoSum :: Test
testTwoSum = "twoSumを検証する" ~: test
    [ "3の合計値を算出するindexは [0, 1]" ~: twoSum [2,7,11,15]  9 ~?= [0, 1],
      "6の合計値を算出するindexは [1, 2]" ~: twoSum [3,2,4]  6 ~?= [1, 2],
      "6の合計値を算出するindexは [0, 1]" ~: twoSum [3,3] 6 ~?= [0, 1]
    ]

main :: IO ()
main = do
    runTestTT (TestList [testTwoSum])
    return ()

Haskellは3~4年前に一回触ったきりだったのですが 久しぶりに触ると新鮮で楽しいです。

再帰の組み方とか勉強になります。

I learn English by using ChatGpt at latest

背景

今、ChatGptを使った英語学習がいい感じになる、とチームで話題になっています。
そこで、業務に出てきた調べ物をChatGptに英語で聞いてみたところ結構勉強になりました。 その時の質問に関してまとめました

(練習のために今回は英語で書きました)

use chatgpt to improve English skill

I learn English by using ChatGpt at latest.
There's something I don't understand, then I send English message to ChatGpt.
By doing so, I think improve my English skill.
I will introduce question to ChatGpt.

about method name

I am thinking about method name. this method decide whether to display the other component. do you have good idea?

ChatGpt return suggested method name.

isComponentVisible()
shouldRenderComponent()
displayComponentIf()
determineComponentVisibility()
showComponentWhen()
checkComponentVisibility()
allowComponentDisplay()

about jest

How to check whether return null from react component using by  jest

ChatGpt return jest method and sample code.

import React from 'react';
import { render } from '@testing-library/react';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('should return null', () => {
    const { container } = render(<MyComponent />);
    expect(container.firstChild).toBeNull();
  });
});

about Markdown

I want to make table that is maked markdown.
first columns is  name.
second columns is  age,
and thierd column is  birthday.
If you can make above markdown table.
please insert  three sample data.

ChatGpt return markdown table with sample data.

| Name      | Age | Birthday    |
|-----------|-----|-------------|
| John      | 30  | 1993-05-15  |
| Sarah     | 25  | 1998-12-10  |
| Michael   | 28  | 1995-09-22  |

about golng sorce code

Please make below program used by golang.
1: get current DateTime.
2: convert format to YYYY/MM/DD
3: convert result of 2 to string type.
4: return result of 3 and  result that is error.

please define method.

ChatGpt return golang sorce code.

package main

import (
    "fmt"
    "time"
)

// Define a method to get the current DateTime and format it as "YYYY/MM/DD"
func formatCurrentDateTime() (string, error) {
    currentTime := time.Now()
    formattedTime := currentTime.Format("2006/01/02")

    return formattedTime, nil
}

func main() {
    // Call the method to get and format the current DateTime
    result, err := formatCurrentDateTime()

    if err != nil {
        fmt.Println("An error occurred:", err)
        return
    }

    fmt.Println("Formatted DateTime:", result)
}

about SQL query

I want to know that how to get columns name from mysql db, can you create sql query?

ChatGpt return SQL query, but it contains unnecessary data, so I heard again.

If possible, I want to get only column name, this sql query result contains unnecessary data.

ChatGpt return Improved SQL query.

SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'your_table_name';

conclusion

It is difficult to experience that write English in Japanese work environment.
By using ChatGpt during working, You can gain experience in writing skill .
I want to continue this learning method.
It seems that ChatGpt also can understand voice message.
So I want to practice speaking.

プロダクトマネージャーのしごとを読んだ

背景

先日リファレンスチェックを実施していただき自分の弱みに触れる時間があった。
どうも自分は技術思考にかなり寄っているらしく 緊急対応然り何かトラブルが発生した場合に、人とコミュニケーションを取って解決するのではなく、技術で突破しようとする癖があるらしい。
そういったフィードバックをいただいた訳だが、改めて自分のやり方を考えてみると確かに当てはまった。 納期に間に合わなさそうとなると設計を変更して工数を短縮するし、フロントの描画が遅いとなるとコンポーネントの最適化に走る。
そこで、技術以外の解決方法という思考を身につけるため、手に取った本がプロダクトマネージャーのしごとだった。

www.oreilly.co.jp

そもそもなんで技術寄りになってしまうのか

理由は非常に単純でだから。
コミュニケーションをとって折半案を出すというのは、対人になる。
特にリモートだと非同期コミュニケーションが常に発生する為より難易度が向上する。
対して技術でどうにかするというのは、自分との同期コミュニケーションになるので、凄く楽。
ただ、それが本当にプロダクトに良い影響を与えてるとは限らない。
悪い影響を与える方が大きい可能性があるということを本書を読んで気付かされた。

アウトカムを意識する

アウトカムのためのアウトプットというキーワードが本書に登場するが、まずこれが出来ていなかった。
役員会で機能と納期が決定されており、それを突破するためにひたすら実装するというスタイルでやってきた。
役員レベルで決まっていることになるので基本的に意見を覆すことは絶対にできない。
そこにはアウトカムを意識した開発はなく、よくわからないけど依頼されたから実装するというスタイルに陥っていた。
無駄になった機能の数は計り知れない。
この経験からプロダクトオーナーのような現場と上層部の認識をすり合わせる役目が必要なのだと感じた。

無理に権限を超えない

エンジニアの採用が行き詰まっていたので、エンジニア専用の企業noteを作成し文化を外部公開し応募者数を上げようとした事がある。
これは権限を超えた行為であり、かなりの代償を伴うことを知った。
メールの文言を一語一句役員が管理する会社だったので、外部に公開する文書に関しては厳しいレビューが入る。
エンジニアが自分達で運用し公開するくらいの温度感で考えていたので、当初考えていたコストと全く違った。
一つの物事にコストを割り当てると、もう一つの物事からは引かれることになる。
その結果発生するのは、プロダクトの質の低下。
無理に権限を超えて解決しようとすると本来の役目がおろそかになりかねないので注意が必要。

曖昧にする部分と確定させる部分をハンドリングする

本書には危険ワードの紹介として「よさそうですね」という言葉が載っている。
実際に実施するかしないか、ふわふわとした言葉なので確定させた方がいいとのこと。
役員が隣で働いているような職場なので、この状況は頻繁に発生していた。 この言葉を発した人間が高い権限を有している時は特に警戒すべき(その人の発言で180度ガラッと変わる可能性があるので)。
要件に関しては確定ばかりさせるのも良くない。
あえて曖昧にしてチームに持ち込みメンバーの成長を促す必要性もある。 このことから、あえて曖昧にする部分と確定させる部分を自分の中で落とし込んでいく必要性がある。

好奇心は武器

人と円滑にコミュニケーションを取るためのコツはなんなのだろう。
その回答の一つが本書に記載されている「好奇心」である。
相手に興味を持って話しかけるか、そうでないかでは雲泥の差がある。
興味がない相手と会話するときは、双方伝える労力が大きくなるだろう。 いざという時の味方を増やすために、普段から好奇心を持ち相手に接する事が重要。

言い方一つ

「なぜ、こんなことをしたんですか?」と「いい感じですね!チームがどのように、そのアイデアに行き着いたのか教えていただけませんか?」
どちらが答えやすいだろうか。
大半の人は後者と答えるだろう。
どちらの質問も、聞いてることは同じようなことである。
しかし、感触がまるっきり違う。
言い方一つで良い方向にも悪い方向にも行くのがコミュニケーションの難しさ。
これはプロダクトマネージャーとか関係なく使うべきテクニックなので少しずつ慣れていこうと思う。

まとめ

「プロダクトマネージャのしごと」は技術でなくコミュニケーションを使った解決方法を学ぶことができる。 より運営寄りというかプロダクト寄りというかアウトカムを意識した志向も身につけていきたい。 解決方法は増えるに越したことがない。
技術・マネジメント両方で思考できたらと思う。

転職活動を終えました

3ヶ月ほど転職活動をして2社から内定をいただきました。
長かったしめっちゃ疲れました。
その時のことを色々と箇条書きできたらと思います。

転職エージェント

  • 主にスカウトが飛んでくる系のサイトを利用した(Forkwell, Findy)
  • 明確にやりたい事があるなら自分で求人を探した方が早いのだが、色々な会社を知りたい場合はスカウト系のサイトを使う方が良さそう
  • Findyのエージェントの方に職務経歴書と履歴書の添削をしていただいた。気合が入りすぎていたのかボリューミーすぎたので削って修正。
  • ありがたい事に1日に平均2スカウトくらいきて、ピーク時にはスカウトが80件以上溜まっていた。
  • スカウト内容を見るとgemの実装や勉強会の開催が評価されていた。コンパイラインタプリタの実装に関しては、あまり触れられなかった。
  • 年収は平均が下限600万以上。たまに800万円とか400万円がくる。会社によって結構バラバラ。

書類関係

  • 履歴書に関してはyagishを使った

rirekisho.yagish.jp

  • 履歴書に貼る写真はki-reiで撮影しスマホに取り込んでyagishへ転送

Ki-Re-i 証明写真画像データサービス Withスマホ|証明写真機Ki-Re-i|株式会社DNPフォトイメージングジャパン

findy-code.io

  • 誤字脱字に関してはchatGptを使ってチェック。かなり楽だった。

  • ただ、chatGpt側もかなりの確率で見逃すので誤字脱字のチェックに関してはエージェントの方にも協力を要請した方がいい

  • なのでchatGptのレビュー、自分のレビュー、エージェントのレビュー、の3段階にするのがおすすめ

  • 新卒の時は手書きだった分、電子データとして作成するのは非常に楽だった。

カジュアル面談

  • 新卒の時は履歴書を提出してそのまま一次面接という流れだったが、転職時にはカジュアル面談というフェーズが置かれているのが標準になっていた。
  • カジュアル面談を受けて仕事に対する認識の不一致を減らし選考に進むかどうかを決定することが出来る。
  • 回数を重ねるうちに面接対策にもなる。
  • リモートの場合、昼休憩の時間をカジュアル面談に充てたりする事もできる。
  • この時にシステムの構成や割り当てられている人数を聞いて技術負債や開発体制を想像していた
  • 会社説明を全くせず質問をひたすらしてくる実質一次面接のような企業もあった。
  • 忙しい時間の中で自分専用のスライド資料を用意してくれた企業もあった。

コーディング試験

  • HireRで技術テストを受けた

hireroo.io

  • HireRのエディタではなく普段使っている使い慣れているvscodeを使用しコピーして貼り付ける作戦で実施
  • HireRが使っているruby言語のバージョンをDockerイメージを使って再現してローカル側で動作確認できるように対応した。
  • 問題20問とコーディングテストを30分で終わらせて、残りの時間で見直しした。今思えば、もう少しエレガントにかけたと思う。
  • 宿題形式でないコーディングテストには要注意。タイムアタック制になるので、ひたすら集中して解かねばならない。

  • タイムアタック制のコーディングテストに対応すべく、テスト直前に下記ページの問題を30問ほど解いた

leetcode.com

  • 階段の段数問題と迷路の最適解を出力する問題だけアドリブで解けなかった。他の問題は大体15分ほどで解けたと思う
  • 新卒の時に受けたSPIやCAB/GABを採用している企業が無くて助かった。個人的にはコーディング試験や技術試験の方が楽だった。

書類選考

  • githubアカウントの提出を求められる場面もあったが普段からコミットしていることが多かった為突破できた。
  • 1社書類選考で落ちた。自己PR欄にずれたことを書いてしまったのが原因だと思う。
  • 証明写真に関して髭を力強く剃ってしまった為、赤みがかかりひげに見えたのが気になったが問題なかった。考えすぎだった。

面接

  • 基本オンラインだしスーツに着替えなくても面接を受けられたのが嬉しかった
  • 技術面と文化面の2軸で見られることが多い
  • 時間に関しては、大体どの企業も1時間ほど実施
  • 今思い返せば限られた環境の中でベストを尽くしているのかを掘り下げるような質問が多かった気がする

リファレンスチェック

  • 現状の仕事を現職の人間が評価するという面接フロー
  • 自分の普段の行いが評価されることになるので一切ごまかしが効かない
  • 幸いにも勉強会を開いていたので、その観点から書いてくださるチームメンバーの方がいて非常に助けられた(本当にありがとうございました)
  • 普段からしっかりと働いて周囲の評価を得ておくのって改めて大事なんだと気付かされた

まとめ

  • 転職はパワーがいる。何度も知らない人達と会話し、同じ自己紹介を何度もするのは精神的にくる。30代になってからの転職はより一層ハードルが上がるので、体力も時間もある20代後半で動けてよかった。
  • 転職するかしないかは置いておいて、今後も定期的に自分の市場価値というものを見直していきたいと思う

Rails7からDBレイヤーを剥がす

RailsからDBレイヤーを剥がす手法について記載します

環境

Rails 7.0.3

bin/setupファイルを修正

bin/setupファイルのdb:prepare部分を削除します

  # 以下2行を削除かコメント化
  puts "\n== Preparing database =="
  system! "bin/rails db:prepare"

config/enviroments/development.rbを修正

  # Raise an error on page load if there are pending migrations.
  # 以下1行を削除かコメント化
  config.active_record.migration_error = :page_load

  # Highlight code that triggered database queries in logs.
  # 以下1行を削除かコメント化
  config.active_record.verbose_query_logs = true

config/database.ymlを削除

config/database.ymlファイルを削除します

dbフォルダを削除

dbフォルダを削除します

modelsフォルダを削除

modelsフォルダを削除します

application.rbを修正

require "rails/all"

を以下に修正

require "action_controller/railtie"
require "action_view/railtie"

他に必要なrailsの機能があるなら、以下を参照しながらrequireする

github.com

rails/allを分解してrequireしたら以下のようなエラーが立ち上げ時に出るので 一つずつファイル内検索して対応する

 `method_missing': undefined method `action_mailer'

基本は設定のところばかりが引っかかるのでコメント化対応でOK

gemファイルからDB関連のライブラリを削除

MysqlやらsqliteなどのDB関連のライブラリを削除して 再度bundle installします

rails sしてエラーなく立ち上がったらOK

以上となります