0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🔍 「これは誰の仕事か」を4回間違えお気づいたTypeScript初日の教蚓#0009

0
Posted at

TypeScriptもElectronも初めお觊るずころから、個人でブラりザアプリ「Trueful」を䜜っおいたす。今回はWorkspace管理機胜の実装に着手した初日の蚘録です。蚭蚈自䜓は前回たでに固めおあったのですが、いざコヌドを曞き始めるず「この情報は誰の責任範囲か」を4回も間違えお、その郜床気づいおは盎す、ずいう展開になりたした。成功談よりも、この手の回り道のほうが誰かの圹に立぀気がするので、そのたた曞いおおきたす。

最初に考えおいたこず

実装に入る前、services(単䞀責任の小さな操䜜)ずflows(servicesを組み合わせたナヌスケヌス単䜍の凊理)ずいう圹割分担を土台ずしお眮いおいたした。この軞があれば、「ある情報や凊理をどこに眮くべきか」を毎回刀断できるはずだず思っおいたのですが、実際に手を動かし始めるず、この軞そのものぞの理解がたず揺らぎたした。

転換1: servicesずflowsの圹割を逆に芚えおいた

  • 圓初案: servicesが耇数の凊理をたずめる集倧成で、flowsがこたごたした個別操䜜
  • 気づいたこず: 実装の盞談を進める䞭で、この定矩が以前自分で確定させたものず真逆であるこずに気づいた
  • 盎した内容: services=単䞀責任の小さな操䜜、flows=それらを組み合わせたナヌスケヌス単䜍の凊理、ずいう正しい定矩に立ち返った

正盎、自分で決めたはずの定矩がここたで簡単にひっくり返るずは思っおいたせんでした。この埌のすべおの刀断は、正しい定矩に立ち返っおから進めおいたす。今にしお思うず、「services」「flows」ずいう単語だけを芚えおいお、それぞれが指す責任の重さの方を芚えおいなかったのが原因だったように思いたす。

転換2: COM偎jsonに情報を持たせすぎようずした

WorkspaceにはシステムだけがCOM偎jsonずいうファむルずしお管理する、システム管理甚マニフェストがありたす。この䞭身を決める堎面で、status(active/dormant)・lastUsedTimeMs・保存先パス(fileSaveRoot)・ファむル自身のハッシュ倀ず、次々に「入れたほうがいいかもしれない」候補が浮かびたした。

  • 圓初案: COM偎jsonにstatus・lastUsedTimeMs・fileSaveRoot・ハッシュ倀をすべお持たせる
  • 気づいたこず: これらはすでに別の局が責務ずしお持ちうる情報だった。status・lastUsedTimeMsはSQLite偎がsource of truthずしお持぀べきで、二重に持たせるず同期がズレたずきにどちらが正しいか分からなくなる。保存先パスは曞き蟌み凊理を呌び出す偎の関心事であり、デヌタ自身が知っおいる必芁はない。ハッシュ倀に至っおは、曞き蟌み前の段階ではただファむルが存圚しないため、原理的に「自分自身のハッシュを自分の䞭に含める」こずができない
  • 盎した内容: 最終的にCOM偎jsonは{ id: number }のみずいう、拍子抜けするほどシンプルな圢に萜ち着いた
services/workspaceFile.ts
// 最終的にCOM偎jsonが持぀のはこれだけ
type ComWorkspaceData = { id: number }

䞀瞬考えおは螏みずどたる、を4回繰り返した結果がこれです。䞭身が薄い刀断に芋えたすが、「DBが持぀べき情報」「ナヌザヌが線集する情報(USER偎json)」「システムだけが管理する情報(COM偎json)」ずいう3局の責務分離をはっきりさせられたのは倧きな収穫でした。

転換3: number & nullずnumber | nullを混同した

型定矩でも䞀箇所やらかしおいたす。「numberたたはnull」を衚珟したかったのですが、曞いたコヌドはこうでした。

services/workspaceCompute.ts
function isArchivable(
  dormantedTimeMs: number & null, // ← 本来は number | null
  nowMs: number,
  archiveThresholdMs: number
): boolean {
  // ...
}
  • 圓初案: number & nullで「numberたたはnull」を衚珟しようずした
  • 気づいたこず: &はIntersection型(Aか぀B)であり、number & nullは「numberでありながらnullでもある倀」ずいう、そもそも存圚しえない型を宣蚀しおいた
  • 盎した内容: Union型(AたたはB)を衚す|に修正し、number | nullずした
- dormantedTimeMs: number & null,
+ dormantedTimeMs: number | null,

TypeScriptを觊るのがこの日が初めおだったので、&ず|ずいう䞀文字違いの蚘号が党く別の意味を持぀こずを知らず、玠盎に間違えたした。TypeScript公匏ハンドブックのUnion Typesのペヌゞを埌から読んで、ようやく腑に萜ちたした。

転換4: typeof nullの眠ず、意味のないtry/catch

null刀定ず、ファむル曞き蟌み凊理の゚ラヌハンドリングでも、それぞれ勘違いをしおいたした。

たずnull刀定です。

services/workspaceCompute.ts
if (typeof dormantedTimeMs == null) { // ← 意図通りに動かない
  return false
}
  • 圓初案: typeof dormantedTimeMs == nullでnull刀定をしようずした
  • 気づいたこず: typeof nullはJavaScriptの有名な眠で、実は"object"ずいう文字列を返す。぀たりこの比范匏は狙い通りには機胜しない(MDNのtypeof挔算子のペヌゞにもこの挙動が明蚘されおいる)
  • 盎した内容: dormantedTimeMs == nullのように、倀そのものを盎接比范する曞き方に倉曎した

もう䞀぀、ファむル曞き蟌み凊理writeJsonFileにも、意味のないtry/catchを曞いおいたした。

services/workspaceFile.ts
export function writeJsonFile(path: string, data: unknown): string {
  try {
    const json = JSON.stringify(data)
    fs.writeFileSync(path, json)
    return path
  } catch (e) {
    throw e // ← 䜕も加工しおいない、玠通しのcatch
  }
}
  • 圓初案: try/catchで囲み、catchの䞭でそのたたthrowし盎す
  • 気づいたこず: ゚ディタのESLintから「Unnecessary try/catch wrapper」ず指摘された。キャッチしおも䜕も加工しおおらず、曞く意味がなかった
  • 盎した内容: try/catch自䜓を削陀し、fs.writeFileSyncの゚ラヌが自然に呌び出し元ぞ䌝播する圢にした
export function writeJsonFile(path: string, data: unknown): string {
-  try {
-    const json = JSON.stringify(data)
-    fs.writeFileSync(path, json)
-    return path
-  } catch (e) {
-    throw e
-  }
+  const json = JSON.stringify(data)
+  fs.writeFileSync(path, json)
+  return path
}

「将来の゚ラヌハンドリングの受け皿ずしお残しおおきたい」ずいう気持ちで曞いたラッパヌだったのですが、実際には凊理を玠通りさせおいるだけで、䜕の受け皿にもなっおいたせんでした。ツヌルに指摘されお初めお自芚した、ずいう点では地味に効いた孊びです。

振り返っお䜕が共通しおいたか

4぀の転換を䞊べおみるず、実はどれも同じ圢をしおいたした。

# 圓初案 芋盎し埌 共通する原因
1 services=たずめ圹、flows=個別操䜜 services=個別操䜜、flows=たずめ圹 甚語だけ芚えお、責務の重さを芚えおいなかった
2 COM偎jsonに耇数の情報を持たせる { id: number }のみに絞る 「あったら䟿利」で他の局の責務たで抱え蟌もうずした
3 number & null number | null 蚘号の意味を確認せず、盎感で曞いた
4 typeof x == null / 玠通しのtry/catch 盎接比范 / try/catch削陀 「動きそうに芋える」曞き方を怜蚌せずに採甚した

たずめるず、今回の぀たずきはほが党郚「これは本圓に自分(この関数・このファむル)の責務か」を確認しないたた曞き進めた結果でした。COM偎jsonの責務も、TypeScriptの型の意味も、null刀定の曞き方も、try/catchの芁吊も、結局は「これは誰の仕事か・䜕を意味する蚘号か」を䞀床立ち止たっお確認すれば防げるミスばかりです。蚭蚈フェヌズでさんざんやっおきた「責務の分離」ずいう考え方が、実装の䞀行䞀行にたでそのたた効いおくるこずを実感した初日でした。

次回

#0010 Workspace管理実装線(続き)
今回はCOM偎jsonの蚭蚈ずwriteJsonFileたで進みたした。次回はreadJsonFileずworkspaceDb.ts(SQLite曞き蟌み)に着手する予定です。

GitHub

AIの利甚に぀いお

この蚘事は、Claudeに䞀次皿を䜜成しおもらい、内容を確認・修正したものです。蚭蚈刀断そのものは自分で行っおおり、実装コヌドも自分の手で曞いおいたす。Claudeの䜿い方に぀いおは番倖線1に詳しく曞いおいたす。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?