Mitsuyuki.Shiiba
https://bufferings.hatenablog.com/
Mitsuyuki.Shiiba
フィード

境界は超えないように気をつけるより超えて体感するのがいい(生成AIコーディング)
Mitsuyuki.Shiiba
会社で生成AIを使って仕事をしつつ、家でも個人でCursorのUltra Planを契約して使い倒してみている別に会社で使ってるなら家で契約せんでもよくない?って気もするし、自分のまわりの人に「家でも使おうよ!」と勧めるつもりも全然ないんだけどじゃあ、なんで自分は家でも使ってるかって言うと「境界を知りたい」という気持ち。「ここを踏み越えたらおいしくない」みたいな境界仕事だとどうしても、そういう境界がありそうだなって時点で踏みとどまって、踏み超えないようにしてしまう。でも、プライベートだと「構わん、行け」が気兼ねなくできるあれ?ここに境界がありそうに思ってたけど、もうちょっと踏み込めるぞ?まだいける?あー!ここに境界があったかー!へー!みたいなのgit checkoutで作業内容を消されたり、ファイルを削除されたり、全然関係ないファイルを編集し始めたり、これ自分でやったら1分で終わることを10分ぐらいかけてやってるやんってなったり、gpt-5と口論したり(時間の無駄)それ以外にも、全然関係なさそうなところをうろうろしてみたり、ヤクの毛刈りをはじめたり、しばらく触るのをやめてみたりとか、いろいろできるのがプライベートのいいところだよなぁって思うおかげで仕事のときは「ここに境界があるんだよな」って考えながらシュシュっと進められていいプライベートで使ってるのはそういう「壊してもいいおもちゃで遊ぶ」って理由が半分で、あとは単純に「おもしろいなー」って気持ちが9割だな今日は大吉祥寺.pmに行って楽しかった
21時間前

チームの問題の原因は外側にあることが多いよなぁ。「チームの力で組織を動かす」を読んだ。
Mitsuyuki.Shiiba
「技術的負債をなんとか減らさなきゃ!」とがんばっているのに、なんかうまくいかないってケースをちょくちょく見る。忙しくて時間が取れないとか、少し改善を進めている間に別の機能追加によってまた負債を抱えてしまうとか。僕はこの10年ぐらい、どうやったらもっとうまく開発できるかなぁって考えながら過ごしている。よりうまく開発をするためには、開発チームの内側を良くするのはもちろんだけど、それ以上に、開発チーム自体を組織の中でどのように設計するかがとても重要だよなと思っている。8月25日に発売です!最近もそんなことを考えながら過ごしていたところ @mtx2s さんから「チームの力で組織を動かす」をいただいた。明日(8/25)発売です!めちゃ面白かった。結構ボリュームがあるので、最初ザーッと読んで、次に、気になったところを中心に読み込んでいった。図がたくさんあって分かりやすいのも良かった!組織やチームについて考えているエンジニアリングマネージャやテックリードにはぜひ読んでほしい。目の前の問題をなんとかするための対応が別の問題を引き起こしてしまうようなアンチパターンや、じゃあどうすればいいのかという組織設計の原則がまとめられていて、とても参考になる。技術的負債に日々向き合っているエンジニアのみんなも「あぁ、このアンチパターン分かる!ここから問題が発生しているのかーたしかになー」といろいろ考えさせられて面白いのでぜひどうぞ。最近は開発が遅い?「以前はもっと少人数で勢いよく開発が進んでいたのに、今はこれだけの人数がいるのにどうして進みが遅いの?」みたいな声を聞いたりして「以前に少人数で勢いよく開発を進めていたから、今大変なんですよね」という気持ちになったりする。それは、少人数で勢いよく開発を進めていたことを否定する気持ちではない。その時代があったから今があると思っている。ただ、そこで意識的に・無意識的に蓄積された技術的負債と、プロダクトや組織の拡大が絡まって、どんどん開発の難易度は上がっていく。だから、その難しさに対応するための組織設計がとても重要になってくる。「組織設計のひずみによって生じた問題は現場だけでは解決できない」最初の方に出てくる言葉。これ好き。組織設計のひずみによって生じた問題は現場だけでは解決できない。そうそうそれだよなーという気持ち。エンジニアが対応しないといけなくなる場
14日前

Kori (氷) というTypeScript用のウェブアプリケーションフレームワークをCursorたちと一緒に作ってみている
Mitsuyuki.Shiiba
とりあえずコンセプトは動きそうだなぁってくらいで、ちゃんと動くことも確認してないし、テストも書いてないし、まだまだやることはたくさんあるんだけど、どっかでいったんブログに書いて休憩しようと思ったので、書くことにした。年内である程度動くところまで持っていけたらいいな。KoriKori (WIP) (英語版を作ってその翻訳をCursorにお願いしたのでそういう感じの日本語になってます)特徴TypeScriptの型安全さをわりといっぱい活かしてコードを書ける。スキーマを定義すると、そのスキーマにしたがってバリデーションが実行されて、その結果を型安全に扱える。その同じスキーマをOpenAPIのスキーマとしても利用できる。スキーマの実装としては、とりあえずZod v4に対応しておいた。たとえばこんな感じで定義するとconst UserSchema = z.object({ name: z.string().min(1).max(100).meta({ description: 'User name' }), age: z.number().int().min(0).meta({ description: 'User age' }),});app.post('/users', { pluginMetadata: openApiMeta({ summary: 'Create user', description: 'Create a new user with validation', }), requestSchema: zodRequestSchema({ body: UserSchema, }), handler: (ctx) => { const { name, age } = ctx.req.validatedBody(); const newUser = createUser(name, age); return ctx.res.status(HttpStatus.CREATED).json(newUser); },});ScalarというUIでOpenAPIのドキュメントを確認できる。Scalarは知らなかったんだけど「Swagger UI以外にもなんかある?」ってCursorに聞いたら教えてくれた。Scalar - Document, Test & Discove
1ヶ月前

CursorのプランをPro($20)からPro+プラン($60)に変更した
Mitsuyuki.Shiiba
最近「説明が足りなくてごめんね」って記事(Clarifying Our Pricing | Cursor - The AI Code Editor)がでたりして話題のCursorの料金プラン。僕はプライベートではProプラン($20)を使っていて、新料金プランのレートリミットモードはわりと気に入っていた。でも、けっこうすぐに$20ぶん使い切って、(たぶん)月間のレートリミットに達してしまっていた。こっからは従量課金かーって気持ちで$100リミットとかにして使っていた。プランのアップグレードも考えてみたけど、Proの上位プランだとUltraプラン($200)だから・・・んー、そこまではちょっとなぁ・・・って思っていた。そんな中でふとドキュメント(Cursor – Models & Pricing)を眺めてたら「あれ?Pro+プラン($60)なんてあるんだ?これくらいならちょうどいいかも?」って思って、Pricingページ(Pricing | Cursor - The AI Code Editor)を探してみても見つからない。「あれー?ドキュメントには書いたけどまだ公開されていない」ってことなのかなぁはやくくるといいなぁって過ごしてた。ら、何かで「僕はPro+プランで$60払ってるんだけどね(英語)」みたいなコメントを見かけて「あれ?もうあるの?」ってなって調べてみつけた。https://www.reddit.com/r/cursor/comments/1lqig05/how_to_actually_upgrade_to_pro/(意訳)リミットに達した人に「Pro+にアップグレードする」を出してるよ!従量課金を設定してる人には出てこないからいったんオフにしたら出てくるよ!おーい!!!ほんまや。そんなん気づかんわー!!!ってことで無事Pro+プランに変更できた。からの、Proプランの残りの日数分は日割りで返金された。Redditには「近い内にDashboardにも載せるね。でも大多数は$20のProで大丈夫なはずだから、Pro+はちょっと奥の方に置いとくつもり」って感じのコメントがあるので、近い内に設定ページかPricingページあたりに出てきそう。ということでしばらくPro+プランで遊ぶー。$20のProで10日くらいもったから、$60のPro+だったら3倍使えるので
2ヶ月前

CursorのBackground Agentで遊んでいてわりと面白い
Mitsuyuki.Shiiba
「最近のおうちコーディングは、CursorのBackground Agentで遊んでいてわりと面白いよ」って会社の同僚に言ったので、簡単にメモだけ残しておくことにする。前半でBackground Agentのことを、後半で僕がどう使ってみてるかを簡単に紹介する。Cursor Background Agent?Cursorをふつうに使うと、AIとチャットしながらコーディングしている感じになる。それはそれでいいんだけど、それとは別で、Cursorにはリモート環境で非同期でタスクを実行してくれる Background Agent という機能がある。ローカル環境とは別のところで実行されるので、手元では別の作業を続けられて便利。https://docs.cursor.com/background-agent準備GitHubとの連携をしておく必要がある。あと、Slack連携もしておくと便利。依頼 on CursorCursor上で ⌘E を押すと、Background Agent用のモーダルが開くので、そこに依頼を書くだけ。そうすると、Background Agentがリモート環境で動き始めて、タスクを進めてくれる。依頼 on Slackもしくは、SlackからCursorにメッセージを送っても、Background Agentが動き始める。依頼 on Webさっき「Background AgentにWebからもアクセスできるようになったよ!」ってアナウンスがあった。タイムリーね。そのWebからも依頼ができる。Cursor is now on your phone and on the web.Spin off dozens of agents and review them later in your editor. pic.twitter.com/y7mOlA9h07— Cursor (@cursor_ai) June 30, 2025 これまでは、依頼の進み具合を見るためにはCursor Appを使う必要があったから、DevinみたいにWebでも確認できたらスマホからもチェックできて便利なのになーって思ってたところだった。Webでも確認できるようになったのは便利そう。PRを作るCursor上でもWeb上でも、Background AgentのビューからPRを作ることができ
2ヶ月前

Devinにドキュメントを生成してもらう実験
Mitsuyuki.Shiiba
Devinにお願いしてソースコードからドキュメントを生成してもらえると面白そうなので実験してみた。Devin Wiki や Deep Wiki もあるんだけど、それとは別に自分で指示を出してコントロールできるのもいいかなという気持ち。どうせ作るなら自分がドキュメントを読みたいやつがいいなぁと思って、ecspresso が好きだから、ecspressoのソースコードからドキュメントを生成してみることにした。軽い気持ちでやってみたら、思ってたより苦戦した。すごくいい感じにできたわけじゃないので「この記事をめちゃ信じる!」んじゃなくて「へー、ちょっと参考にしとこっか」くらいが良いと思う。勢いで書かないと書き終わらなさそうだったので、勢いでざーっと書いた。ので長い。できあがったものできあがったものを最初に書いておく。わりと気に入ってる。ただ、生成するたびに色々変わるので、雰囲気で参照することにする。注意:このドキュメントが正しいかどうかは確認できていないです!https://bufferings.github.io/devin-docs/ecspresso/注意:今後色々触っていくうちに上記のドキュメントは見えなくなるかもしれないDevin?Devin https://devin.ai/お願いすると勝手に動いてPRを作ってくれるAIエージェント。個人では Core (Pay as you go) プランを契約している。使った分だけ払うやつ。やりたいことecspressoのソースコードを元にドキュメントを生成して、それをGitHub Pagesで見られるようにしたい。最初はecspressoをフォークしてごにょごにょしてたけど、それよりもドキュメント生成用のリポジトリを作るほうがいいかも?と思ってそうした。そのリポジトリからecspressoをチェックアウトしてきてドキュメントを生成する。https://github.com/bufferings/devin-docsGitHub Actionsをポチると、Devinにドキュメント更新を依頼するDevinが最新のソースコードを読んでドキュメントを生成してPRを出す僕がPRを手でマージするmainブランチが更新されると、GitHub Pagesが最新のドキュメントに更新されるメインは手順2のプロンプトなので、それ以外を先にさらっ
4ヶ月前

Zod v4でz.discriminatedUnionはどうなる予定なんだっけ?を見ておいた
Mitsuyuki.Shiiba
「数日前に↓のIssueがクローズされたんだよねー。Zod v4が関係してそう。知らんけど」って会社の同僚と喋ったので、ちゃんと知っておくかーって気持ちになった。※ 本記事はzod@4.0.0-beta.20250505T195954時点の挙動をもとにしています。正式版で変更される可能性があります。最初にまとめz.switchが追加されるとか、z.discriminatedUnionが非推奨になるとかの話はなくなった様子Zod v4 ではz.discriminatedUnionに識別プロパティを渡さないようになった(渡しても無視される)共通の識別プロパティを持たずに、各オプションがそれぞれリテラルかenum(ネスト可)のプロパティを持つだけでよくなったZod v3までのz.unionとz.discriminatedUnionIssueの内容を説明する前に、現行であるZod v3のz.unionとz.discriminatedUnionについておさらいしておく。z.unionUnionsどちらかの型だよという定義。const stringOrNumber = z.union([z.string(), z.number()]);パースするときは、前から順番にチェックして最初に成功したものを返す。パースに失敗した場合は、すべての型に対する失敗内容を返す。例えば、こういうスキーマの場合(あとでDiscriminated Unionと比較するため、わざとそういう定義にしてる)import { z } from 'zod';const MyUnion = z.union([ z.object({ kind: z.literal('square'), size: z.number(), }), z.object({ kind: z.literal('rectangle'), width: z.number(), height: z.number(), }),]);const result = MyUnion.safeParse({ kind: 'circle', radius: 5,});console.log(result.error?.message);実行すると↓こういうエラーメッセージになる(zod 3.24.4で確認)。つまり、全部の型をチェックして、全部のエラーを返す
4ヶ月前

旗振りをするときに考えてること
Mitsuyuki.Shiiba
エンジニアとしてチームをリードするときよりも、もう少し広めの範囲をリードするときの話。1 つのチームをエンジニアとしてリードするときには、ぐいっと引っ張ったり、やって見せたり、そばでペアプロをしたり、直接話をしたり、そういう直接のコミュニケーションでリードできるし、そうしたい。でも、複数チームの方向性を決めるような旗振りをするときには、そういう直接のコミュニケーションは難しくなる。それに 1 つのチームを見ているときよりももう少し遠くを見ることが多い。そんなときに意識しているのは「自分が考えてることを見えるようにすること」。考えてることが見えないと考えてることが見えないタイプのリーダーは、メンバーとしては動きにくいなって思ってしまう。責任感が強かったり、自分がリーダーとしてしっかりしなきゃ!と頑張ってたりするから、というのが多いかも。で、いろいろ悩んで、最終的に決まってから「こういう方針に決めました」と伝えてくれる。でも、やることが決まってから渡されると、メンバーには考える余地がない。一緒に課題に向き合ってるのにね。まぁ、言われたことはやりますけど、ってなってしまう。経緯が分からないから納得しづらかったりもする。みんなを頼りたいそれよりも僕は、みんなを頼りたいなと思っている。僕一人でなんとかなることなんてたかがしれてるから、みんなのチカラをできるだけ借りたい。だから、考えている段階で「こういう課題に対して、こうやりたいなと考えて進めているよ」というのをできるだけ見えるようにする。今はフルリモートの場所にいるから、Slackやドキュメントで考えている途中のこともできるだけ見える場所に書いている。そうすると見てる方も「なるほどね。じゃそろそろこういう話になりそうね」って準備ができたり「あの話、進んでるのかなぁ?」って思わずに「あの話はいまこういうステータスか・・・なるほどね」って待ってくれたり「その課題には、こういうやり方もありだと思うよ」ってアドバイスをくれたり、あとは「そういう考えで進めてたのに、この話でブロックされてこうなったのか」って納得できたりする。そんな風に過程を見えるようにして、みんなが動きやすい状態をつくりたい。んで、一緒に動きたい。諸刃の剣だったりもするただ、これは諸刃の剣だったりもする。みんなを頼ってばっかりであの人何もしてないやんって思われたり、「
4ヶ月前

DenoでMCPサーバーを作って遊んだ
Mitsuyuki.Shiiba
数日前に↓を読んで、なるほどー!ってなったので、なんか作ってみるかと思いMCPサーバー自作入門なんとなく、npxで実行するより、実行可能ファイルにしてみたいなと思って、Denoに初挑戦。↓こちらを参考にして作ってみたDeno で RooCode 用にローカルMCPサーバーをさっと作る↓こうなったhttps://github.com/bufferings/mcp-servers/tree/main/hello実行可能ファイルはこんな感じで作って❯ deno compile --output dist/hello hello/index.tsCursorでそのファイルを設定して{ "mcpServers": { "hello": { "command": "~/mcp-servers/hello", "args": [], "env": {} } }}有効化して文字列の長さを聞いてみると、使ってくれるGitHub ActionsでビルドしてGitHub Pagesにでもあげとくかと思ってCursorにお願いしたらワークフローファイルを書いてくれた。ありがと。実行ファイルが70MBあるのはちょっと大きいなぁとは思うけど、自分用には便利(他の人がビルドしたバイナリは実行しないほうがいいと思う)。これで、適当に遊びで色々作る環境ができたー。Cursorはまだtoolsしかサポートしてないってことなので、toolsで遊んでみたらいいかなー。
5ヶ月前

GitHub ActionsでAI呼び出し
Mitsuyuki.Shiiba
すごく久しぶりにブログを書く。3ヶ月ぶりくらい?↓この記事を読んで「へー。どういうこと?」ってなったので遊んでみた。「GITHUB_TOKEN でGitHub Modelsを呼び出せるようになったよ!PAT(Personal Access Tokens)はもう使わなくていいよ!」って書いてある。そもそもGitHub Modelsを知らんかったけど、GitHub Copilotとかで使ってるAIのモデルたちのことかな。やってみたGitHub ActionsでAIの呼び出しができるよってことだろうなと思って適当に作ってみた。「今日の運勢を教えて!」って投げるだけのGitHub Actions。「今日は新しいことにチャレンジする絶好の日!」ふむふむー。コードgithub.comname: GitHub Models API Exampleon: workflow_dispatch:permissions: models: readjobs: call-model: runs-on: ubuntu-latest steps: - name: Call AI model id: model-call env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PROMPT: "今日の運勢を教えて!" run: | # API呼び出しと生のレスポンスの保存 RAW_RESPONSE=$(curl "https://models.github.ai/inference/chat/completions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GITHUB_TOKEN" \ -d '{ "messages": [ { "role": "user", "content": "'"$PROMPT"'" } ], "model": "openai/gpt-4o" }') # 生のレスポンスを一時ファイルに保存 echo "$RAW_RESPONSE" > raw_response.json # レスポンスからコンテンツ部分を抽出 CONTENT=$(echo "$RAW_RESPONSE" | jq -r '.choices[0].message.conten
5ヶ月前

HonoのZod OpenAPIを読んでたらWebStormのCPUとメモリを消費しまくってたのをJetBrainsにレポートしたらすぐに解決方法を教えてもらってニッコリなメモ
Mitsuyuki.Shiiba
HonoとZodとOpenAPIまわりが気になって、Zod OpenAPIのコードをWebStormで読んでたら、WebStormとNode.jsのプロセスがCPUをたくさん消費して、動きが遅くなって困った。メモリもWebStormに割り当てたぶんを使い切っちゃうよーって警告が出てきてた。なんの気なしにそんなことをつぶやいてたらJetBrainsの@niklas_wortmannがコメントをくれた。Did you happen to create a YouTrack ticket with some CPU or Memory snapshots? Would love to further look into this— Jan-Niklas Wortmann (@niklas_wortmann) January 18, 2025 ので、たしかにレポート送るのいいか、と思ってYouTrackにIssueを報告した。Issue自体は僕(とJetBrainsの人)にしか見えないっぽいんだけど、内容はこんな感じHonoのZod OpenAPIのコードをWebStormで読んでたらCPUとメモリの使用量が多くなっちゃうこのコードで再現する https://github.com/bufferings/20250119_webstorm_cpu_memそしたら早速返事が来て、対応方法として↓をやってみて!って言われてやったら解決した。Help | Change Memory Settings... でメモリを増やして2048MBだったので、4096MBに増やした。まぁたしかに2GBは少ないなTools | Internal Action | Registryから typescript.service.node.arguments を探して --max-old-space-size=3072 を設定してみてInternal Action が見つからなかったので Find Action... から Registry を検索して設定したSettings | Languages and Frameworks | TypeScript から“Use types from server” をオンにして“Show project errors” をオフにしてみてなんでこれで解決したのかは
8ヶ月前

Honoのルーティングの分割を思いつくままに実験
Mitsuyuki.Shiiba
GroupingHonoにはGroupingという機能がある。僕はルーティングを複数のファイルに分けて書きたいタイプなので、たぶんこれを使うだろうなと思っている。https://hono.dev/docs/api/routing#grouping実験環境Node.jsが好きなのでNode.jsで動かしている。hono: 4.6.16@hono/node-server: 1.13.7node.js: 23.6.0分割に対するHono的おすすめはappまるごとルーティングを分割して書こうと思うと、まず最初に思いつくのはhandler関数を別のファイルに定義することかなと思う。で、それをメインのルーターのところでパスにマッピングする。でも、Hono的なおすすめはそうじゃない。handler関数ではなくappインスタンスを別のファイルに定義する。それによって、型を気にしなくてもHonoがいい感じに推論してくれる。https://hono.dev/docs/guides/best-practicesappインスタンスを別のファイルに定義する?たとえば、こんなパスを定義したいとき/users/users/:id/books/books/:idこんな風にUser用とBook用を分割できるimport { Hono } from 'hono';const userApp = new Hono();userApp.get('/', (c) => { return c.text('users');});userApp.get('/:id', (c) => { const id = c.req.param('id'); return c.text('Get User: ' + id);});export { userApp };import { Hono } from 'hono';const bookApp = new Hono();bookApp.get('/', (c) => { return c.text('books');});bookApp.get('/:id', (c) => { const id = c.req.param('id'); return c.text('Get Book: ' + id);});export { bookApp };そして、それらをメインap
8ヶ月前

TypeScriptのBranded TypeとZodの.brand
Mitsuyuki.Shiiba
Branded Typeについては、もういろんなところで触れられているから、わざわざ書かなくてもいいよなぁという気持ちがありつつ。でも、せっかく頭の整理をしたから、来月の自分用にまとめておくくらいはやっておこうか、という気持ちになったのでメモを残しておく。それとZodの.brand。やりたいこと次の2つの型に対する値を間違えて渡したときに、TypeScriptの型検査でエラーになってほしい。type UserId = number;type BookId = number;TSの型システムはStructural Subtypingを採用しているので、構造が同じだったら部分型として扱われる。だから、↓こんな風にUserIdを引数で受け取る関数にBookIdの値を渡してもエラーにならない。どちらも同じnumber型だから。const getUser = (id: UserId) => ({ id, name: 'SHIIBA' }); // 例なので適当const bookId: BookId = 1;const user = getUser(bookId);// UserId型の引数に対してBookId型の変数を渡してもエラーにならない先に言っておくと先に言っておくと、Branded Typeをいたるところで使いたいとは思っていない。それなら最初からJavaとかを使えばいいやん、と思う(フロントエンドTSじゃなくてサーバーサイドTSの頭で喋っている)。TSを使うからにはTSの良さ・柔軟さを大切にしたいので、普通に書いても大丈夫な部分はできるだけ普通に書きたい。でも「ここは型で守っておきたいな」という部分にはBranded Typeという選択肢もあるよなって、引き出しに入れておこうという気持ち。Branded TypeということでUserIdとBookIdを区別するのにBranded Typeと呼ばれる手法が使える。↓こんな感じでマーカーとなる型をIntersection Typeでくっつけるtype UserId = number & { __brand: 'UserId' };type BookId = number & { __brand: 'BookId' };そうするとUserIdとBookIdが異なる構造になるので区別されるようになる。const bookI
8ヶ月前

Zodのドキュメントを読みながら自分用にメモ
Mitsuyuki.Shiiba
基本的なことは大丈夫なのでざっと読んで気になったところだけをメモしておく。使ってるときに「そういえばこんな機能がZodにあった気がする」って頭の中で引っかかるように。視点としては、Webアプリケーションのサーバーサイドを作る頭で読んでる。フレームワークを作る頭とかではない。Coercionコンストラクタ関数を噛ませて変換するやつ。z.coerce.string()Literals忘れたりはしないだろうけどメモz.literal("tuna")StringsdatetimeZodStringにくっついてくる。タイムゾーン有無・精度・ローカルとかある。const schema = z.string().datetime({ local: true });schema.parse("2020-01-01T00:00:00"); // passdatetime以外に、dateもtimeもある。日付文字列を扱うやつだから、日付型を扱うやつと頭の中で混乱しないように注意しておきたい。Zod enumsへー。ZodEnumには.enum なんてのがあるんだ。値だけを返す .options もある。.extract と .exclude もある。(使わない) Native enums僕は使わない.optional .nullable .nullishラッピングする関数もあるけどconst schema = z.optional(z.string());↓僕はメソッドチェーンの方を使いそうconst schema = z.string().optional();.nullable() もそう。nullとundefinedを両方許容する .nullish() もある。.unwrap() で中のスキーマを取り出せる。Objects(たぶん使わない) .shapeプロパティのスキーマにアクセスできるDog.shape.name;(たぶん使わない) .keyofキーのZodEnumを生成する。へー。ZodEnumなのか。const keySchema = Dog.keyof();keySchema; // ZodEnum<["name", "age"]>.extendフィールドを追加できる。上書きもできるので注意const DogWithBreed = Dog.extend({ breed:
8ヶ月前

結局iTerm2を単体で使うことにした
Mitsuyuki.Shiiba
年末年始にGhosttyを触ってみてて、好きだなとは思いつつもメイン使いするのはもうちょっと待ちたいなという気持ちになった。なので、↓以前に書いたみたいにiTerm2 + tmuxに戻すかー!と思って、それならtmuxの使い方をもういっかい勉強するかー!って考えたんだけど。はて?そういえばなんでtmuxを使ってるんだっけ?ってなった。もともとは、踏み台からサーバーに入って作業をするときに切断されないようにするためだったな。ついでに複数台のサーバーに入りやすくて便利だなくらいで使い始めたんだった。もう今じゃ踏み台からサーバーに入ることもほとんどないし、単に複数ペインやタブで操作したいだけならiTerm2だけでよくない?って気持ちになった。それに、もしまた踏み台経由でtmuxを使いたいってなったら、iTerm2のtmuxインテグレーションの機能を使えばiTerm2の使い方でtmuxが使えそうだからそれでいいよな。ということでiTerm2を単体で使うことにした。なにはともあれバージョンアップから。3.5.11へあげる。設定こんな感じになった。わりと気に入ってる。ふだんはドロップダウンウィンドウをホットキーで呼び出して使う。通常のウィンドウで使いたいときもあるので、そういうときはCtrl + Nで新規ウィンドウを作成すると通常のウィンドウで開くようにしている。プロンプトにはStarshipを使っているとはいっても、色々表示されると気になってしまうので、何も出さないようにシンプルにしている。Color SchemeにはDraculaを使ってるこれもずいぶん前から設定してある。ちょこっと色をいじったかもしれない。Shell IntegrationをオンにしたSettings > Profiles > General > Command > Load shell integration automatically にチェックを入れた色々便利機能はありそうなんだけど、そのへんはよく分かってない。コマンドの結果が長い場合でもコマンドが上部に固定されるのが好きでそれだけのためにオンにした。Clicking on a command selects it to restrict Find and FilterをオフにしたSettings > General > Selection > C
8ヶ月前

Ghostty使っていこうかな
Mitsuyuki.Shiiba
2025-01-07 追記年末年始に触ってみてて、いまはまだiTerm2+tmuxのままにしておこうと思ったのだった。検索ができなかったり、ちょこちょこ気になる動きをする部分があったりするから。追記ここまで今朝リリースされたなんとなく楽しみにしてたやつ。わーい。https://t.co/39Xj39wheA 👻 pic.twitter.com/PH0qejFB4z— Mitchell Hashimoto (@mitchellh) December 26, 2024 使ってみようと思ったちょっと触った感じ、なんとなく心地良いなと思ったので使ってみることにする。僕は今 iTerm2 + tmux なんだけど、これを機に tmux もやめてみて Ghostty だけを使ってみようかなと思っている。Ghostty + tmux でもいいよなとは思ったんだけど、せっかくなら Ghostty の機能をちゃんと使ってみるかなという気持ち。tmux を全然使いこなせていないから大丈夫(?)。テーマやフォントデフォルトのままで好きな感じなので、変更せずに使う。ちなみに、デフォルトフォントは JetBrains Mono。タブやビューの分割や移動これぐらいで自分は大丈夫そう。⌘Tで新規タブ作成。⇧⌘[や⇧⌘]でタブを移動⌘Dで横にスプリット、⇧⌘Dで縦にスプリット。⌘[や⌘]でスプリットを移動⇧⌘↵でスプリットのズームをトグルQuick Terminal僕はGuakeのようなドロップダウンウィンドウが好きなんだけど、GhosttyにはQuick Terminalという機能があって、まさにこれ。グローバルのホットキーを設定してF12で表示されるようにしておいた。設定keybind = global:f12=toggle_quick_terminalkeybind = f11=toggle_fullscreenglobalはアプリケーションにフォーカスがあたってなくてもそのショートカットを使えるようにする設定。Quick Terminalではタブが使えないんー。タブは使いたいかなー。じゃ、ドロップダウンウィンドウをやめてみるかこれを機にドロップダウンウィンドウ自体もやめてみてもいいかもしれない。ホットキーを押したら画面がでてくればいいか。と思ってtoggle-visibilityをF12...
8ヶ月前

午前中に読み始めたら午後には設計が上達してしまった! - 『Tidy First?』を読んだ
Mitsuyuki.Shiiba
私の目標は、読者が午前中に本書を読み始めたら、午後には設計が上達していることだ。本当にそのとおりだった。読んでる途中で既に自分の設計に対する考えが良い方向に変わってると感じた。とても良かった。おすすめです。『Tidy First?』をいただいて読んだ。昨日(2024年12月25日)発売。英語版が2023年11月28日発売だから、たった1年で日本語版が出たということだな。うれしい!はやい!ありがたい!ソフトウェア設計に焦点を当てたシリーズの最初の1冊ということで、サブタイトルに「個人で実践する経験主義的ソフトウェア設計」とあるように、1人でできる種類のソフトウェア設計について書かれている。続刊ではチームについての話になる予定のようで、それも今から楽しみ。2周読んだなんとなく2周読もうと思ってそうした。1周目は細かい部分は気にせずにざーっと1,2時間くらいで読んだ。全体的にどういう話があるかを把握してから、2周目に突入。2周目は1行1行しっかり理解しながら数日かけて読んだ。1周目:前半が面白かった1周目は、第1部が分かりやすくて面白いなと思いながら読んでた。第1部では、ガード節や説明変数など、ほんとに個人で取り組める整頓が紹介されている。だいたいどこかで目にしたことがあるかなとは思う。そういう、一人で10分から1時間ぐらいあれば修正できてしまうような整頓によってコードを読みやすしていくのはとてもいい。後半は内容が少し難しいなと思いながら読んだ。デッドコード消そう。以上。笑った。それはそう。— SHIIBA Mitsuyuki (@bufferings) December 17, 2024 2周目:後半が面白かった1周目では整頓の具体的な一手を楽しんでたけど、2周目は一歩下がって眺めてみた。「整頓はいいよね。やりたい。でも、実際の仕事で難しいのはいつ・どんな風に整頓へ取り組むかなんだよなぁ」と思ってたら、第2部がそれについての話だった(←気づくの遅い)ので「わー!そういう流れだったのかー!面白いー!」ってなって読んだ。第3部もさらに面白かった。第2部:振る舞いの変更、構造の変更第2部では、個人レベルでどのように日々の開発の中に整頓を取り入れるか、について紹介されている。通常の開発では、システムに振る舞いの変更を加える。それに対して整頓は「コードの構造の変更」をする。この構
8ヶ月前

typescript-eslintとFlat Config
Mitsuyuki.Shiiba
typescript-eslintのFlat Configについて、自分に今必要そうな部分だけをひととおり確認したので忘れる前にメモを残しておく。前提素のJavaScriptプロジェクトをやることは自分はあまりなさそうなのでTypeScript前提ES Modules前提でいいやと思っているので設定ファイルの拡張子はシンプルに .js にするフォーマッターにはESLintのStylisticじゃなくてESLint外のフォーマッター(PrettierやBiome)を使う前提基本の設定https://typescript-eslint.io/getting-started/ の最初に書いてある設定。// @ts-checkimport eslint from '@eslint/js';import tseslint from 'typescript-eslint';export default tseslint.config( eslint.configs.recommended, tseslint.configs.recommended,);この設定の意味**/*.js, **/*.cjs, and **/*.mjs と '**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts' に対してeslint.configs.recommended と tseslint.configs.recommended が適用されるシンプルだね。参照:推奨ルールの実装eslint.configs.recommendedhttps://github.com/eslint/eslint/blob/90c1db9a9676a7e2163158b37aef0b61a37a9820/packages/js/src/configs/eslint-recommended.jstseslint.configs.recommendedhttps://github.com/typescript-eslint/typescript-eslint/blob/a383d5022b81eaf65ce7b0946491444c6eaa28e3/packages/typescript-eslint/src/configs/recommended.tstseslint.config()
9ヶ月前

NeverThrowのESLintプラグインをフォークしてFlat Configに対応した
Mitsuyuki.Shiiba
ちょっと前にNeverThrowを触ろうとして、そのESLintプラグインがFlat Configに未対応だったから、そこで遊んでしまった話を書いたけど。遊んでしまったついでに、フォークしてFlat Configに対応した。www.npmjs.compnpmとかでインストールして# npmnpm install --save-dev @bufferings/eslint-plugin-neverthrow# pnpmpnpm install --save-dev @bufferings/eslint-plugin-neverthrowこんな感じで設定を書いたらOKimport eslint from '@eslint/js';import tseslint from 'typescript-eslint';import neverthrowPlugin from '@bufferings/eslint-plugin-neverthrow';export default tseslint.config( eslint.configs.recommended, tseslint.configs.recommendedTypeChecked, neverthrowPlugin.configs.recommended, { languageOptions: { parserOptions: { projectService: { allowDefaultProject: ['*.config.*'], }, tsconfigRootDir: import.meta.dirname, }, }, });そうすると、中身を取り出していないResultは怒られる。わーい。利用サンプルはここに置いておいた注意点プラグインの書き方がよくわかっていない。Node.jsのバージョン対応とからへんあやしい。そもそも、Ruleのコアの部分のロジックは読まずに、その周りの対応だけをしたので、ロジックがどうなってるか分かってない。semantic-releaseを雰囲気で使っている。ちゃんといい感じでリリースできるか分かってない。まぁ、自分が個人で使うぶんにはこれでいいかな。ちょこっと改良とかできたら面白いかな。
9ヶ月前

NeverThrowを触ろうと思ったらESLintのFlat Configを触っていた(後編)
Mitsuyuki.Shiiba
の続き。eslint-plugin-neverthrow に手を入れて動くようにしてみるぞー!そして記事を書き終わるぞー!eslint-plugin-neverthrow に手を入れてみるそのままでは動かなさそうだから手を入れて動くようにしてみたい。パッケージを作ればできそうではあるけど、もうちょっと簡単にできないかな?と思って探してみたら、こんな記事を見つけた。ありがたい。srcのとなりにコードを置いて、それを使うようにできるのかー。これなら簡単に eslint-plugin-neverthrow に手を入れられそう。この記事や、ESLintのプラグイン自作ページを見ながら試してみたら、サンプルのプラグインが動いた。この仕組みで eslint-plugin-neverthrow に対して手を入れてみよう。my-plugin という名前でプラグインを作る# プラグイン用のフォルダを作る❯ mkdir my-pluginindex.js はこんな感じ。import {rule} from './must-use-result.js'const plugin = { meta: { name: 'my-plugin', version: '1.0.0', }, rules: { 'must-use-result': rule },}export default pluginそして、must-use-result ルールのファイルをダウンロードしてくる。TypeScriptのファイルだから、tscでjsにコンパイルすればいいか。❯ cd my-plugin❯ curl https://raw.githubusercontent.com/mdbetancourt/eslint-plugin-neverthrow/refs/heads/master/src/rules/must-use-result.ts -O❯ lsindex.js must-use-result.tsで、コンパイルエラーが出てるからまずはそれを解消しよう。import部分のエラーimport部分では↓の3ヶ所がエラーになる。(1) tsutils がない:import { unionTypeParts } from 'tsutils';(2) @typescript-eslint/experimental
9ヶ月前

NeverThrowを触ろうと思ったらESLintのFlat Configを触っていた(中編)
Mitsuyuki.Shiiba
の続き。Flat Configで eslint-plugin-neverthrow を使えるようにするぞー!Flat Config?そもそもFlat Configをよくわかっていないってところからスタート。へー。v9でFlat Configがデフォルトになっていて、v8は2024年10月からEOLなのか。https://eslint.org/version-support/んで、次のv10で旧設定は使えなくなる。↓に「2024年末から2025年頭くらい」って書いてある。もうほんとにすぐだな。https://eslint.org/blog/2023/10/flat-config-rollout-plans/#eslintrc-removed-in-eslint-v10.0.0僕は公式ドキュメントに最初からは入れないタイプなので、心のハードルを下げるために分かりやすそうな記事を読んでみる。↓安心のSajiさん@サイボウズフロントエンド。記事を読みながら思ったんだけど、そもそもESLintの設定ファイルはこれまで雰囲気で触ってきてたので、旧の設定が新でどうなるかよりも新がどういうものなのか、という観点が僕には良さそう。この記事は新設定目線でまとめられているので、僕にとってちょうどいい。ありがたいー。ざーっと読んで完全に理解した(= 雰囲気だけ理解した)これまでは設定ファイルを独自で解決してたけど、JSの解決の仕組みを使うようにした。ってことかな。それは、分かりやすくていいな。設定を配列で指定しておいてその書き方や項目によっては全体に適用されるものがあるあとで書いたほうはそれまでの設定と合成されたりするってことみたいなので、その観点で公式ドキュメントをチェックすればよさそう。全部をチェックするのは大変だから、自分に関係しそうなところだけピックアップしてみるかな。心のハードルが少し下がったところでFlat Configの仕様を眺めてみる。詳しくは↑を見てねってことで、ざっくり自分が見たことを書くとname がある対象のファイルは files ignores で指定する。指定しなかった場合や、ignores だけを指定した場合の動きは特徴的なので先に把握しておくとよさそうPredefinedの設定はインポートして使うhttps://eslint.org/docs/latest/
9ヶ月前

NeverThrowを触ろうと思ったらESLintのFlat Configを触っていた(前編)
Mitsuyuki.Shiiba
TypeScriptでサーバーサイドのアプリケーションを書いていて、エラーをThrowするより型安全に失敗を返したいなと思って、簡単なResult型をペラっと作って使ったことがある。あまり複雑なことはしたくないからそれで満足しているんだけど、TSKaigiやTSKaigi KansaiでResult型の話をよく耳にしたので、ちゃんとライブラリを一個くらい勉強しようかなと思った。最初にあらすじneverthrowとeslint-plugin-neverthrowを入れてNeverThrowを触ろうとしたら、eslint-plugin-neverthrowがESLintのFlat Configに対応していなかったFlat Configを調べるところから始めて、最終的にeslint-plugin-neverthrowの問題はESLintが提供しているラッパーで解決したやったー!NeverThrowで遊べるぞー!←いまここ(つまりまだ遊んでない)長くなりそうなので途中で切った。NeverThrowを触ってみることにしたResult型が使えるライブラリってどういうのがあるの?って同僚の @kosui_me に聞いたら「fp-ts・Effect・NeverThrowがあるよ」って教えてもらったのと、@sadnessOjisan の記事を見かけてoption-tを知った。fp-ts: https://gcanti.github.io/fp-ts/Effect: https://effect.website/NeverThrow: https://github.com/supermacro/neverthrowoption-t: https://github.com/option-t/option-tほんとにちらっとだけ見てみて、fp-tsとEffectはResult型よりも広い範囲をカバーしてそうだなって感じた。関数型のプログラミングや、実現したいエコシステムがあって、その一つの要素としてResult型があるような印象。それはちょっと僕には大きいので、今回はやめておこうと思った。で、NeverThrowとoption-tはResult型をメインで扱っているのでどちらもいいなーと思いつつ、GitHubを眺めたりしてなんとなくNeverThrowを触ってみることにした。↓ @sadn
9ヶ月前

TSKaigi Kansaiから帰ってきてDuckDB Wasmで遊んだ
Mitsuyuki.Shiiba
カケハシのスタッフとしてTSKaigi Kansaiに参加して楽しんできた。スポンサーのランチLTでカケハシのメンバーも喋るからブースを抜け出して見に行ってたら、newmoの大貫さんのLTで「DuckDB Wasmを使ってクライアントだけで処理したよ!」って発表があって、面白いなーと思ったのだった。kansai.tskaigi.orgので、遊んだDuckDBは初めて知ったし、Wasmには興味があるので、遊んでみた。GitHub Pagesにアップロードしておいた。11/18の日本各地の最高気温が分かるよ!https://bufferings.github.io/vite-react-duckdb-wasm/やってるのはDuckDB Wasmをクライアントで取得してe-Govデータポータルの11/18の最高気温のCSVをDuckDBに入れてそのDBの内容をテーブルに表示テキストボックスの内容が変更されたら、SQLを実行してその値で結果をフィルタリングして表示最高気温のデータは、こちらからダウンロードしておいた。気象観測_最新の気象データ | 最高気温 | e-GovデータポータルCSVで何か適当なデータがほしいなと思ってe-Govからこれを見つけてきたのだ。Shift_JISだったのでUTF-8に変換して、静的コンテンツとしてダウンロードして使っている。面白かった。クライアントで処理するから速いよね。ふむふむ。ソースコードhttps://github.com/bufferings/vite-react-duckdb-wasm/どんなふうに動くのかなーって適当に試しただけなので、本番運用で使えるレベルのものでは全くない。使ってみたものDuckDB Wasmだけ使えたら満足なつもりで始めたのに、せっかく遊ぶんなら!ってちょこちょこ手をだして楽しんでた。Vite (+ React + TS) https://ja.vite.dev/素のHTMLでも楽しめそうだったけど、せっかくならReactとTSを使っておこうと思ってViteで作ったBiome https://biomejs.dev/TSKaigi KansaiでもBiomeの話をよく耳にしたなぁ。と思って、Viteの用意してくれたESLintを全部消して、BiomeでLintとFormatをするようにしてみたWebSto
10ヶ月前

TypeScript 5.8で条件付き戻り値型に対するナローイングができるようになりそう(特定の制約を満たす場合)
Mitsuyuki.Shiiba
数日前にTypeScript 5.7 RCがアナウンスされてリリースが楽しみだなー!ってところなんだけど、そのさらに数日前に、ウォッチしていたこのPR↓がマージされてTypeScript 5.8.0のマイルストーンに入った。わー!これが今日のお話。TypeScript 5.8.0でConditional return type narrowingが入りそう。楽しみ!Conditional return type narrowing?直訳すると「条件付き戻り値型の絞り込み」かな。引数の型によって戻り値の型が変わる関数を定義したいときに、例えばこんな風に書きたくなる。declare const record: Record<string, string[]>;declare const array: string[];function getObject<T extends string | undefined>( group: T): T extends string ? string[] : T extends undefined ? Record<string, string[]> : never { if (group === undefined) { return record; } return array;}const arrayResult = getObject("group");const recordResult = getObject(undefined);この例では、引数である group の型が文字列(またはそのサブタイプ)だったら文字列の配列を、undefined だったら Record<string, string[]> を返すように定義してある。でも、このコードはエラーになる2024-11-07現在のTypeScript 5.6.3では、このコードはエラーになる。呼び出す側のコードはエラーにならずに、渡した引数の型に合わせて正しく戻り値の型が判断されるんだけど(arrayResultの型はstring[]になっている)、関数の実装側の return 部分がエラーになる。「if ブロックの中に入るってことは group が undefined だってことだから戻り値の型は Record<string, string[]> だし、if ブロ
10ヶ月前

2024-10-26(土)にDevLOVE関西で喋ります! #devkan
Mitsuyuki.Shiiba
なんとDevLOVE関西200回目という記念すべき回でお話させてもらえることになりました!わーい。devlove-kansai.doorkeeper.jp喋る人みんなDevLOVE関西でたくさんお世話になってる人たちなので、楽しみ!そめださん、だいくしーさん、いろふさん、くぼさん!楽しみだー!ぜひ申し込んで見に来てねー!何を喋るの?ちょっとまだ固まってないんだけど、僕が開発をするときに考えていることを、来てくれた人と会話しながら紹介できたらいいなって思っています。2011年くらいからアジャイルな開発を実践してきて、自分の中にだいぶ開発の型ができてきたかなぁと思うのでそのあたりを。何を大切にして開発してる?チームとか役割とかどういう感じがいい?計画づくりや見積もりどうしてる?開発しながら運用どうしてる?ディスカバリーもどうしてる?テスターやデザイナーとどういう感じで仕事するのがいい?とかとか。そのあたりで、適当に自分の考えをメモしていくので、その場にいる人に「どの話をしよう?」って聞いて、その話ができたらいいかなって思っています。インプットの期間だけどなんとなく、自分の中ではあと半年くらいはインプットの期間にしたいなぁと思っているので、今は発表はしないようにしているのだけど。DevLOVE関西は、自分の中でも大切な場なので喋るぞー!!!という気持ち。見に来てねー!ということで、関西のかたはぜひ申し込んで遊びにきてねー!発表が終わった後も喋ろうー!
1年前

はてなブログのコードブロックでPrism.jsを使うようにしてたところにラベルを表示できるようにした
Mitsuyuki.Shiiba
最近ブログのデザインを変えた。その続きで少し改修した。bufferings.hatenablog.com何を修正したのか?コードブロックでファイル名などのラベルを出せたらいいなと思ったので対応した。↓これはスクリーンキャプチャ。hello.javaが表示されている。シンタックスハイライトが効いていることを確認したかっただけなのでコードの内容は関係ない。こんな感じ↓これは実際のコードブロック。sealed interface Mapping<T> { T value(); record A(Boolean value) implements Mapping<Boolean> {} record B(String value) implements Mapping<String> {}}↓こう書いている```java:hello.javasealed interface Mapping<T> { T value(); record A(Boolean value) implements Mapping<Boolean> {} record B(String value) implements Mapping<String> {}}```仕組み僕は、はてなブログをマークダウンで書いているので、コードブロックは```javaみたいに言語を指定して書いている。そうするとこんな感じのHTMLになる。<pre class="code lang-java" data-lang="java" data-unlink="">classにlang-javaが設定されて、data-langにjavaが設定されている。ここで```java:hello.javaとコロンにつなげてラベルを書いてみるとこうなる。<pre class="code java:hello.java" data-lang="java:hello.java" data-unlink="">classのlang-javaがjava:hello.javaになっていて、はてなのシンタックスハイライトは効かない状態になる。だけど、僕はブログのデザインを変えたときに、コードブロックにはPrism.jsを使うようにしているので問題ない。Prism.jsのtoolbarプラグインを使う自分で実装しようかと思ったけど、ちょうどいいプラグイ
1年前

前回TypeScriptでやった「タグ付きユニオンのタグを指定して、型安全に値を取り出したい」をJavaでやってみた
Mitsuyuki.Shiiba
前回書いたこれを同僚に「こんな感じだったよ。勉強になったよー!」って見せたら「なるほど勉強になった!ありがとう!」って言ってもらえたのでよかった。bufferings.hatenablog.comそしてその同僚が「こういうのってJavaだったらどう書くの?」って言って「んー。最近Java書いてないからどうだっけなぁ・・・そもそもJavaのときには、Discriminated Unionみたいなの欲しいと思ったことなかった気がするなぁ」ってなったのでJavaで考えてみることにした。前回の記事のTypeScriptのコードtype MyUnion = | { tag: "a", value: boolean } | { tag: "b", value: string }const values: MyUnion[] = [ { tag: "a", value: true }, { tag: "b", value: "foo" },]type MyMapping = { [I in MyUnion as I["tag"]]: I["value"]}function getValue<T extends MyUnion["tag"]>(t: T): MyMapping[T] { for (const v of values) { if (v.tag === t) { return v.value as MyMapping[T]; } } throw new Error("Unknown tag.");}このコードでやりたいことは「タグ付きユニオンのタグを指定して、型安全に値を取り出したい」ということ。結局最後はType Assertionを使ってしまった。Javaで考えてみるだいぶ久しぶりのJavaだいぶ久しぶりにJavaを触ったので思い出したりしながら考える。もうバージョン23かー!今なら println(...) だけでもいけるって @sugarlife さんに教えてもらったのでやってみたらいけた!みじかいー!ありがとうございます! https://t.co/2n6KfX2ipu pic.twitter.com/kVMww4L3Id— SHIIBA Mitsuyuki (@bufferings) 2024年9月22日 そもそもを考えるそもそも「タグ付きユニオンのタグを指
1年前

TypeScriptでGeneric Typeに対するNarrowingをしたかったけど現在のところ対応していなかった
Mitsuyuki.Shiiba
2024-11-11 追記ここから ----TS 5.8で、その1のインデックスアクセス型の方はサポートされそう。その2の方はその対応が入ってもサポートされない。追記ここまで ----最初にまとめ現在のTypeScript(2024-09-19時点のバージョン5.6.2)では Generics と Control Flow Analysis は、いい感じには連携しないということを学んだ。どういうこと?その1Genericsを使って型安全にやりたいなぁと思って、こんなコードを書いてみてもコンパイルエラーになる。type Mapping = { a: boolean, b: string,}function getValue<K extends "a" | "b">(key: K): Mapping[K] { if (key === "a") { return true; } return "foo";}このコードでやりたいのは「パラメータとして"a"を渡すとboolean型の値を、"b"を渡すとstring型の値を返す」ということ。key === "a"のところでKが"a"であることが分かるので、Mapping["a"]にあたるboolean型で返してくれそうなもんだよね。でも、実際は次のようなコンパイルエラーになる。Type 'true' is not assignable to type 'Mapping[K]'. Type 'boolean' is not assignable to type 'never'.Genericsの型パラメータに対してはNarrowingが行われないから、ということらしい。Narrowingが行われなかった結果never型になるのは、戻り値の型としてboolean型とstring型の可能性があるから、どちらも満たす必要がある。つまりboolean & stringだからnever型になっている。参考にした情報↓これを読んだ。typescript - Type narrowing for the return type of a function with switch - Stack Overflow回答者のjcalzさんは、GenericsとNarrowingまわりを調べるとたくさん出てくる。TypeScriptのコントリビュータ
1年前

バグを見つける
Mitsuyuki.Shiiba
僕は、実装するペアとは別のペアがテストをするのがわりと好き。仕様からテストを設計して実施してたら、実装者が見逃してたバグを見つけられたりする。バグを見つけるのって面白い。でも、見つけるより前に、減らしておきたい。だから、プロジェクト全体で誰が意思決定者なのかをキックオフの段階で明確にしておきたい。誰が決めるかが分からないプロジェクトは迷走してバグが生まれやすくなる。だから、プロダクトマネージャーには機能改修の背景を聞いてから機能の話を聞きたい。背景と機能が自分の中でつながらないときは、何か認識のズレがあってバグが生まれやすくなる。だから、スコープは小さくしたい。スコープが大きいとバグが生まれやすくなる。だから、関係する他チームとのコミュニケーションを最初に設計しておきたい。チーム間のコミュニケーションがうまくいかないとバグが生まれやすくなる。だから、早い段階で動くものをステークホルダーに見てもらってフィードバックをもらいたい。実際に動くものを見ると気がつくことがある。頭の中や言葉だけだと勘違いがあってバグが生まれやすくなる。だから、設計は誰かエンジニア1人がリードしつつも、毎日その図を見ながらエンジニア4人でわちゃわちゃ議論したい。複数の目で見ることで設計の問題に早く気づけて、バグが生まれにくくなる。だから、実装ペアとテストペアを分けて、仕様を元に実装をするペアと、仕様を元にテストを設計して実施するペアに分かれたい。実装ペアは「テストペアにはバグを見つけさせない!」って自動テストや動作確認をしてからテストペアに渡して、テストペアは「絶対にバグを見つける!」って取り組むと、ここでバグを見つけやすくなる。だから、システム化された部分以外も含んだ業務全体の運用をプロダクトマネージャーと一緒に考えたい。運用が回らない・ミスをしやすいというバグが見つけやすくなる。それでも通り抜けてしまったバグを見つけるために「ただしく動いていたらどこがどうなる?」「ただしく動いてなかったらどこがどうなる?」って考えて監視を設計して実装したい。そうすると、ユーザーが気づくより先にバグを見つけて対応できる。そんな風に全体の流れを見て、バグを生みにくくして、バグを見つけたいなと思っている。
1年前

このはてなブログのデザインを変更した
Mitsuyuki.Shiiba
なんとなくこのブログのシンタックスハイライトのデザインを変えたいなぁと思って、せっかくだからブログのテーマごと変更するかーってテーマストアを眺めてたら、自分で自分が好きな感じのテーマを作ってみるのも面白い・・・か、と思ったのでやってみた。PCスマホわりと気に入っている。コードたまに間違えて上書きして消してしまったりするので、念のためGitHubに置いといた。https://github.com/bufferings/hatenablog-my-theme自分が使ってる機能だけ対応はてなブログにはいろんな機能や設定があるけど、それを全部サポートするのは僕には無理なので、自分が使ってる機能だけに絞って対応した。ブログのコメント機能とか、はてなのキーワード機能とかはオフにしてるから対応してない。CSSにはボイラープレートのままのコードがあるだけ。細かいことは気にしない自分が見た目を気に入ればいいやという気持ちでCSSを直接ごにょごにょしながら作った。中で float:left を使おうと !important を使おうと、共通の色を変数化してなかろうと問題ない!動けばよかろうなのだー!レスポンシブ対応レスポンシブ対応で作った。PC用とスマホ用を別々に作るの無理だと思ったので。コードのシンタックスハイライトこれがいちばん対応したかったやつ。もともとは highlight.js でごにょごにょしてたので、今回は Prism を使ってみようと思って↓こちらのブログを参考に設定した。感謝。tech.natsuneko.blogCSSには、TOMORROW NIGHTを選んだ。何日か前に書いたTypeScriptのコードはこんな感じにハイライトされるようになった。満足。type A = Extract<MyUnion, { tag: "a" | "b" }>type cases = [ Expect<Equal<A, { tag: "a" | "b", value: boolean }>>,]ちょこっと触ったところ参考にした記事にも書かれているとおり、はてなのCSSが !important でシンタックスハイライトの色付けをしてるので、それを上書きしないといけない。だからCSSをダウンロードしたあとに、色関係は !important してる。はみ出した部分はてなのCSSでは、pre
1年前