LEFログ:学習記録ノート

leflog: 学習の記録をどんどんアップしていきます

Denoハンズオンに参加しました!🦕

deno-ja.connpass.com

Denoハンズオン&もくもく会:Fresh + KV - connpass

Denoハンズオンに参加しました!🦕

こちらの「Denoハンズオン&もくもく会:Fresh + KV」に参加しました!

2023年の12月(約3か月前)、timer.teamというWebアプリをリリースしたのですが、その際にDenoとFreshを主要技術として選択しました。*1

そのため今回のハンズオンを偶然見かけたとき、運命を感じました。

――これはもう、絶対に行くっきゃないぜ……!!

というわけで、久々に浅草に行ってきました🗼


ハンズオンではFreshの概要説明から始まって、実際にWebサイトを作りながら学ぶ形式でした。🍋

hashrockさんがZennの記事を作成してくださったおかげで、迷わずにハンズオンを進めることができました! ありがとうございます!

zenn.dev

_layoutファイルのネストやdeployctlを使ったデプロイ方法、拡張機能のKiviについて知らなかったのでとても参考になりました🙏


また、今回のハンズオンで色々な方とお話しすることができました。

緊張&口下手で、うまく喋れなかった気がしますが、皆さま暖かく答えてくださってとても嬉しかったです!

スタッフの皆様、お話ししてくださった皆様、ありがとうございました。✨

Photos

出発前

区立台東区民会館(駐車場側)

建物近くから見えたスカイツリー

建物正面。8階にレストランがありましたが所持金が少なかったので昼食を我慢しました……

キュートなDenoくんステッカー

会場入口

自宅でプリントアウトして持ってきたA4用紙が役に立って良かったです!!🦕

Next.js バージョンアップ時の Error: Parsing error: DeprecationError: 'originalKeywordKind' の対処法

TL;DR(解決法)

最新の@typescript-eslint/parserを明示的にpackage.jsonに入れてからnpm installする

npm install @typescript-eslint/parser --save-dev
npm install

具体的な経緯

Next.jsのバージョンアップ時に次のようなエラーが出た。

具体的にはnext build時に発生する。

Error: Parsing error: DeprecationError: 'originalKeywordKind' has been deprecated since v5.0.0 and can no longer be used. Use 'identifierToKeywordKind(identifier)' instead.

stack overflowでは次のような記事があった。

しかし、自分のpackage.jsonは下のようになっていて、実際にインストールされている@typescript-eslint/parserをアップデートすることができなかった。

【package.json

"devDependencies": {
    "@playwright/test": "^1.41.2",
    "@types/node": "^20.11.19",
    "@types/react": "^18.2.57",
    "eslint": "^8.56.0",
    "eslint-config-next": "^14.1.0",
    "sass": "^1.71.0",
    "typescript": "^5.3.3"
  }

package-lock.jsonを見てみると古いライブラリのままになっていた。

そのため、npm install @typescript-eslint/parser --save-devを実行して明示的にpackage.jsonに追加した後、npm installをしたら、無事にpackage-lock.jsonも更新されて動くようになった。

【package.json(追加後)】

"devDependencies": {
    "@playwright/test": "^1.41.2",
    "@types/node": "^20.11.19",
    "@types/react": "^18.2.57",
    "@typescript-eslint/parser": "^7.0.2",
    "eslint": "^8.56.0",
    "eslint-config-next": "^14.1.0",
    "sass": "^1.71.0",
    "typescript": "^5.3.3"
  }

これによってTypeScript5.2以降でも使えるようになる。 (package-lock.jsonからtsutilsの依存が消える)

いちばん大事なポイントは、最新のライブラリを明示的にpackage.jsonへと記述すること。

たとえeslinteslint-config-nextが最新の状態でも、それに依存したライブラリが最新のものになるとは限らないので、明示する必要がある。

@typescript-eslint/eslint-pluginが影響している場合もあるので注意。

【感想】マーティン・ファウラー『リファクタリング 第2版』―― ソフトウェア設計の入り口としてのコード整理

※この記事の『リファクタリング』という二重鉤括弧は、書籍そのものを示しています。それ以外の「リファクタリング」という単語は「コードの片付け」という意味合いで用いています。

なぜリファクタリングをするのか?

開発をするうえで、実装に関しては今まで鍛えてきた自信がありました。

しかし、設計という領域については自分はまだまだ未熟だと感じています。

2023年は主にbootcamp, 引用箱, timer.teamの3つのWebアプリの開発に携わりました。それらにおいて自分は「Issueというゴールを達成することができるか」という観点で開発していました。つまり、「実装できるかどうか」が最大の関心事で「どのように実装するか」についてはあまり気にしていませんでした。

そのままではいけないと感じたのはtimer.teamの開発が始まってからです。一番難しいところ……例えばBroadcastChannelやWebSocketに関しては純粋な実装力が必要でした。ただし、その後が問題で、その実装したコードをいかに整理するかという方法論を知らなければ、どんどんコードが複雑化してしまうことが分かりました。

複雑化すると、その後の実装が難しくなります。単純な機能を追加するだけなのに、入り組んだコードを解読する羽目になってしまうかもしれません。また、既存の機能を変更するのも大変になってしまいます。

次の画像は、『リファクタリング』に登場する図です。すぐれた設計であれば、機能の追加とプログラミングに掛かる時間は比例します。しかし、まずい設計であれば、一定以上の機能を追加すると、プログラミングに掛かる時間は膨大になります。

p.50「リファクタリングはプログラミングを速める」より

困難な状況を防ぐためには、早い段階で手を打つ必要があります。そのためには、一つの機能を実装すると同時に「小さな片付け」をするのが最適です。この小さな片付けこそがマーティン・ファウラーの言う「リファクタリング」です。

リファクタリング」という言葉が、現在のシステム開発において誤解されているケースは多いです。本来は、機能追加におけるちょっとしたコードの片付けのことを指し、「1時間に1回はリファクタリングをしている(p.50)」ような小規模なものでした。しかし、この「リファクタリング」という言葉が広まるにつれ、それが大規模な改修作業であるとの誤解が広まりました。その結果、リファクタリングの効用が軽視され、機能の追加(実装)だけが優先される事例が増えてしまいました。

最近ケント・ベックが『Tidy First?(訳:最初に片付ける?)』という書籍を出版しました。これは『リファクタリング』と似通った内容なのですが、小規模なコード修正のメリットについて更にフォーカスしています。

www.oreilly.com

Tidy First? [Book]

話を戻すと、「小さな片付け」を疎かにすることで技術的負債が貯まっていきます。最初のうちは良くても、どんどんコードが複雑化し、プロジェクトの進行が遅れていきます。気づいた頃には、手を付けるのが恐ろしいスパゲッティの完成です。機能追加が困難になり、ビジネス的にもデメリットがあるでしょう。

それを未然に予防するために必要なのがリファクタリングです。当たり前ですが、一つ一つの実装が綺麗になっていれば、結果として全体のコードも良いものになります。だからこそ、リファクタリングは小さい規模でこまめにやるべきなのです。

設計の第一歩としてのリファクタリング

しかし、頭では分かっていても、それをおこなうのは難しいです。実際、良いリファクタリングをするためには、自分が書いたコードが良いものか悪いものかの判断がつく必要があります。

機能を実装すること自体は、「動いた」「動かない」というゼロイチの明確な指標があるので、自分が達成しているかどうかの判断がつきやすいです。しかし、リファクタリングをする上での「良いコード」か「悪いコード」かの判断は、それより難しいです。「悪いコード」でも、動くには動くからです。*1

とはいえ、明らかに「悪いコード」は存在します。「変数名と中身が一致していないケース」が代表的な例として挙げられるでしょう。まず、そのように基準が明確なものから改善します。

それから、プロジェクト全体を俯瞰して考えたときに「より適切なコード」に改善できないか考えます。この判断は前者よりも難しく、知識や経験を必要とします。

というのも、どんなふうにコードを書くかはトレードオフの関係にあることも多いからです。影響するファイル数が2つや3つなら問題がなくても、10や20なら問題のあるコードもあります。疎結合・密結合という言葉が有名ですが、それぞれメリット・デメリットがあります(いつでも疎結合が良いわけではありません)。

つまり、リファクタリングは小規模でありながら、そこには設計能力が必要とされます。リファクタリングは設計の第一歩なのです。良いリファクタリングこそが設計力の向上につながります。

そしてこの考え方は、どんな場面でも役に立ちます。フロントエンドのコンポーネントをどのように切り分けるか、肥大化したモデル層のコードをどのように分割するか、DBをどのように移行してパフォーマンスを上げるか……こうした場面で、適切な設計を考える必要があり、そのためには小さな改善から始めたほうが良いでしょう。*2

この本においては、汎用的なリファクタリングの方法が紹介されていますが、根底に流れている考えは、どこでも応用が効くものだと思われます。

リファクタリング上達のレベル

リファクタリングするうえではいくかのレベルがあると思います。まず、具体的にそれを挙げましょう。

  1. コードの違和感に気づく
  2. 違和感を言語化し、方針を立てられる
  3. リファクタリングの手法を使いこなす

LEVEL1: コードの違和感に気づく

そもそものところで「悪いコード」に気づかなければ、リファクタリングすることはできません。

つまり、リファクタリングをするための基礎として「コードの不吉な臭い(p.73)」を察知することが大切です。

リファクタリング』では、その不吉さの具体例がたくさん紹介されています。「不可思議な名前」「重複したコード」「長い関数」「グローバルなデータ」……。実際の場面でこれらに気づくのは、意外と難しいです。レビューを受けて初めて「あっ、そっか」と問題に気づくことも多いです。

違和感を持っているかどうかは、大きな差を生みます。違和感を持っていれば「このファイルのこのコード、もっと良く書ける気がするのだけど……」と誰かに相談することができます。しかし、違和感を持っていなければ、そうした機会すら失われてしまいます。

だからこそ、まずは違和感に気づくために、悪いコードの例を知る必要があります。その例を身近なコードの中に探すことで、察知する力は向上するでしょう。

LEVEL2: 違和感を言語化し、方針を立てられる

違和感に気づいたときに、それを上手く言語化することができたら、かなり上達していると言えます。

例えば、2つのクラスがあるとします。そこで、片方のクラスのコードの量がやけに短いとします。

ここで「クラスが非対称な気がする」「片方の責務が足りない気がする」と違和感になんとなく気づきます。しかし、この違和感だけでは、具体的に何をどうすれば良いかの方針が立ちません。

もし、ここから更に踏み込んで、違和感の理由を説明できたとしたらどうでしょうか?

例えば「デメテルの法則に違反している部分がある」→「この違反を修正するために、責務を移す必要がある」→「そう考えると、このメソッドはこちらのクラスに移行するべきだ」。このような流れで言語化し、リファクタリングの方針を立てることができます。

ここまでくれば、7割は目標を達成しています。「違和感の原因を特定し、改善する方針を立てられる」というところまで来たら、あとは具体的な手法を適用するだけです。

ただし、その具体的な手法を適用するのも、なかなか難しい場合があります。そして、次のレベルが出てきます。

LEVEL3: リファクタリングの手法を使いこなす

リファクタリング』の第5章からは、具体的な手法がサンプルコードとともにたくさん紹介されています。

この本の良いところは、リファクタリングの手法をステップ・バイ・ステップで解説しているところです。改善前のコードと改善後のコードを比較するだけでなく、どのような過程を経たのかが順番に示されています。一見大きな変更に見えるリファクタリングも、方法論に則って少しずつ変更すれば、思わぬバグを生んでしまう可能性をできる限り低くできます。

小さなステップに分けることは重要です。そのことで、コードを整理する心理的コストを減らすこともできますし*3、ステップごとにテストコードを走らせてミスに気づくこともできます。

リファクタリングの手法には、正反対のテクニックも出てきます。関数に抽出するテクニックがあれば、関数をインライン化する*4テクニックもあります。

そのため、どの手法を選択するかという状況判断が必要です。これは一つ前の項目で書いた「方針を立てる」能力です。

そのうえで、その選択した手法をどれだけ鮮やかに適用するかが、「手法を使いこなす」レベルに進むための関門となります。実際、プロダクションコードを目の前にすると、やるべきことが分かっていても、どこからどう手を付ければ良いか迷ってしまう場合があるでしょう。

とても分かりやすい例だと、コメントが書かれているコードを修正する場合です。そのコメントが、複雑な挙動を解説するために置かれていたとします。コメントを削除するには「コメントがない状態でも挙動を分かりやすく説明できる」状態までコードをリファクタリングする必要があるでしょう。その箇所を修正しなければいけないと分かっていても、どのように改善するかの手法を知らないと、歯が立たないかも知れません。*5

この本では、無数の事例が載っています。マーティン・ファウラーも、あらゆる手法を網羅したいという目標があったのだと想像できます。『リファクタリング』で紹介された手法を全てマスターすれば、リファクタリング・マスターも夢ではないでしょう。

読んでいて難しかったところ

最後に、自分が『リファクタリング』を読んでいて難しかったところについて、ご紹介したいと思います。

これは社内で質問することで、やっと謎が解けた部分でした。これから読む方の参考になれば幸いです。

diffを追いかけにくいコードについて

上記に書いたように『リファクタリング』ではコードの修正がステップ・バイ・ステップで掲載されています。

ただし、コード例によってはその過程を追いにくいものもあります。そのため、変更量が多いコードに関しては、手元のエディタへ写経するのがオススメです。

自分は今まで、技術書のコードを写経することがほとんどありませんでした。コードの全体像が掴めれば、特に書き写す必要を感じなかったからです。

しかし、この『リファクタリング』は、過程を説明する際に変更のない箇所については省略されています(わずかな変更ごとにコード全体が載ると冗長だからです)。そのため、コード全体のどの部分に手を加えているのか、理解しづらい場面があります。

手元で写経すれば、その問題は解決します。ちょっとした変更ごとにGitでコミットを積めば、どのような過程でリファクタリングされているのか、流れを追いやすくなります。 コード例はJavaScriptなので、開発環境を構築するのも簡単です。そして効果は大きいです。一番初めのセットアップだけは少し面倒ですが、それを過ぎれば楽です。

自分の場合、次の画像のように環境をセットアップしていました。

ローカルに写経すると全体像を掴みながら差分(diff)を確認できます

上はVSCodeを使った例ですが、CLIでも差分を確認しやすいツールがあります。

自分はこのdifftasticを愛用しています。

github.com

Wilfred/difftastic: a structural diff that understands syntax 🟥🟩

改善の目的が分かりづらかったところ

ポリモーフィズムによる条件記述の置き換え

リファクタリング』を読んでいて、理解が難しい節がありました。

第10章の「ポリモーフィズムによる条件記述の置き換え(Replace Conditional with Polymorphism)」という節です。

まず、リファクタリング前のコードをご紹介します。

function plumages(birds) {
  return new Map(birds.map((b) => [b.name, plumage(b)]));
}
function speeds(birds) {
  return new Map(birds.map((b) => [b.name, airSpeedVelocity(b)]));
}
function plumage(bird) {
  switch (bird.type) {
    case "EuropeanSwallow":
      return "average";
    case "AfricanSwallow":
      return bird.numberOfCoconuts > 2 ? "tired" : "average";
    case "NorwegianBlueParrot":
      return bird.voltage > 100 ? "scorched" : "beautiful";
    default:
      return "unknown";
  }
}
function airSpeedVelocity(bird) {
  switch (bird.type) {
    case "EuropeanSwallow":
      return 35;
    case "AfricanSwallow":
      return 40 - 2 * bird.numberOfCoconuts;
    case "NorwegianBlueParrot":
      return bird.isNailed ? 0 : 10 + bird.voltage / 10;
    default:
      return null;
  }
}

次に、リファクタリング後のコードをご紹介します。

function plumages(birds) {
  return new Map(
    birds.map((b) => createBird(b)).map((bird) => [bird.name, bird.plumage])
  );
}
function speeds(birds) {
  return new Map(
    birds
      .map((b) => createBird(b))
      .map((bird) => [bird.name, bird.airSpeedVelocity])
  );
}
function createBird(bird) {
  switch (bird.type) {
    case "EuropeanSwallow":
      return new EuropeanSwallow(bird);
    case "AfricanSwallow":
      return new AfricanSwallow(bird);
    case "NorwegianBlueParrot":
      return new NorwegianBlueParrot(bird);
    default:
      return new Bird(bird);
  }
}
class Bird {
  constructor(birdObject) {
    Object.assign(this, birdObject);
  }
  get plumage() {
    return "unknown";
  }
  get airSpeedVelocity() {
    return null;
  }
}
class EuropeanSwallow extends Bird {
  get plumage() {
    return "average";
  }
  get airSpeedVelocity() {
    return 35;
  }
}
class AfricanSwallow extends Bird {
  get plumage() {
    return this.numberOfCoconuts > 2 ? "tired" : "average";
  }
  get airSpeedVelocity() {
    return 40 - 2 * this.numberOfCoconuts;
  }
}
class NorwegianBlueParrot extends Bird {
  get plumage() {
    return this.voltage > 100 ? "scorched" : "beautiful";
  }
  get airSpeedVelocity() {
    return this.isNailed ? 0 : 10 + this.voltage / 10;
  }
}

このコードを見て、最初自分は「リファクタリング前のコード」のほうが読みやすくて良いと思いました。そのため、どうしてこのようなリファクタリングが必要なのか、理解するのに苦労しました。

この節について、社内で質問したところ、疑問が氷解しました。結論から言うと、この節の目的は次のようにまとめられます。

  • Afterではメンテナンスするときに、一箇所だけ書き換えれば良い。Beforeではたくさんのswitch文があるときに、複数の箇所を書き換える必要が出てくる。

例えば、switch (bird.type)を使っているコードが無数にある場合を想定します。そのとき、もしBirdの種類が増えた場合、それらの条件記述を一つ一つ書き換えることになるでしょう。

Afterのようにポリモーフィズムを使うと、クラスの中身を変更するだけで事足ります。

コード例ではswitch文が2つしか存在しないため、そのメリットが分かりにくかったのですが、実際のコードではswitch文がたくさん増えてしまうケースが想定されます。その場合にこの節が有効になります。*6

サブクラスによるタイプコードの置き換え

他にも理解するのがちょっと難しい箇所があります。例えば第12章に出てくる「サブクラスによるタイプコードの置き換え(Replace Type Code with Subclasses)」の2つ目の例「間接的な継承の使用」です。サブクラスを導入するメリットは1つ目の例で説明されていたため、どうして2つ目の例が紹介されているのか、理解するのに時間が掛かりました。

このコードを写経して手元でdiffを確認することで、その意図を掴むことができました。この例ではEmployeeクラスの中にcreateEmployeeType()というstaticメソッドを導入しています。それを使って、従業員の種類ごとのサブクラスを作成しています(ファクトリーメソッドの導入)。

いちばん大事なところは、クラスの中にクラスをネストしているところでした。このコードではクラスの外部にサブクラスを作ることができないという条件がありました。そのため、クラスの中にサブクラスを作成することで、見通しを良くしているのです。

おわりに

コードリーディングに関する本で一番有名なのは、やはり『リーダブルコード』でしょう。自分もこの本の輪読会を開催した*7ほど、読みやすいコードには興味がありました。

では、読みにくいコードを読みやすいコードへと変えるための手法をどうやって学ぶか……それにうってつけの本こそ、この『リファクタリング』でした。

本書を読んでいて思ったのは、「物事を理解することと、理解したものを実践のレベルに落とし込むことには、大きな差がある」ということです。

リファクタリング後のコードを見ると「明らかに良くなっている」と理解できます。しかし、いざ自分で作業するとなると、手が止まってしまいます。理解に実践が追いついていない状態です。これは試行を重ねることでしか、上達しない気がしています。

そのため、先程挙げた3段階のレベルのうち、まずは「違和感に気づく」ところから始めたいと考えています。何かがおかしいと思ったとき、その箇所にちょこっとメモを残しておいて、レビューをやり取りする際に「このコードの書き方はどう思いますか?」と質問できるだけでも、プログラマーとしてかなり上達していると言えるでしょう。

最近は、社内でケント・ベックの『Tidy First?』を読んでいます。こちらについても、読書会が終わった頃に、またブログ記事を書けたらいいなと思います。

*1:「将来的に問題を引き起こす可能性が高いコード」のことを、この記事では「悪いコード」と呼んでいます。

*2:実際、データベースのリファクタリングに関する本も存在しています。→ https://amzn.asia/d/eBb4LIU

*3:わんこそば理論

*4:関数をやめて呼び出し元のコードで展開すること

*5:自分も最近、副作用を持つ関数をどのように修正するかで苦戦しました

*6:リファクタリング第2版』では「複雑な条件分岐」を解消するための方法の一つとして紹介されています。しかし、その「複雑な条件分岐」が何であるのかが初見だと理解が難しいです。『リファクタリング第1版』では次のように書かれています。「Polymorphism gives you many advantages. The biggest gain occurs when this same set of conditions appears in many places in the program. If you want to add a new type, you have to find and update all the conditionals. But with subclasses you just create a new subclass and provide the appropriate methods. Clients of the class don't need to know about the subclasses, which reduces the dependencies in your system and makes it easier to update.」第二版では「タイプコードで分岐する switch 文を含む関数が複数存在する場合(……)共通な switch 文のロジックの重複を排除します。」と書かれてはいるのですが、意図としては第一版のほうが明快に受け取れます。

*7:リーダブルコード輪読会2023を企画・主催します!📘 - LEFログ:学習記録ノート

完璧な開発環境は存在しない(あるいは開発に集中するために)

これは自戒として書き残すのですが、最近思うことは、完璧な開発環境なんてありえないということ。

例えば自分はWindowsmacOSと素のLinuxをそれぞれ別のパソコンに入れて使い分けているのですが、どれもメリット・デメリットがあり、一概にどれがベストとは言えないことが分かりました。*1

また、自分は常用しているノートPCが2つあって、それぞれJIS配列とUS配列のキーボードになっています。その2つを行き来して思うのが、やっぱりそれぞれメリット・デメリットが(以下略)。

つまり「完璧な開発環境」を目指そうとしたら、いつまで経っても「開発そのもの」に集中できないのではないか、という危機感を最近抱きました。

なので、「ちょっとしっくりこないな」という不完全さがあっても、そのまま開発に集中できるマインドにしておくことはそれなりに重要そう。

とはいえ、改善すると作業効率が一気に向上するペインポイントはたしかに存在します。最近だとこの記事のようなペインポイントを消すことで、とても快適になりました。

これは、繰り返し使ううちにペインポイントに気づけたから改善しようと思えたことです。

だから、最初から完璧な設定を目指さず、実際に開発を進める中で暇なときに改善してみる。そんな感じの開発環境づくりが良いと思いました。

――完璧な開発環境なんて存在しない。完璧な絶望が存在しないように。

*1:ちなみに個人の感覚だと、WindowsmacOSの使い心地はほぼ同じな気がしています

【感想】『情熱プログラマー』―― 日々楽しんでプログラミングに向き合うために

以前からちょこちょことつまみ食いのようにこの本『情熱プログラマー』を読んでいたのだけれど、一度しっかり通読してみようと思い立ち、最初から最後までじっくりと読んでみた。

この本の内容を簡単にまとめると、以下の3つに要約できる

これらの3つの項目はそれぞれ独立している訳はなく、互いに連関している。つまり、プログラマーとしての理想像に近づくことで、プログラマーとして生き延びることができ、そのプロセスにおいてプログラミングを楽しむことができる。

そしてそのことは、おそらくこの本を読まなくても無意識のうちに感じているだろうけど、この本を読むことで更に解像度を上げることができるだろう。

本の要約になってしまうと味気ないため、自分自身の経験も交えて感想を述べていこうと思う。

時代の変化についていこう

ソフトウェア開発に関する領域は進化が速い。いや、正確に言うならば、進化の速い領域と、遅い領域がある。進化の速い領域を学ぼうと思ったら、日々学習を続けなければならない。だけど、これはとても幸運なことだ。

つまり、それはルーチンワークではないということだ。自分は学生時代お金がほとんどなく、とあるバイトをしていた。そのアルバイトでは毎日決まりきった仕事が繰り返され、個人が創意工夫する余地はなかった。単調な作業の中で、ただ時間が経過するのを待っている状態だった。

その経験を思い出すと、新しいことを学び続けられるこのプログラマーという仕事は、とても幸運で、そして楽しいものだと思う。新しいゲームが発売されたときのワクワク感を、常に胸に抱いて仕事できる。

自分は学生時代、作家か研究者になりたいと思っていた。それらは日々新しいことを学べる仕事だからだ。自分はその両方にはなれなかったけど、プログラマーという形で実現できた。

新しい技術を学ぶことには他にも色々なメリットがある。そのことについては本書に書いてあるので省略する。

なんでもやる

なんでもやろう。苦手意識を持たず、なんでもやる。これは、自分がこの半年で痛感したことである。

例えば、自分はデザインに対して苦手意識を持っていた。具体的にはCSSだ。RubyやTypeScriptでコードを書くことに比べると、CSSを書くことは、なんとなく自分に向いていない気がしていた。

だけど、そうした先入観を持ってしまうことは、結果として自分の可能性を閉ざしてしまうことがわかった。CSSは、どこでどう表示を切り分けるかというロジックを持っていて、書いたコードが画面へと即時に反映される。先入観を捨てて思い切って学習すると、楽しいことがわかった。そして、根源的なところでは、他の言語を学ぶのとあまり変わらないということもわかった。

また『情熱プログラマー』の内容を借りて言うと、「コーディングはもう武器にならない(p.9)」。現在、ChatGPTの影響もあって人工知能がどんどん進化して、単純な実装だけには価値がないことが更に浮き彫りになりつつある。だから、設計やアーキテクチャリファクタリングのような、プロジェクト全体の視座を持った仕事が重要になっている。

更に広くこのことを分析すると、「人間と機械の間のインターフェイス」として、プログラマーの価値は担保されるのではないかと思う。つまり「なんでもできる」必要があるし、「なんでもやる」必要がある。お客様の要望を分析し、本当に必要なものを実装する。そのためには対話を通じて、信頼を育む必要がある。コンサルティングからDevOpsに至るまで、なんでもできたほうが良いし、そうしたプログラマーのほうがこれからどんどん価値を持つのは間違いないと思う。

また、「なんでもやる」に関するエピソードでいうと、半年間darashiさんと一緒に開発をしていて、学びになったことがたくさんある。上記のCSSのこともそうだし、他にもこんなエピソードがあった。

timer.teamの開発の途中で、残り時間を円グラフで表示するという機能を実装した。

時間経過とともに背景のランドルト環が欠けていく機能

この画像のように、時間経過とともに円グラフが欠けていく。

ここで自分が凄いと思った点が2つある。それは「この円グラフを実装する技術力」と「その機能を容赦なくオミットできる決断力」だ。

円グラフを実装することは難しく、ただ単にTypeScriptとReactを書けるだけでは実装できない機能である。circleタグとviewBoxタグを使った実装であり、幅広い知識があるからこそ実現できた。

そしてその特徴的な機能を、デザイン案の決定とともに、ノータイムで削除した。これも、自分の中では驚いたことだった。もし自分一人の開発であったら「せっかく頑張って実装したのだから……」と躊躇していたと思う。

これはtimer.team全体の開発におけるほんの一つのエピソードであるが、その一つにおいても学べることが多かった。「なんでもやる」という精神があるからこそ、上の実装と判断ができるのだと思う。

――最後には全部できるようになるとイイよね

この言葉は1on1の中で「プログラマーとして学習すべきこと」について、darashiさんからアドバイスされたことである。そう、一流のプログラマーを目指すのであれば、最後には全部できる必要がある。そのためには、先入観や苦手意識を捨てなければならない。なんでもやる。全部やる。そして成す。

最後に必要なのは行動力

『情熱プログラマー』では優れたプログラマーであるための具体的な方法論がたくさん載っていて、それがプログラマーとしての幸福に繋がることが述べられている。

しかし、これらは実践しなければ何も始まらない。例えばブログを書くのだって、正直にいうと少し億劫だ。自分はショーペンハウアー的なニヒリズムを持っているので、「せっかくブログを書いたところで100年後には……」みたいな感情が生まれてしまう。

だけど、それでもやる。それをわかった上でやる。無為かもしれないと覚悟しつつ、行動に移す。そして、その過程を楽しんでみる。ブログ記事を書くという内容に絞るなら、毎回文体を変えて読者が飽きないようにしようと試みる(ときには動画も撮ってみる)。サービスに新しい機能を追加するときは、できるだけ読みやすいコードにしようと挑戦してみる。そうしたちょっとした工夫が、日々の仕事を楽しくし、生きがいを持たせるのだと思う。

私事だが、先月の末に体調を崩し、一ヶ月ほど微妙な体調不良が続いていた。今は良くなって、メンタルも回復し、休日にブログも書けるようになった。そこで思ったのが、やはり健康と体力は大事だと言うこと。健康じゃないとやる気は生まれないし、体力がないとやる気が持続しない。だから、たくさん睡眠を取って、食生活を整えて、たくさん運動するように生活習慣を改善しないといけない、と改めて思いました。

話を戻すと、良い理念も実践しなければ意味がない。プラグマティズム(行為主義)はプログラマーにとっても重要だ。そして、ジェダイ・マスターのヨーダのように、恐怖心を捨てなければならない。なぜなら「普通の人間とプロを隔てているのは恐怖心(p.137)」なのだから……。

【macOS】Karabinerでウィンドウの切り替えキーをcommand+tabからcontrol+tabへ変更する

概要

自分の現在のキーバインドだと、command+tabでウィンドウを切り替えると指が痛くなってしまったため、control+tabへと変更したのでそのメモ

結論

次のようなJSONファイルを追加すればOK

"description": "Swap Command-Tab to Control-Tab",
"manipulators": [
    {
        "type": "basic",
        "from": {
            "key_code": "tab",
            "modifiers": {
                "mandatory": ["left_command"],
                "optional": ["any"]
            }
        },
        "to": [
            {
                "key_code": "tab",
                "modifiers": ["left_control"]
            }
        ]
    },
    {
        "type": "basic",
        "from": {
            "key_code": "tab",
            "modifiers": {
                "mandatory": ["left_control"],
                "optional": ["any"]
            }
        },
        "to": [
            {
                "key_code": "tab",
                "modifiers": ["left_command"]
            }
        ]
    }
]

"optional": ["any"]のところはちょっと悩みどころだけど、とりあえずこれでいいはず。

VSCodeのスクロールがカクカクするときはSmooth Scrollingをオンにしよう!

まとめ

次のように設定すればOK

デフォルトではSmooth Scrollingはオフになっているので、チェックを入れてオンにしよう!

smoothで検索するとSmooth Scrollingが出てくるのでオンにしよう

経緯

マウスのホイールボタンを使ってVSCode上でスクロールすると、すごくカクカクしていた。

表示位置が瞬間移動するため、目的のコードを見失ってしまうことがしばしばあって、とても困っていた。

このカクカクする動きはVSCodeだけで発生していた。他のアプリでは発生していなかったので不思議だった。

VSCodeの設定を隅から隅まで眺めたところ、Smooth Scrollingという項目を発見した。試しにオンにしてみたら、滑らかにスクロールできるようになった。

目的のコードを見失うことが無くなって、かなりストレスが減りました。皆様もお試しあれ。