[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fqQTkX5xIJWB7y5pzBjuLxUQtpwF5g2M3GrdN5D2SbTM":3,"$fiyeQuD8zUl49VB_u0wPs3D7LeIpsAii0J2wskfEySqw":2380,"$fRDFvlscftQrW2nsFXMDCR6Fe_jbyF3Er094H0c_D2fA":2384,"$f2DlVqZDVksL7ADIr0C0kho3gdWoEnkd1DjBIBWLVxJg":2386,"$f8e2WFn5mY2TM1g-cwi0bWJHlTu4aeL05CrTRcRh6ze8":2390},{"id":4,"title":5,"body":6,"date":2365,"description":2366,"extension":2367,"icon":2368,"meta":2369,"navigation":346,"ogImage":2370,"path":2371,"published":346,"publishedAt":2372,"seo":2373,"stem":2374,"tags":2375,"updatedAt":2378,"__hash__":2379},"tech/tech/small-is-not-simple.md","小さいこととシンプルは違う",{"type":7,"value":8,"toc":2353},"minimark",[9,13,17,20,32,37,56,60,66,69,75,78,81,87,96,100,103,106,110,113,871,874,917,920,923,926,2209,2212,2251,2254,2258,2265,2271,2283,2286,2290,2296,2302,2306,2309,2312,2315,2318,2337,2340,2343,2346,2349],[10,11,12],"p",{},"O'Reilly の『シンプリシティ』を読みました。",[14,15],"external-link-card-wrapper",{"url":16},"https://www.oreilly.co.jp/books/9784814401710/",[10,18,19],{},"この本は、仕事論・組織論・人生論など、概念的なプラクティスを中心に扱っています。",[10,21,22,23,26,27,31],{},"これはこれで勉強になるのですが、ソフトウェア設計について書かれていることを期待していた身としては、そこにあまりページが割かれていなかったのは物足りなく感じました。（この本でもたびたび唱えているように、何がシンプルかは文脈によって異なるため、あえて扱っていないのだと思います。）",[24,25],"br",{},"\nそこで本記事では、ソフトウェア設計を、",[28,29,30],"strong",{},"シンプルさとコードの小ささという観点","で深掘りしてみようと思います。",[33,34,36],"h2",{"id":35},"tldr最初に結論","TL;DR（最初に結論）",[38,39,40,44,47,50,53],"ul",{},[41,42,43],"li",{},"シンプルとは、小さいことではなく、分けて考えられること",[41,45,46],{},"小さくても、複数の責務が絡み合ったコードはシンプルではない",[41,48,49],{},"シンプルさのものさしは、同時に考えなければならないことの数",[41,51,52],{},"コードは改修を重ねるうちに絡み合っていく。だから、改修のたびに境界を意識し続ける",[41,54,55],{},"AI時代でも、品質に責任を持つのは人間。信頼できるコードのために、シンプルさは今も欠かせない",[33,57,59],{"id":58},"シンプル小さいという誤解","「シンプル＝小さい」という誤解",[10,61,62],{},[63,64,65],"em",{},"「ここのコード、もう少しシンプルにできない？」",[10,67,68],{},"コードレビューで、このように言われたり、言ったりしたことはありませんか？（あるいは、AIにこのような指示を出したり）\nシンプルとは便利な言葉で、具体的に何が悪いのかを言わなくても「今のままでは良くない」ことだけは伝えられます。",[10,70,71,74],{},[28,72,73],{},"シンプル","とは何なのでしょうか？",[10,76,77],{},"こういう語義を考えるときは、その対義語から考えると意味をつかみやすいです。\nsimple の対義語は complex です。complex は語源をたどると「編み合わされた」という意味です。つまり、絡み合っていない状態がシンプルであると言えます。",[10,79,80],{},"ところが、シンプルはよく「小さいこと」と混同されます。コードが短い、ロジックが少ない、1つのファイルにまとまっている。こうした小ささは見通しの良さには繋がりますが、それだけで設計がシンプルとまでは言えません。小さいコードの中にも、複数の責務が絡み合っていることは往々にしてあります。",[10,82,83,84,74],{},"では、",[28,85,86],{},"ソフトウェア設計におけるシンプル",[10,88,89,92,93,95],{},[28,90,91],{},"シンプルとは、分けて考えられること"," であると本記事では定義します。",[24,94],{},"\n分けて考えられることは、対象を理解・変更・検証するときに強力です。",[33,97,99],{"id":98},"コードで見る小ささとシンプルさ","コードで見る、小ささとシンプルさ",[10,101,102],{},"分けて考えられると何が嬉しいのか、CSVファイルからユーザーを取り込む処理を例に、具体的に見ていきます。",[10,104,105],{},"各行を検証し、エラーがあれば保存せずに行番号と理由を返し、問題がなければユーザーを保存して取り込み件数を返す、という関数です。",[107,108,109],"h3",{"id":109},"小さくても複雑な設計",[10,111,112],{},"読み込み・検証・保存を、1つの関数にまとめます。",[114,115,120],"pre",{"className":116,"code":117,"language":118,"meta":119,"style":119},"language-ts shiki shiki-themes material-theme-lighter github-dark-high-contrast github-dark","/**\n * CSVファイルからユーザーを取り込む。\n * 1行でもエラーがあれば、何も保存せずにエラーの一覧を返す。\n */\nconst importUsers = async (file: File): Promise\u003CImportResult> => {\n  const lines = (await file.text()).split(\"\\n\").slice(1)\n  const seen = new Set\u003Cstring>()\n  const errors: ImportError[] = []\n  const users: NewUser[] = []\n\n  for (const [i, line] of lines.entries()) {\n    const [name, email] = line.split(\",\")\n    const row = i + 2\n\n    if (!name || !email) errors.push({ row, reason: \"必須項目がありません\" })\n    else if (!EMAIL_RE.test(email)) errors.push({ row, reason: \"形式が不正です\" })\n    else if (seen.has(email)) errors.push({ row, reason: \"CSV内で重複しています\" })\n    else if (await db.user.exists({ email })) errors.push({ row, reason: \"登録済みです\" })\n    else users.push({ name, email })\n\n    seen.add(email)\n  }\n\n  if (errors.length > 0) return { ok: false, errors }\n\n  await db.transaction((tx) => tx.user.createMany(users))\n  return { ok: true, importedCount: users.length }\n}\n","ts","",[121,122,123,132,138,144,150,206,273,300,322,341,348,389,426,445,450,510,567,619,682,708,713,730,736,741,786,791,835,865],"code",{"__ignoreMap":119},[124,125,128],"span",{"class":126,"line":127},"line",1,[124,129,131],{"class":130},"sZPSj","/**\n",[124,133,135],{"class":126,"line":134},2,[124,136,137],{"class":130}," * CSVファイルからユーザーを取り込む。\n",[124,139,141],{"class":126,"line":140},3,[124,142,143],{"class":130}," * 1行でもエラーがあれば、何も保存せずにエラーの一覧を返す。\n",[124,145,147],{"class":126,"line":146},4,[124,148,149],{"class":130}," */\n",[124,151,153,157,161,165,168,172,176,179,183,186,188,191,194,197,200,203],{"class":126,"line":152},5,[124,154,156],{"class":155},"sGRfs","const",[124,158,160],{"class":159},"s8Xov"," importUsers",[124,162,164],{"class":163},"sUBcA"," =",[124,166,167],{"class":155}," async",[124,169,171],{"class":170},"seLpV"," (",[124,173,175],{"class":174},"senS2","file",[124,177,178],{"class":163},":",[124,180,182],{"class":181},"sywW5"," File",[124,184,185],{"class":170},")",[124,187,178],{"class":163},[124,189,190],{"class":181}," Promise",[124,192,193],{"class":170},"\u003C",[124,195,196],{"class":181},"ImportResult",[124,198,199],{"class":170},">",[124,201,202],{"class":155}," =>",[124,204,205],{"class":170}," {\n",[124,207,209,212,216,218,221,225,229,232,236,239,241,244,247,251,255,257,259,261,264,266,270],{"class":126,"line":208},6,[124,210,211],{"class":155},"  const",[124,213,215],{"class":214},"sSuNx"," lines",[124,217,164],{"class":163},[124,219,171],{"class":220},"sLCpo",[124,222,224],{"class":223},"stP2V","await",[124,226,228],{"class":227},"sdyPO"," file",[124,230,231],{"class":170},".",[124,233,235],{"class":234},"s7KVs","text",[124,237,238],{"class":220},"())",[124,240,231],{"class":170},[124,242,243],{"class":234},"split",[124,245,246],{"class":220},"(",[124,248,250],{"class":249},"sPUPB","\"",[124,252,254],{"class":253},"sGBsI","\\n",[124,256,250],{"class":249},[124,258,185],{"class":220},[124,260,231],{"class":170},[124,262,263],{"class":234},"slice",[124,265,246],{"class":220},[124,267,269],{"class":268},"sFHE5","1",[124,271,272],{"class":220},")\n",[124,274,276,278,281,283,286,289,291,295,297],{"class":126,"line":275},7,[124,277,211],{"class":155},[124,279,280],{"class":214}," seen",[124,282,164],{"class":163},[124,284,285],{"class":163}," new",[124,287,288],{"class":234}," Set",[124,290,193],{"class":170},[124,292,294],{"class":293},"snYqn","string",[124,296,199],{"class":170},[124,298,299],{"class":220},"()\n",[124,301,303,305,308,310,313,316,319],{"class":126,"line":302},8,[124,304,211],{"class":155},[124,306,307],{"class":214}," errors",[124,309,178],{"class":163},[124,311,312],{"class":181}," ImportError",[124,314,315],{"class":220},"[] ",[124,317,318],{"class":163},"=",[124,320,321],{"class":220}," []\n",[124,323,325,327,330,332,335,337,339],{"class":126,"line":324},9,[124,326,211],{"class":155},[124,328,329],{"class":214}," users",[124,331,178],{"class":163},[124,333,334],{"class":181}," NewUser",[124,336,315],{"class":220},[124,338,318],{"class":163},[124,340,321],{"class":220},[124,342,344],{"class":126,"line":343},10,[124,345,347],{"emptyLinePlaceholder":346},true,"\n",[124,349,351,354,356,358,361,364,367,370,373,376,378,380,383,386],{"class":126,"line":350},11,[124,352,353],{"class":223},"  for",[124,355,171],{"class":220},[124,357,156],{"class":155},[124,359,360],{"class":170}," [",[124,362,363],{"class":214},"i",[124,365,366],{"class":170},",",[124,368,369],{"class":214}," line",[124,371,372],{"class":170},"]",[124,374,375],{"class":163}," of",[124,377,215],{"class":227},[124,379,231],{"class":170},[124,381,382],{"class":234},"entries",[124,384,385],{"class":220},"()) ",[124,387,388],{"class":170},"{\n",[124,390,392,395,397,400,402,405,407,409,411,413,415,417,419,422,424],{"class":126,"line":391},12,[124,393,394],{"class":155},"    const",[124,396,360],{"class":170},[124,398,399],{"class":214},"name",[124,401,366],{"class":170},[124,403,404],{"class":214}," email",[124,406,372],{"class":170},[124,408,164],{"class":163},[124,410,369],{"class":227},[124,412,231],{"class":170},[124,414,243],{"class":234},[124,416,246],{"class":220},[124,418,250],{"class":249},[124,420,366],{"class":421},"sSIes",[124,423,250],{"class":249},[124,425,272],{"class":220},[124,427,429,431,434,436,439,442],{"class":126,"line":428},13,[124,430,394],{"class":155},[124,432,433],{"class":214}," row",[124,435,164],{"class":163},[124,437,438],{"class":227}," i",[124,440,441],{"class":163}," +",[124,443,444],{"class":268}," 2\n",[124,446,448],{"class":126,"line":447},14,[124,449,347],{"emptyLinePlaceholder":346},[124,451,453,456,458,461,463,466,469,472,475,478,480,483,485,488,490,492,495,497,500,503,505,508],{"class":126,"line":452},15,[124,454,455],{"class":223},"    if",[124,457,171],{"class":220},[124,459,460],{"class":163},"!",[124,462,399],{"class":227},[124,464,465],{"class":163}," ||",[124,467,468],{"class":163}," !",[124,470,471],{"class":227},"email",[124,473,474],{"class":220},") ",[124,476,477],{"class":227},"errors",[124,479,231],{"class":170},[124,481,482],{"class":234},"push",[124,484,246],{"class":220},[124,486,487],{"class":170},"{",[124,489,433],{"class":227},[124,491,366],{"class":170},[124,493,494],{"class":220}," reason",[124,496,178],{"class":170},[124,498,499],{"class":249}," \"",[124,501,502],{"class":421},"必須項目がありません",[124,504,250],{"class":249},[124,506,507],{"class":170}," }",[124,509,272],{"class":220},[124,511,513,516,519,521,523,526,528,531,533,535,538,540,542,544,546,548,550,552,554,556,558,561,563,565],{"class":126,"line":512},16,[124,514,515],{"class":223},"    else",[124,517,518],{"class":223}," if",[124,520,171],{"class":220},[124,522,460],{"class":163},[124,524,525],{"class":214},"EMAIL_RE",[124,527,231],{"class":170},[124,529,530],{"class":234},"test",[124,532,246],{"class":220},[124,534,471],{"class":227},[124,536,537],{"class":220},")) ",[124,539,477],{"class":227},[124,541,231],{"class":170},[124,543,482],{"class":234},[124,545,246],{"class":220},[124,547,487],{"class":170},[124,549,433],{"class":227},[124,551,366],{"class":170},[124,553,494],{"class":220},[124,555,178],{"class":170},[124,557,499],{"class":249},[124,559,560],{"class":421},"形式が不正です",[124,562,250],{"class":249},[124,564,507],{"class":170},[124,566,272],{"class":220},[124,568,570,572,574,576,579,581,584,586,588,590,592,594,596,598,600,602,604,606,608,610,613,615,617],{"class":126,"line":569},17,[124,571,515],{"class":223},[124,573,518],{"class":223},[124,575,171],{"class":220},[124,577,578],{"class":227},"seen",[124,580,231],{"class":170},[124,582,583],{"class":234},"has",[124,585,246],{"class":220},[124,587,471],{"class":227},[124,589,537],{"class":220},[124,591,477],{"class":227},[124,593,231],{"class":170},[124,595,482],{"class":234},[124,597,246],{"class":220},[124,599,487],{"class":170},[124,601,433],{"class":227},[124,603,366],{"class":170},[124,605,494],{"class":220},[124,607,178],{"class":170},[124,609,499],{"class":249},[124,611,612],{"class":421},"CSV内で重複しています",[124,614,250],{"class":249},[124,616,507],{"class":170},[124,618,272],{"class":220},[124,620,622,624,626,628,630,633,635,638,640,643,645,647,649,651,653,655,657,659,661,663,665,667,669,671,673,676,678,680],{"class":126,"line":621},18,[124,623,515],{"class":223},[124,625,518],{"class":223},[124,627,171],{"class":220},[124,629,224],{"class":223},[124,631,632],{"class":227}," db",[124,634,231],{"class":170},[124,636,637],{"class":227},"user",[124,639,231],{"class":170},[124,641,642],{"class":234},"exists",[124,644,246],{"class":220},[124,646,487],{"class":170},[124,648,404],{"class":227},[124,650,507],{"class":170},[124,652,537],{"class":220},[124,654,477],{"class":227},[124,656,231],{"class":170},[124,658,482],{"class":234},[124,660,246],{"class":220},[124,662,487],{"class":170},[124,664,433],{"class":227},[124,666,366],{"class":170},[124,668,494],{"class":220},[124,670,178],{"class":170},[124,672,499],{"class":249},[124,674,675],{"class":421},"登録済みです",[124,677,250],{"class":249},[124,679,507],{"class":170},[124,681,272],{"class":220},[124,683,685,687,689,691,693,695,697,700,702,704,706],{"class":126,"line":684},19,[124,686,515],{"class":223},[124,688,329],{"class":227},[124,690,231],{"class":170},[124,692,482],{"class":234},[124,694,246],{"class":220},[124,696,487],{"class":170},[124,698,699],{"class":227}," name",[124,701,366],{"class":170},[124,703,404],{"class":227},[124,705,507],{"class":170},[124,707,272],{"class":220},[124,709,711],{"class":126,"line":710},20,[124,712,347],{"emptyLinePlaceholder":346},[124,714,716,719,721,724,726,728],{"class":126,"line":715},21,[124,717,718],{"class":227},"    seen",[124,720,231],{"class":170},[124,722,723],{"class":234},"add",[124,725,246],{"class":220},[124,727,471],{"class":227},[124,729,272],{"class":220},[124,731,733],{"class":126,"line":732},22,[124,734,735],{"class":170},"  }\n",[124,737,739],{"class":126,"line":738},23,[124,740,347],{"emptyLinePlaceholder":346},[124,742,744,747,749,751,753,756,759,762,764,767,770,773,775,779,781,783],{"class":126,"line":743},24,[124,745,746],{"class":223},"  if",[124,748,171],{"class":220},[124,750,477],{"class":227},[124,752,231],{"class":170},[124,754,755],{"class":214},"length",[124,757,758],{"class":163}," >",[124,760,761],{"class":268}," 0",[124,763,474],{"class":220},[124,765,766],{"class":223},"return",[124,768,769],{"class":170}," {",[124,771,772],{"class":220}," ok",[124,774,178],{"class":170},[124,776,778],{"class":777},"sBxIE"," false",[124,780,366],{"class":170},[124,782,307],{"class":227},[124,784,785],{"class":170}," }\n",[124,787,789],{"class":126,"line":788},25,[124,790,347],{"emptyLinePlaceholder":346},[124,792,794,797,799,801,804,806,808,811,813,815,818,820,822,824,827,829,832],{"class":126,"line":793},26,[124,795,796],{"class":223},"  await",[124,798,632],{"class":227},[124,800,231],{"class":170},[124,802,803],{"class":234},"transaction",[124,805,246],{"class":220},[124,807,246],{"class":170},[124,809,810],{"class":174},"tx",[124,812,185],{"class":170},[124,814,202],{"class":155},[124,816,817],{"class":227}," tx",[124,819,231],{"class":170},[124,821,637],{"class":227},[124,823,231],{"class":170},[124,825,826],{"class":234},"createMany",[124,828,246],{"class":220},[124,830,831],{"class":227},"users",[124,833,834],{"class":220},"))\n",[124,836,838,841,843,845,847,850,852,855,857,859,861,863],{"class":126,"line":837},27,[124,839,840],{"class":223},"  return",[124,842,769],{"class":170},[124,844,772],{"class":220},[124,846,178],{"class":170},[124,848,849],{"class":777}," true",[124,851,366],{"class":170},[124,853,854],{"class":220}," importedCount",[124,856,178],{"class":170},[124,858,329],{"class":227},[124,860,231],{"class":170},[124,862,755],{"class":214},[124,864,785],{"class":170},[124,866,868],{"class":126,"line":867},28,[124,869,870],{"class":170},"}\n",[10,872,873],{},"コードは20行ほどで、処理の流れも追えます。しかし、このコードを正しく読むには、次のことを同時に考える必要があります。",[38,875,876,890,900,903,909],{},[41,877,878,881,882,885,886,889],{},[121,879,880],{},"row = i + 2"," の ",[121,883,884],{},"2"," が何を足しているのか、離れた ",[121,887,888],{},".slice(1)"," まで読まないと分からない",[41,891,892,895,896,899],{},[121,893,894],{},"seen.add(email)"," がループの最後にあるため、形式が不正なメールアドレスや ",[121,897,898],{},"undefined"," も「出現済み」になる。これが意図どおりかは、ループ全体を読まないと判断できない",[41,901,902],{},"検証の途中でDBに問い合わせている。行ごとにクエリが走り、検証ルールをテストするだけでもDBが必要になる",[41,904,905,908],{},[121,906,907],{},"else if"," が連なっているため、1行につき最初のエラーしか返らない。これが意図どおりかは、コードから読み取れない",[41,910,911,913,914,916],{},[121,912,477],{}," と ",[121,915,831],{}," を同じループで積み上げているため、片方の条件を変えるともう片方にも影響する",[10,918,919],{},"検証ルールを1つ確認したいだけでも、CSVの形式、ループ内の状態、DBへの問い合わせまで頭に置かなければなりません。",[107,921,922],{"id":922},"大きくてもシンプルな設計",[10,924,925],{},"読み込み・検証・保存を、それぞれ別の関数に分けます。",[114,927,929],{"className":116,"code":928,"language":118,"meta":119,"style":119},"/**\n * CSVファイルからユーザーを取り込む。\n * 1行でもエラーがあれば、何も保存せずにエラーの一覧を返す。\n */\nconst importUsers = async (file: File): Promise\u003CImportResult> => {\n  const rows = await readUserCsv(file)\n  const registeredEmails = await findRegisteredEmails(rows)\n  const validation = validateUsers(rows, registeredEmails)\n\n  if (!validation.ok) {\n    return { ok: false, errors: validation.errors }\n  }\n\n  await saveUsers(validation.users)\n\n  return { ok: true, importedCount: validation.users.length }\n}\n\n/**\n * CSVファイルを読み込み、行番号付きのデータに変換する。\n * 行番号はヘッダーを1行目として数える。\n */\nconst readUserCsv = async (file: File): Promise\u003CCsvRow[]> => {\n  const [, ...lines] = (await file.text()).split(\"\\n\")\n\n  return lines.map((line, i) => {\n    const [name, email] = line.split(\",\")\n    return { row: i + 2, name, email }\n  })\n}\n\n/**\n * CSVに含まれるメールアドレスのうち、登録済みのものを返す。\n */\nconst findRegisteredEmails = async (rows: CsvRow[]): Promise\u003CSet\u003Cstring>> => {\n  const emails = rows.map(({ email }) => email).filter(Boolean)\n  const users = await db.user.findMany({ email: { in: emails } })\n\n  return new Set(users.map(({ email }) => email))\n}\n\n/**\n * 各行を検証し、エラーがなければ保存するユーザーデータを返す。\n * 1行につき、最初に見つかったエラーのみを返す。\n */\nconst validateUsers = (\n  rows: CsvRow[],\n  registeredEmails: Set\u003Cstring>,\n): ValidationResult => {\n  const errors: ImportError[] = []\n  const seen = new Set\u003Cstring>()\n\n  for (const { row, name, email } of rows) {\n    if (!name || !email) {\n      errors.push({ row, reason: \"必須項目がありません\" })\n      continue\n    }\n    if (!EMAIL_RE.test(email)) {\n      errors.push({ row, reason: \"形式が不正です\" })\n      continue\n    }\n    if (seen.has(email)) {\n      errors.push({ row, reason: \"CSV内で重複しています\" })\n      continue\n    }\n    seen.add(email)\n\n    if (registeredEmails.has(email)) {\n      errors.push({ row, reason: \"登録済みです\" })\n    }\n  }\n\n  if (errors.length > 0) {\n    return { ok: false, errors }\n  }\n\n  return { ok: true, users: rows.map(({ name, email }) => ({ name, email })) }\n}\n\n/**\n * トランザクション内でユーザーをまとめて保存する。\n */\nconst saveUsers = async (users: NewUser[]): Promise\u003Cvoid> => {\n  await db.transaction((tx) => tx.user.createMany(users))\n}\n",[121,930,931,935,939,943,947,981,1002,1023,1045,1049,1069,1096,1100,1104,1121,1125,1155,1159,1163,1167,1172,1177,1181,1219,1262,1266,1293,1325,1352,1360,1365,1370,1375,1381,1386,1430,1474,1519,1524,1555,1560,1565,1570,1576,1582,1587,1599,1614,1631,1645,1662,1683,1688,1719,1740,1772,1778,1784,1807,1838,1843,1848,1869,1900,1905,1910,1925,1930,1952,1983,1988,1993,1998,2019,2038,2043,2048,2103,2108,2113,2118,2124,2129,2167,2204],{"__ignoreMap":119},[124,932,933],{"class":126,"line":127},[124,934,131],{"class":130},[124,936,937],{"class":126,"line":134},[124,938,137],{"class":130},[124,940,941],{"class":126,"line":140},[124,942,143],{"class":130},[124,944,945],{"class":126,"line":146},[124,946,149],{"class":130},[124,948,949,951,953,955,957,959,961,963,965,967,969,971,973,975,977,979],{"class":126,"line":152},[124,950,156],{"class":155},[124,952,160],{"class":159},[124,954,164],{"class":163},[124,956,167],{"class":155},[124,958,171],{"class":170},[124,960,175],{"class":174},[124,962,178],{"class":163},[124,964,182],{"class":181},[124,966,185],{"class":170},[124,968,178],{"class":163},[124,970,190],{"class":181},[124,972,193],{"class":170},[124,974,196],{"class":181},[124,976,199],{"class":170},[124,978,202],{"class":155},[124,980,205],{"class":170},[124,982,983,985,988,990,993,996,998,1000],{"class":126,"line":208},[124,984,211],{"class":155},[124,986,987],{"class":214}," rows",[124,989,164],{"class":163},[124,991,992],{"class":223}," await",[124,994,995],{"class":234}," readUserCsv",[124,997,246],{"class":220},[124,999,175],{"class":227},[124,1001,272],{"class":220},[124,1003,1004,1006,1009,1011,1013,1016,1018,1021],{"class":126,"line":275},[124,1005,211],{"class":155},[124,1007,1008],{"class":214}," registeredEmails",[124,1010,164],{"class":163},[124,1012,992],{"class":223},[124,1014,1015],{"class":234}," findRegisteredEmails",[124,1017,246],{"class":220},[124,1019,1020],{"class":227},"rows",[124,1022,272],{"class":220},[124,1024,1025,1027,1030,1032,1035,1037,1039,1041,1043],{"class":126,"line":302},[124,1026,211],{"class":155},[124,1028,1029],{"class":214}," validation",[124,1031,164],{"class":163},[124,1033,1034],{"class":234}," validateUsers",[124,1036,246],{"class":220},[124,1038,1020],{"class":227},[124,1040,366],{"class":170},[124,1042,1008],{"class":227},[124,1044,272],{"class":220},[124,1046,1047],{"class":126,"line":324},[124,1048,347],{"emptyLinePlaceholder":346},[124,1050,1051,1053,1055,1057,1060,1062,1065,1067],{"class":126,"line":343},[124,1052,746],{"class":223},[124,1054,171],{"class":220},[124,1056,460],{"class":163},[124,1058,1059],{"class":227},"validation",[124,1061,231],{"class":170},[124,1063,1064],{"class":227},"ok",[124,1066,474],{"class":220},[124,1068,388],{"class":170},[124,1070,1071,1074,1076,1078,1080,1082,1084,1086,1088,1090,1092,1094],{"class":126,"line":350},[124,1072,1073],{"class":223},"    return",[124,1075,769],{"class":170},[124,1077,772],{"class":220},[124,1079,178],{"class":170},[124,1081,778],{"class":777},[124,1083,366],{"class":170},[124,1085,307],{"class":220},[124,1087,178],{"class":170},[124,1089,1029],{"class":227},[124,1091,231],{"class":170},[124,1093,477],{"class":227},[124,1095,785],{"class":170},[124,1097,1098],{"class":126,"line":391},[124,1099,735],{"class":170},[124,1101,1102],{"class":126,"line":428},[124,1103,347],{"emptyLinePlaceholder":346},[124,1105,1106,1108,1111,1113,1115,1117,1119],{"class":126,"line":447},[124,1107,796],{"class":223},[124,1109,1110],{"class":234}," saveUsers",[124,1112,246],{"class":220},[124,1114,1059],{"class":227},[124,1116,231],{"class":170},[124,1118,831],{"class":227},[124,1120,272],{"class":220},[124,1122,1123],{"class":126,"line":452},[124,1124,347],{"emptyLinePlaceholder":346},[124,1126,1127,1129,1131,1133,1135,1137,1139,1141,1143,1145,1147,1149,1151,1153],{"class":126,"line":512},[124,1128,840],{"class":223},[124,1130,769],{"class":170},[124,1132,772],{"class":220},[124,1134,178],{"class":170},[124,1136,849],{"class":777},[124,1138,366],{"class":170},[124,1140,854],{"class":220},[124,1142,178],{"class":170},[124,1144,1029],{"class":227},[124,1146,231],{"class":170},[124,1148,831],{"class":227},[124,1150,231],{"class":170},[124,1152,755],{"class":214},[124,1154,785],{"class":170},[124,1156,1157],{"class":126,"line":569},[124,1158,870],{"class":170},[124,1160,1161],{"class":126,"line":621},[124,1162,347],{"emptyLinePlaceholder":346},[124,1164,1165],{"class":126,"line":684},[124,1166,131],{"class":130},[124,1168,1169],{"class":126,"line":710},[124,1170,1171],{"class":130}," * CSVファイルを読み込み、行番号付きのデータに変換する。\n",[124,1173,1174],{"class":126,"line":715},[124,1175,1176],{"class":130}," * 行番号はヘッダーを1行目として数える。\n",[124,1178,1179],{"class":126,"line":732},[124,1180,149],{"class":130},[124,1182,1183,1185,1187,1189,1191,1193,1195,1197,1199,1201,1203,1205,1207,1210,1213,1215,1217],{"class":126,"line":738},[124,1184,156],{"class":155},[124,1186,995],{"class":159},[124,1188,164],{"class":163},[124,1190,167],{"class":155},[124,1192,171],{"class":170},[124,1194,175],{"class":174},[124,1196,178],{"class":163},[124,1198,182],{"class":181},[124,1200,185],{"class":170},[124,1202,178],{"class":163},[124,1204,190],{"class":181},[124,1206,193],{"class":170},[124,1208,1209],{"class":181},"CsvRow",[124,1211,1212],{"class":227},"[]",[124,1214,199],{"class":170},[124,1216,202],{"class":155},[124,1218,205],{"class":170},[124,1220,1221,1223,1226,1229,1232,1234,1236,1238,1240,1242,1244,1246,1248,1250,1252,1254,1256,1258,1260],{"class":126,"line":743},[124,1222,211],{"class":155},[124,1224,1225],{"class":170}," [,",[124,1227,1228],{"class":163}," ...",[124,1230,1231],{"class":214},"lines",[124,1233,372],{"class":170},[124,1235,164],{"class":163},[124,1237,171],{"class":220},[124,1239,224],{"class":223},[124,1241,228],{"class":227},[124,1243,231],{"class":170},[124,1245,235],{"class":234},[124,1247,238],{"class":220},[124,1249,231],{"class":170},[124,1251,243],{"class":234},[124,1253,246],{"class":220},[124,1255,250],{"class":249},[124,1257,254],{"class":253},[124,1259,250],{"class":249},[124,1261,272],{"class":220},[124,1263,1264],{"class":126,"line":788},[124,1265,347],{"emptyLinePlaceholder":346},[124,1267,1268,1270,1272,1274,1277,1279,1281,1283,1285,1287,1289,1291],{"class":126,"line":793},[124,1269,840],{"class":223},[124,1271,215],{"class":227},[124,1273,231],{"class":170},[124,1275,1276],{"class":234},"map",[124,1278,246],{"class":220},[124,1280,246],{"class":170},[124,1282,126],{"class":174},[124,1284,366],{"class":170},[124,1286,438],{"class":174},[124,1288,185],{"class":170},[124,1290,202],{"class":155},[124,1292,205],{"class":170},[124,1294,1295,1297,1299,1301,1303,1305,1307,1309,1311,1313,1315,1317,1319,1321,1323],{"class":126,"line":837},[124,1296,394],{"class":155},[124,1298,360],{"class":170},[124,1300,399],{"class":214},[124,1302,366],{"class":170},[124,1304,404],{"class":214},[124,1306,372],{"class":170},[124,1308,164],{"class":163},[124,1310,369],{"class":227},[124,1312,231],{"class":170},[124,1314,243],{"class":234},[124,1316,246],{"class":220},[124,1318,250],{"class":249},[124,1320,366],{"class":421},[124,1322,250],{"class":249},[124,1324,272],{"class":220},[124,1326,1327,1329,1331,1333,1335,1337,1339,1342,1344,1346,1348,1350],{"class":126,"line":867},[124,1328,1073],{"class":223},[124,1330,769],{"class":170},[124,1332,433],{"class":220},[124,1334,178],{"class":170},[124,1336,438],{"class":227},[124,1338,441],{"class":163},[124,1340,1341],{"class":268}," 2",[124,1343,366],{"class":170},[124,1345,699],{"class":227},[124,1347,366],{"class":170},[124,1349,404],{"class":227},[124,1351,785],{"class":170},[124,1353,1355,1358],{"class":126,"line":1354},29,[124,1356,1357],{"class":170},"  }",[124,1359,272],{"class":220},[124,1361,1363],{"class":126,"line":1362},30,[124,1364,870],{"class":170},[124,1366,1368],{"class":126,"line":1367},31,[124,1369,347],{"emptyLinePlaceholder":346},[124,1371,1373],{"class":126,"line":1372},32,[124,1374,131],{"class":130},[124,1376,1378],{"class":126,"line":1377},33,[124,1379,1380],{"class":130}," * CSVに含まれるメールアドレスのうち、登録済みのものを返す。\n",[124,1382,1384],{"class":126,"line":1383},34,[124,1385,149],{"class":130},[124,1387,1389,1391,1393,1395,1397,1399,1401,1403,1406,1408,1410,1412,1414,1416,1419,1421,1423,1426,1428],{"class":126,"line":1388},35,[124,1390,156],{"class":155},[124,1392,1015],{"class":159},[124,1394,164],{"class":163},[124,1396,167],{"class":155},[124,1398,171],{"class":170},[124,1400,1020],{"class":174},[124,1402,178],{"class":163},[124,1404,1405],{"class":181}," CsvRow",[124,1407,1212],{"class":227},[124,1409,185],{"class":170},[124,1411,178],{"class":163},[124,1413,190],{"class":181},[124,1415,193],{"class":170},[124,1417,1418],{"class":181},"Set",[124,1420,193],{"class":170},[124,1422,294],{"class":293},[124,1424,1425],{"class":170},">>",[124,1427,202],{"class":155},[124,1429,205],{"class":170},[124,1431,1433,1435,1438,1440,1442,1444,1446,1448,1451,1453,1456,1458,1460,1462,1464,1467,1469,1472],{"class":126,"line":1432},36,[124,1434,211],{"class":155},[124,1436,1437],{"class":214}," emails",[124,1439,164],{"class":163},[124,1441,987],{"class":227},[124,1443,231],{"class":170},[124,1445,1276],{"class":234},[124,1447,246],{"class":220},[124,1449,1450],{"class":170},"({",[124,1452,404],{"class":174},[124,1454,1455],{"class":170}," })",[124,1457,202],{"class":155},[124,1459,404],{"class":227},[124,1461,185],{"class":220},[124,1463,231],{"class":170},[124,1465,1466],{"class":234},"filter",[124,1468,246],{"class":220},[124,1470,1471],{"class":227},"Boolean",[124,1473,272],{"class":220},[124,1475,1477,1479,1481,1483,1485,1487,1489,1491,1493,1496,1498,1500,1502,1504,1506,1509,1511,1513,1515,1517],{"class":126,"line":1476},37,[124,1478,211],{"class":155},[124,1480,329],{"class":214},[124,1482,164],{"class":163},[124,1484,992],{"class":223},[124,1486,632],{"class":227},[124,1488,231],{"class":170},[124,1490,637],{"class":227},[124,1492,231],{"class":170},[124,1494,1495],{"class":234},"findMany",[124,1497,246],{"class":220},[124,1499,487],{"class":170},[124,1501,404],{"class":220},[124,1503,178],{"class":170},[124,1505,769],{"class":170},[124,1507,1508],{"class":220}," in",[124,1510,178],{"class":170},[124,1512,1437],{"class":227},[124,1514,507],{"class":170},[124,1516,507],{"class":170},[124,1518,272],{"class":220},[124,1520,1522],{"class":126,"line":1521},38,[124,1523,347],{"emptyLinePlaceholder":346},[124,1525,1527,1529,1531,1533,1535,1537,1539,1541,1543,1545,1547,1549,1551,1553],{"class":126,"line":1526},39,[124,1528,840],{"class":223},[124,1530,285],{"class":163},[124,1532,288],{"class":234},[124,1534,246],{"class":220},[124,1536,831],{"class":227},[124,1538,231],{"class":170},[124,1540,1276],{"class":234},[124,1542,246],{"class":220},[124,1544,1450],{"class":170},[124,1546,404],{"class":174},[124,1548,1455],{"class":170},[124,1550,202],{"class":155},[124,1552,404],{"class":227},[124,1554,834],{"class":220},[124,1556,1558],{"class":126,"line":1557},40,[124,1559,870],{"class":170},[124,1561,1563],{"class":126,"line":1562},41,[124,1564,347],{"emptyLinePlaceholder":346},[124,1566,1568],{"class":126,"line":1567},42,[124,1569,131],{"class":130},[124,1571,1573],{"class":126,"line":1572},43,[124,1574,1575],{"class":130}," * 各行を検証し、エラーがなければ保存するユーザーデータを返す。\n",[124,1577,1579],{"class":126,"line":1578},44,[124,1580,1581],{"class":130}," * 1行につき、最初に見つかったエラーのみを返す。\n",[124,1583,1585],{"class":126,"line":1584},45,[124,1586,149],{"class":130},[124,1588,1590,1592,1594,1596],{"class":126,"line":1589},46,[124,1591,156],{"class":155},[124,1593,1034],{"class":159},[124,1595,164],{"class":163},[124,1597,1598],{"class":227}," (\n",[124,1600,1602,1605,1607,1609,1611],{"class":126,"line":1601},47,[124,1603,1604],{"class":174},"  rows",[124,1606,178],{"class":163},[124,1608,1405],{"class":181},[124,1610,1212],{"class":227},[124,1612,1613],{"class":170},",\n",[124,1615,1617,1620,1622,1624,1626,1628],{"class":126,"line":1616},48,[124,1618,1619],{"class":174},"  registeredEmails",[124,1621,178],{"class":163},[124,1623,288],{"class":181},[124,1625,193],{"class":170},[124,1627,294],{"class":293},[124,1629,1630],{"class":170},">,\n",[124,1632,1634,1636,1638,1641,1643],{"class":126,"line":1633},49,[124,1635,185],{"class":227},[124,1637,178],{"class":163},[124,1639,1640],{"class":181}," ValidationResult",[124,1642,202],{"class":155},[124,1644,205],{"class":170},[124,1646,1648,1650,1652,1654,1656,1658,1660],{"class":126,"line":1647},50,[124,1649,211],{"class":155},[124,1651,307],{"class":214},[124,1653,178],{"class":163},[124,1655,312],{"class":181},[124,1657,315],{"class":220},[124,1659,318],{"class":163},[124,1661,321],{"class":220},[124,1663,1665,1667,1669,1671,1673,1675,1677,1679,1681],{"class":126,"line":1664},51,[124,1666,211],{"class":155},[124,1668,280],{"class":214},[124,1670,164],{"class":163},[124,1672,285],{"class":163},[124,1674,288],{"class":234},[124,1676,193],{"class":170},[124,1678,294],{"class":293},[124,1680,199],{"class":170},[124,1682,299],{"class":220},[124,1684,1686],{"class":126,"line":1685},52,[124,1687,347],{"emptyLinePlaceholder":346},[124,1689,1691,1693,1695,1697,1699,1701,1703,1705,1707,1709,1711,1713,1715,1717],{"class":126,"line":1690},53,[124,1692,353],{"class":223},[124,1694,171],{"class":220},[124,1696,156],{"class":155},[124,1698,769],{"class":170},[124,1700,433],{"class":214},[124,1702,366],{"class":170},[124,1704,699],{"class":214},[124,1706,366],{"class":170},[124,1708,404],{"class":214},[124,1710,507],{"class":170},[124,1712,375],{"class":163},[124,1714,987],{"class":227},[124,1716,474],{"class":220},[124,1718,388],{"class":170},[124,1720,1722,1724,1726,1728,1730,1732,1734,1736,1738],{"class":126,"line":1721},54,[124,1723,455],{"class":223},[124,1725,171],{"class":220},[124,1727,460],{"class":163},[124,1729,399],{"class":227},[124,1731,465],{"class":163},[124,1733,468],{"class":163},[124,1735,471],{"class":227},[124,1737,474],{"class":220},[124,1739,388],{"class":170},[124,1741,1743,1746,1748,1750,1752,1754,1756,1758,1760,1762,1764,1766,1768,1770],{"class":126,"line":1742},55,[124,1744,1745],{"class":227},"      errors",[124,1747,231],{"class":170},[124,1749,482],{"class":234},[124,1751,246],{"class":220},[124,1753,487],{"class":170},[124,1755,433],{"class":227},[124,1757,366],{"class":170},[124,1759,494],{"class":220},[124,1761,178],{"class":170},[124,1763,499],{"class":249},[124,1765,502],{"class":421},[124,1767,250],{"class":249},[124,1769,507],{"class":170},[124,1771,272],{"class":220},[124,1773,1775],{"class":126,"line":1774},56,[124,1776,1777],{"class":223},"      continue\n",[124,1779,1781],{"class":126,"line":1780},57,[124,1782,1783],{"class":170},"    }\n",[124,1785,1787,1789,1791,1793,1795,1797,1799,1801,1803,1805],{"class":126,"line":1786},58,[124,1788,455],{"class":223},[124,1790,171],{"class":220},[124,1792,460],{"class":163},[124,1794,525],{"class":214},[124,1796,231],{"class":170},[124,1798,530],{"class":234},[124,1800,246],{"class":220},[124,1802,471],{"class":227},[124,1804,537],{"class":220},[124,1806,388],{"class":170},[124,1808,1810,1812,1814,1816,1818,1820,1822,1824,1826,1828,1830,1832,1834,1836],{"class":126,"line":1809},59,[124,1811,1745],{"class":227},[124,1813,231],{"class":170},[124,1815,482],{"class":234},[124,1817,246],{"class":220},[124,1819,487],{"class":170},[124,1821,433],{"class":227},[124,1823,366],{"class":170},[124,1825,494],{"class":220},[124,1827,178],{"class":170},[124,1829,499],{"class":249},[124,1831,560],{"class":421},[124,1833,250],{"class":249},[124,1835,507],{"class":170},[124,1837,272],{"class":220},[124,1839,1841],{"class":126,"line":1840},60,[124,1842,1777],{"class":223},[124,1844,1846],{"class":126,"line":1845},61,[124,1847,1783],{"class":170},[124,1849,1851,1853,1855,1857,1859,1861,1863,1865,1867],{"class":126,"line":1850},62,[124,1852,455],{"class":223},[124,1854,171],{"class":220},[124,1856,578],{"class":227},[124,1858,231],{"class":170},[124,1860,583],{"class":234},[124,1862,246],{"class":220},[124,1864,471],{"class":227},[124,1866,537],{"class":220},[124,1868,388],{"class":170},[124,1870,1872,1874,1876,1878,1880,1882,1884,1886,1888,1890,1892,1894,1896,1898],{"class":126,"line":1871},63,[124,1873,1745],{"class":227},[124,1875,231],{"class":170},[124,1877,482],{"class":234},[124,1879,246],{"class":220},[124,1881,487],{"class":170},[124,1883,433],{"class":227},[124,1885,366],{"class":170},[124,1887,494],{"class":220},[124,1889,178],{"class":170},[124,1891,499],{"class":249},[124,1893,612],{"class":421},[124,1895,250],{"class":249},[124,1897,507],{"class":170},[124,1899,272],{"class":220},[124,1901,1903],{"class":126,"line":1902},64,[124,1904,1777],{"class":223},[124,1906,1908],{"class":126,"line":1907},65,[124,1909,1783],{"class":170},[124,1911,1913,1915,1917,1919,1921,1923],{"class":126,"line":1912},66,[124,1914,718],{"class":227},[124,1916,231],{"class":170},[124,1918,723],{"class":234},[124,1920,246],{"class":220},[124,1922,471],{"class":227},[124,1924,272],{"class":220},[124,1926,1928],{"class":126,"line":1927},67,[124,1929,347],{"emptyLinePlaceholder":346},[124,1931,1933,1935,1937,1940,1942,1944,1946,1948,1950],{"class":126,"line":1932},68,[124,1934,455],{"class":223},[124,1936,171],{"class":220},[124,1938,1939],{"class":227},"registeredEmails",[124,1941,231],{"class":170},[124,1943,583],{"class":234},[124,1945,246],{"class":220},[124,1947,471],{"class":227},[124,1949,537],{"class":220},[124,1951,388],{"class":170},[124,1953,1955,1957,1959,1961,1963,1965,1967,1969,1971,1973,1975,1977,1979,1981],{"class":126,"line":1954},69,[124,1956,1745],{"class":227},[124,1958,231],{"class":170},[124,1960,482],{"class":234},[124,1962,246],{"class":220},[124,1964,487],{"class":170},[124,1966,433],{"class":227},[124,1968,366],{"class":170},[124,1970,494],{"class":220},[124,1972,178],{"class":170},[124,1974,499],{"class":249},[124,1976,675],{"class":421},[124,1978,250],{"class":249},[124,1980,507],{"class":170},[124,1982,272],{"class":220},[124,1984,1986],{"class":126,"line":1985},70,[124,1987,1783],{"class":170},[124,1989,1991],{"class":126,"line":1990},71,[124,1992,735],{"class":170},[124,1994,1996],{"class":126,"line":1995},72,[124,1997,347],{"emptyLinePlaceholder":346},[124,1999,2001,2003,2005,2007,2009,2011,2013,2015,2017],{"class":126,"line":2000},73,[124,2002,746],{"class":223},[124,2004,171],{"class":220},[124,2006,477],{"class":227},[124,2008,231],{"class":170},[124,2010,755],{"class":214},[124,2012,758],{"class":163},[124,2014,761],{"class":268},[124,2016,474],{"class":220},[124,2018,388],{"class":170},[124,2020,2022,2024,2026,2028,2030,2032,2034,2036],{"class":126,"line":2021},74,[124,2023,1073],{"class":223},[124,2025,769],{"class":170},[124,2027,772],{"class":220},[124,2029,178],{"class":170},[124,2031,778],{"class":777},[124,2033,366],{"class":170},[124,2035,307],{"class":227},[124,2037,785],{"class":170},[124,2039,2041],{"class":126,"line":2040},75,[124,2042,735],{"class":170},[124,2044,2046],{"class":126,"line":2045},76,[124,2047,347],{"emptyLinePlaceholder":346},[124,2049,2051,2053,2055,2057,2059,2061,2063,2065,2067,2069,2071,2073,2075,2077,2079,2081,2083,2085,2087,2089,2091,2093,2095,2097,2099,2101],{"class":126,"line":2050},77,[124,2052,840],{"class":223},[124,2054,769],{"class":170},[124,2056,772],{"class":220},[124,2058,178],{"class":170},[124,2060,849],{"class":777},[124,2062,366],{"class":170},[124,2064,329],{"class":220},[124,2066,178],{"class":170},[124,2068,987],{"class":227},[124,2070,231],{"class":170},[124,2072,1276],{"class":234},[124,2074,246],{"class":220},[124,2076,1450],{"class":170},[124,2078,699],{"class":174},[124,2080,366],{"class":170},[124,2082,404],{"class":174},[124,2084,1455],{"class":170},[124,2086,202],{"class":155},[124,2088,171],{"class":220},[124,2090,487],{"class":170},[124,2092,699],{"class":227},[124,2094,366],{"class":170},[124,2096,404],{"class":227},[124,2098,507],{"class":170},[124,2100,537],{"class":220},[124,2102,870],{"class":170},[124,2104,2106],{"class":126,"line":2105},78,[124,2107,870],{"class":170},[124,2109,2111],{"class":126,"line":2110},79,[124,2112,347],{"emptyLinePlaceholder":346},[124,2114,2116],{"class":126,"line":2115},80,[124,2117,131],{"class":130},[124,2119,2121],{"class":126,"line":2120},81,[124,2122,2123],{"class":130}," * トランザクション内でユーザーをまとめて保存する。\n",[124,2125,2127],{"class":126,"line":2126},82,[124,2128,149],{"class":130},[124,2130,2132,2134,2136,2138,2140,2142,2144,2146,2148,2150,2152,2154,2156,2158,2161,2163,2165],{"class":126,"line":2131},83,[124,2133,156],{"class":155},[124,2135,1110],{"class":159},[124,2137,164],{"class":163},[124,2139,167],{"class":155},[124,2141,171],{"class":170},[124,2143,831],{"class":174},[124,2145,178],{"class":163},[124,2147,334],{"class":181},[124,2149,1212],{"class":227},[124,2151,185],{"class":170},[124,2153,178],{"class":163},[124,2155,190],{"class":181},[124,2157,193],{"class":170},[124,2159,2160],{"class":293},"void",[124,2162,199],{"class":170},[124,2164,202],{"class":155},[124,2166,205],{"class":170},[124,2168,2170,2172,2174,2176,2178,2180,2182,2184,2186,2188,2190,2192,2194,2196,2198,2200,2202],{"class":126,"line":2169},84,[124,2171,796],{"class":223},[124,2173,632],{"class":227},[124,2175,231],{"class":170},[124,2177,803],{"class":234},[124,2179,246],{"class":220},[124,2181,246],{"class":170},[124,2183,810],{"class":174},[124,2185,185],{"class":170},[124,2187,202],{"class":155},[124,2189,817],{"class":227},[124,2191,231],{"class":170},[124,2193,637],{"class":227},[124,2195,231],{"class":170},[124,2197,826],{"class":234},[124,2199,246],{"class":220},[124,2201,831],{"class":227},[124,2203,834],{"class":220},[124,2205,2207],{"class":126,"line":2206},85,[124,2208,870],{"class":170},[10,2210,2211],{},"コードの量は増えました。分割前に挙げたわかりにくさが、それぞれどう変わったかを見ていきましょう。",[38,2213,2214,2221,2228,2241],{},[41,2215,2216,2217,2220],{},"行番号の計算は、",[121,2218,2219],{},"readUserCsv"," の中だけで完結する",[41,2222,2223,2224,2227],{},"形式チェックを通過したメールアドレスだけを重複チェックの対象にしている、と ",[121,2225,2226],{},"validateUsers"," を読めば分かる",[41,2229,2230,2231,2234,2235,2237,2238,2240],{},"DBへの問い合わせは ",[121,2232,2233],{},"findRegisteredEmails"," で1回だけ行う。",[121,2236,2226],{}," はDBに触れないので、配列と ",[121,2239,1418],{}," を渡すだけで検証ルールをテストできる",[41,2242,2243,2244,2246,2247,2250],{},"ループの中で積み上げるのは ",[121,2245,477],{}," だけになった。ユーザーデータを作らなくなったので、",[121,2248,2249],{},"continue"," が「1行につき最初のエラーのみを返す」という意図として読める",[10,2252,2253],{},"共通して言えることは、それぞれを確かめるために読む場所が1か所に絞られたということです。",[33,2255,2257],{"id":2256},"シンプルさは同時に考えることの数で捉える","シンプルさは「同時に考えることの数」で捉える",[10,2259,2260,2261,2264],{},"2つの ",[121,2262,2263],{},"importUsers"," は振る舞いこそ同じですが、読むときに一度に考えなければならないことの量は違います。",[10,2266,2267,2268,2270],{},"分割前の ",[121,2269,2263],{}," は20行ほどの小さな関数でしたが、読み込み・検証・DBへの問い合わせ・保存という別々の責務が混ざっていました。異なる関心事が絡み合った関数は、どんなに小さくてもシンプルとは言えません。",[10,2272,2273,2274,2276,2277,2279,2280,2282],{},"分割後の ",[121,2275,2263],{}," を読むと、「読み込む → 登録済みを調べる → 検証する → 保存する」という流れだけが分かり、それぞれの中身は一段下の関数に任されています。ユーザーを登録したいだけの人は ",[121,2278,2263],{}," だけを読めばよく、検証のルールの詳細について関心のある人は ",[121,2281,2226],{}," だけを読めば済みます。どちらも、関心のない段階のことは考えなくて済みます。",[10,2284,2285],{},"シンプルさを測るものさしは、コードの大きさではなく、同時に考えなければならないことの数です。",[33,2287,2289],{"id":2288},"まとめる削るではなく分ける名前を付ける境界を作る","「まとめる・削る」ではなく、「分ける・名前を付ける・境界を作る」",[10,2291,2292,2293,2295],{},"大抵のコードは、最初から複雑なわけではありません。目まぐるしく変化する業務要件に、手っ取り早く応えようとして既存のコードに足し続けた結果、やがて複雑さが生まれます。分割前の ",[121,2294,2263],{}," も、最初は読み込みと保存だけの関数だったかもしれません。",[10,2297,2298,2299],{},"境界は最初に一度決めて終わりではなく、改修のたびに意識し続けなければいけません。条件を1つ足すときに、それが今の関数の責務なのか、別に分けるべきものなのかを考える必要があります。まとめたり削ったりするより、分けて、名前を付けて、境界を作る方が、シンプルさを保てます。",[28,2300,2301],{},"これは関数に限らず、API設計やDB設計、UI設計においても同様です。",[33,2303,2305],{"id":2304},"ai-時代にシンプルさは必要なのか","AI 時代にシンプルさは必要なのか？",[10,2307,2308],{},"AI は複雑なコードをすぐに理解してくれます。そして、理解した内容を人間にわかりやすく説明してくれます。そんな現代にシンプルなコードを書く理由などあるのでしょうか？",[10,2310,2311],{},"確かに、コードの読み書きで AI に任せられる場面は増えました。しかし、AI が読み書きできることと、人間がそのコードに責任を持てることは別の話です。最終的にそのコードの品質に責任を持つのは実装者であり、開発チームです。さらに画面の向こうには、そのソフトウェアの品質を信頼している無数のユーザーがいます。",[10,2313,2314],{},"AI がどれだけコードを書き、レビューできるようになっても、そのコードに責任を持ち、信頼するのは（今のところは）人間なのです。",[10,2316,2317],{},"そして、",[2319,2320,2321,2329],"blockquote",{},[10,2322,2323,2324,2326,2327],{},"Simplicity is a prerequisite for reliability.",[24,2325],{},"\n信頼性には、シンプルさが不可欠である。",[24,2328],{},[10,2330,2336],{"className":2331},[2332,2333,2334,2335],"text-right","text-xs","italic","opacity-80","― Edsger W. Dijkstra",[33,2338,2339],{"id":2339},"参考文献",[14,2341],{"url":2342},"https://jyn.dev/simple-is-not-the-same-as-small/",[14,2344],{"url":2345},"https://www.infoq.com/presentations/Simple-Made-Easy/",[14,2347],{"url":2348},"https://news.ycombinator.com/item?id=49558685",[2350,2351,2352],"style",{},"html pre.shiki code .sZPSj, html code.shiki .sZPSj{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#BDC4CC;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sGRfs, html code.shiki .sGRfs{--shiki-light:#9C3EDA;--shiki-default:#FF9492;--shiki-dark:#F97583}html pre.shiki code .s8Xov, html code.shiki .s8Xov{--shiki-light:#90A4AE;--shiki-default:#DBB7FF;--shiki-dark:#B392F0}html pre.shiki code .sUBcA, html code.shiki .sUBcA{--shiki-light:#39ADB5;--shiki-default:#FF9492;--shiki-dark:#F97583}html pre.shiki code .seLpV, html code.shiki .seLpV{--shiki-light:#39ADB5;--shiki-default:#F0F3F6;--shiki-dark:#E1E4E8}html pre.shiki code .senS2, html code.shiki .senS2{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#FFB757;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sywW5, html code.shiki .sywW5{--shiki-light:#E2931D;--shiki-default:#FFB757;--shiki-dark:#B392F0}html pre.shiki code .sSuNx, html code.shiki .sSuNx{--shiki-light:#90A4AE;--shiki-default:#91CBFF;--shiki-dark:#79B8FF}html pre.shiki code .sLCpo, html code.shiki .sLCpo{--shiki-light:#E53935;--shiki-default:#F0F3F6;--shiki-dark:#E1E4E8}html pre.shiki code .stP2V, html code.shiki .stP2V{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#FF9492;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sdyPO, html code.shiki .sdyPO{--shiki-light:#90A4AE;--shiki-default:#F0F3F6;--shiki-dark:#E1E4E8}html pre.shiki code .s7KVs, html code.shiki .s7KVs{--shiki-light:#6182B8;--shiki-default:#DBB7FF;--shiki-dark:#B392F0}html pre.shiki code .sPUPB, html code.shiki .sPUPB{--shiki-light:#39ADB5;--shiki-default:#ADDCFF;--shiki-dark:#9ECBFF}html pre.shiki code .sGBsI, html code.shiki .sGBsI{--shiki-light:#90A4AE;--shiki-default:#FF9492;--shiki-dark:#79B8FF}html pre.shiki code .sFHE5, html code.shiki .sFHE5{--shiki-light:#F76D47;--shiki-default:#91CBFF;--shiki-dark:#79B8FF}html pre.shiki code .snYqn, html code.shiki .snYqn{--shiki-light:#E2931D;--shiki-default:#91CBFF;--shiki-dark:#79B8FF}html pre.shiki code .sSIes, html code.shiki .sSIes{--shiki-light:#91B859;--shiki-default:#ADDCFF;--shiki-dark:#9ECBFF}html pre.shiki code .sBxIE, html code.shiki .sBxIE{--shiki-light:#FF5370;--shiki-default:#91CBFF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":119,"searchDepth":140,"depth":140,"links":2354},[2355,2356,2357,2361,2362,2363,2364],{"id":35,"depth":134,"text":36},{"id":58,"depth":134,"text":59},{"id":98,"depth":134,"text":99,"children":2358},[2359,2360],{"id":109,"depth":140,"text":109},{"id":922,"depth":140,"text":922},{"id":2256,"depth":134,"text":2257},{"id":2288,"depth":134,"text":2289},{"id":2304,"depth":134,"text":2305},{"id":2339,"depth":134,"text":2339},"2026-10-26T00:00:00.000Z","シンプルとは、小さいことではなく、分けて考えられること。","md","/avatar_gray_xlafck.webp",{},"https://res.cloudinary.com/dyoyv8djx/image/upload/v1792946978/tsukiyama-blog/small-is-not-simple/small-is-not-simple_u0btqy.webp","/tech/small-is-not-simple","2026-10-26T08:00:00.000Z",{"title":5,"description":2366},"tech/small-is-not-simple",[2376,2377],"ソフトウェア設計","リファクタリング",null,"v9_tcA1rznF2FVR2CBEdBGnAi9etuHQmi6_CLKpy--I",{"title":2381,"image":2382,"description":2383},"シンプリシティ","https://www.oreilly.co.jp/books/images/picture_large978-4-8144-0171-0.jpeg","ソフトウェア開発は本質的に複雑ですが、私たちが自らその複雑さを助長していることも少なくありません。本書は、そうした不要な複雑さを見極め、開発プロセスやコード、そしてあなた自身の働き方をよりシンプルに、より人間的に、そしてより効果的にするアプローチを解説した一冊です。\n紹介する29のプラクティスは、組織を変える壮大な処方箋ではなく、読者一人ひとりが現在の環境に合わせて小さく試し、学び、調整していけるものです。自分のコードを少しわかりやすくすること、依存関係を減らすこと、不要な手順や儀式をやめること、仕事の進め方を少し軽くすること。本書ではそうした実践を通じて、開発者自身が状況や環境をコントロールしていく方法を学びます。\n大きな変化は、一人ひとりの日々の小さな選択から始まります。本書は、その選択を支える視点を与えてくれる、現場開発者のための心強いガイドです。",{"title":2385,"image":119,"description":119},"simple is not smallmenugithub logoLinkedIn logo",{"title":2387,"image":2388,"description":2389},"Simple Made Easy ","https://res.infoq.com/presentations/Simple-Made-Easy/en/mediumimage/rich-hickey-big.jpg","Rich Hickey emphasizes simplicity’s virtues over easiness’, showing that while many choose easiness they may end up with complexity, and the better way is to choose easiness along the simplicity path.",{"title":2391,"image":119,"description":119},"Simple Is Not Small | Hacker News"]