[{"data":1,"prerenderedAt":1130},["ShallowReactive",2],{"content:\u002Fja\u002Ffiddling\u002Fchitchat-about-programming-language":3,"series:content_ja":412},{"id":4,"title":5,"authorship":6,"body":7,"categories":383,"date":385,"description":386,"draft":387,"extension":388,"image":389,"meta":390,"navigation":392,"path":393,"permalink":394,"published":394,"readingTime":395,"recommend":400,"references":394,"seo":401,"seoDescription":402,"seoTitle":403,"sitemap":404,"stem":405,"tags":406,"type":410,"__hash__":411},"content_ja\u002Fposts\u002Ffiddling\u002Fchitchat-about-programming-language.md","プログラミング言語についての雑談","human-only",{"type":8,"value":9,"toc":370},"minimark",[10,14,19,22,25,28,31,34,38,41,47,50,53,56,59,62,65,73,83,86,89,92,95,98,108,111,114,125,128,133,136,139,145,148,155,160,163,169,184,187,194,203,206,209,214,217,220,223,226,229,233,236,255,261,264,267,270,276,279,282,286,289,292,295,298,306,309,312,315,318,333,352,355,358,361,364,367],[11,12,13],"p",{},"この記事では、プログラミング言語をどう設計するかを話しながら、言語理論の基本概念、実装の考え方、現状を紹介します。",[15,16,18],"h3",{"id":17},"自分で言語を設計するんですか","自分で言語を設計……するんですか？",[11,20,21],{},"これから新しいプログラミング言語、C--を設計します。",[11,23,24],{},"そう、私たち自身でです。",[11,26,27],{},"コンパイラ理論やコンパイラ・インタープリターの実装といった複雑な話は、ひとまず置いておきます。個々の機能の具体的な実装にも踏み込みません。タイトルを見てください、雑談です！",[11,29,30],{},"自分たちの言語を、下から積み上げていきましょう。",[11,32,33],{},"最下層は仮定してしまいます。最終的なコンパイル結果はRISC-VI形式で、対応するRISC-VI命令セットがあるものとします。このアセンブリ言語はとても基本的で、メモリとレジスターの簡単な操作しかできません。",[15,35,37],{"id":36},"コードはどこで動く","コードはどこで動く？",[11,39,40],{},"これはRISC-VIの命令セットやアーキテクチャの問題で、設計したい高級言語の機能とは無関係に見えます。しかし、コードがシステムのどの階層にいるかという、言語設計者が最初に考えるべき問題です。",[42,43,44],"blockquote",{},[11,45,46],{},"コンピューターシステムの本質は、階層化された仮想マシンです。",[11,48,49],{},"このモデルでは、上位層が下位層の操作インターフェースを包んで隠し、独自の機能を加えて、さらに上の層へ提供します。",[11,51,52],{},"OSはハードウェア、つまりベアメタルを仮想化する層です。たとえばx86のPCで小さなCプログラムをコンパイルして実行すると、OSはまずバイナリ形式を解析します。Linuxなら実行ファイルはELFです。解析後、各セグメントをメモリへロードし、コードセグメントの最初の命令へ飛んで実行します。もちろん実際はもっと複雑で、OSはメモリを細かく管理し、プロセスなどで実行中のタスクを分離します。",[11,54,55],{},"偶然にも（？）、Cのコンパイル結果はOS上だけでなく、ベアメタルでも動きます。典型例はLinuxカーネルで、大半がCです。最近メインラインにRustも入り、今後が楽しみです。システムプログラミングでは、Cプログラムは主にOSのシステムコールを使います。x86 Linuxでファイルをメモリへ読むなら、通常sys_readを呼びます。Linuxは権限確認などを行い、代わりに読み込んでくれます。しかしCでOSを書く場合、使えるシステムコールはありません。ファイル自体がOSの抽象概念です。ある位置のデータを読むだけでも、ディスクのハードウェアと直接やり取りし、コントローラーのレジスターを変更する必要があります。",[11,57,58],{},"こう見るとOSは先ほどの仮想マシンの定義にぴったり当てはまります。LinuxはELFを実行するVMとも言えます。もちろんそれ以上のこともしますが。OSが提供するC標準ライブラリを除けば、Cはベアメタルの層で動く言語です。正確にはコンパイル結果がそこで動くのですが、ひとまずそう呼びましょう。",[11,60,61],{},"別の例🌰としてPythonを見ます。典型的なインタープリター型言語で、公式実装のCPythonはCで書かれています。階層モデルで言えば、CPythonはOS上のVMです。OSのインターフェースを包み、上のPythonプログラムから呼べるようにします。",[11,63,64],{},"極端に言えば、Cのようなコンパイル型言語も無理やりインタープリター型と見なせます。CPUは実際に命令を1つずつ読んで解析・実行していて、それがバイナリなだけです。一方Pythonの命令は読める文字列で、CPythonの入力は人間が読めるテキストです。",[11,66,67,68,72],{},"インタープリター型の大きな利点は移植性です。OSごとの違いを隠して共通APIを提供するので、",[69,70,71],"strong",{},"一度書けばどこでも動く","わけです。もっとも苦労の総量は保存されるので、利用者が楽をした分、インタープリターの作者が苦労します。ただコンパイル型でも命令セットごとの実装は必要なので、それほど違わないのかもしれません。",[11,74,75,78,79,82],{},[69,76,77],{},"どこでも動く","といえば、有名な",[69,80,81],{},"一度コンパイルすればどこでも動く","Javaです。Javaはコンパイルと解釈を組み合わせます。JVMはPythonのCPythonに相当するランタイムです。javaファイルをまずclassへコンパイルし、JVMはそのclass形式を読みます。バイナリですが、異なる命令セットのOSでも同じ形式です。だからx86で作ったclassがRISC-VのJVMでも動きます。読み込んだ後は、インタープリターのように命令を1つずつ解析・実行します。Javaがコンパイル型かインタープリター型か、単純には決められません。",[11,84,85],{},"JVMはシステムの観点でも成功したVMで、JavaだけでなくScalaやGroovyなども動かせます。重要なのは、これらがすべてclass形式にコンパイルできることです。",[11,87,88],{},"一般にはインタープリター型は遅く、コンパイル型は速いと考えます。しかし発展とともに、前者にも実行効率を上げる機能が加わりました。JavaではJVMがclassを解釈する間にホットなコードを分析し、直接機械語へコンパイルします。次回からは再解釈せず、その機械語を実行します。これがJIT（Just-in-time compilation、実行時コンパイル）です。PythonのNumbaもJITで実行を高速化します。",[11,90,91],{},"もちろんCのインタープリターを書けば、Cはインタープリター型だと言ってもいいわけですが……。",[15,93,94],{"id":94},"型システム",[11,96,97],{},"C--が動く場所は決まりましたが、まだ非常に貧弱で、存在していないも同然です。",[99,100,101,105],"ul",{},[102,103,104],"li",{},"コンパイル型で進むなら、RISC-VIは命令セットアーキテクチャで、通常は高級言語とは独立しています。",[102,106,107],{},"インタープリター型で進むなら、RISC-VIと対応するインタープリターを自分たちで設計・実装するかもしれません。",[11,109,110],{},"RISC-VIが操作できるのはメモリとレジスターだけです。その目には、どちらも意味のないバイト列で、下位VMの許す範囲でどのバイトも操作できます。",[11,112,113],{},"型システムがなく、すべての操作がバイト列を直接扱うと仮定します。Cで言えば、型を定義せずvoid *ですべてのバイトを操作するようなものです。アドレス取得、参照先の操作、バイトの読み書きしかできず、アセンブリとほぼ同じです。ヒープに4バイト整数を作り1を代入するなら、次のようになります。C構文ですが、型がなければ本当にアセンブリ同然です。",[115,116,122],"pre",{"className":117,"code":119,"language":120,"meta":121},[118],"language-c","void *intBytes = malloc(4);    \u002F\u002F 堆上分配四字节\n*(intBytes+3) = 0x01;          \u002F\u002F 假设大端序，偏移为 3 处设置为 1\n","c","",[123,124,119],"code",{"__ignoreMap":121},[11,126,127],{},"おなじみのintやfloatはどこへ行ったのでしょう。それが型システムの仕事です。",[42,129,130],{},[11,131,132],{},"型の本質は、あるメモリ領域をどう解釈するかです。",[11,134,135],{},"型システムは無秩序なスタックやヒープを意味のある塊へ分け、型ごとに解釈を与えます。プログラマーにとって最も分かりやすい違いは定義時の構文でしょう。Cのintは通常4バイト整数、doubleはIEEE 754の倍精度浮動小数点です。型によって、コンパイラが生成する実行時コードのバイト操作が変わります。",[11,137,138],{},"型システムがあれば、先ほどの4バイト整数はこう書けます。",[115,140,143],{"className":141,"code":142,"language":120,"meta":121},[118],"int *intBytes = (int *)malloc(4);\n*intBytes = 1;\n",[123,144,142],{"__ignoreMap":121},[11,146,147],{},"intBytesをintへのポインターと宣言したので、参照先は整数として解釈されます。2行目では、1が3番目ではなく0番目のバイトに入る心配をせず、そのまま代入できます。コンパイラはintへのポインターだと分かれば、操作をint向けに調整します。最終的な機械語はやはり3番目のバイトを1にしますが、その処理はコンパイラ任せで、私たちは型を操作すればよいのです。",[11,149,150,151,154],{},"面白いのは、Cがポインターのオフセット計算をコンパイル時に処理することです。ここで",[123,152,153],{"code":153},"intBytes+1","は実際には元のアドレス+4です。intが4バイトだからです。これはCの配列実装の重要な基盤でもあります。",[42,156,157],{},[11,158,159],{},"Cでは、型システムはコンパイル時の機能です。",[11,161,162],{},"構造体の定義も、本質的にはコンパイラへメモリの操作方法を伝えるものです。たとえば次です。",[115,164,167],{"className":165,"code":166,"language":120,"meta":121},[118],"typedef exampleStruct struct {\n\tint a;\n\tint b;\n}\n",[123,168,166],{"__ignoreMap":121},[11,170,171,172,175,176,179,180,183],{},"intが2つなので8バイトを占めます。exampleStructへのポインター",[123,173,174],{"code":174},"esp","を定義すると、そのアドレスから8バイトをexampleStructの構造で解釈するという意味になります。",[123,177,178],{"code":178},"esp.b","や",[123,181,182],{"code":182},"esp->b","でint bを操作するのは、espからオフセット4〜7のバイトをintとして操作することです。",[11,185,186],{},"つまり構造体のフィールド名は、実行時には構造体先頭からのアドレスのずれを示すだけ、と言えます。",[11,188,189,190,193],{},"ポインターを使わず関数内で",[123,191,192],{"code":192},"exampleStruct esp;","と宣言する場合は、スタック上の変数確保に対するコンパイラの特別扱いです。構文糖衣と見てもよいでしょう。というのも、次のことができるからです。",[195,196,197,200],"ol",{},[102,198,199],{},"手動で初期化せず、宣言すれば使えます。実際にはコンパイラがスタックフレーム内の位置を先に決めています。",[102,201,202],{},"寿命を管理する必要がなく、関数終了時に自動解放されます。下向きに伸びるスタックならポインターを上へ動かすだけで、メモリ自体は上書きしません。",[11,204,205],{},"欠点は言うまでもなく、2つ目の利点の裏返しです。関数が戻ると解放されるので、関数の外では使えません。",[11,207,208],{},"Cに比べるとJavaの型システムはかなり制約があります。型情報がオブジェクトのメモリに直接入り、キャストは型ツリーの親子間でしかできません。",[210,211,213],"h4",{"id":212},"値渡しか参照渡しか","値渡しか参照渡しか？",[11,215,216],{},"関数の引数が値渡しか参照渡しかは、よく話題になり、間違えやすいところでもあります。",[11,218,219],{},"根本的にはすべて値渡しと考えられ、いわゆる参照渡しも値渡しに基づく最適化です。",[11,221,222],{},"Cは分かりやすく、レジスターでもスタックでも、元の内容をコピーまたは退避し、呼び出し先から戻った後に変わらないようにします。ポインターもその性質を外して見れば、アーキテクチャに応じた32ビットや64ビットの数値にすぎません。そのアドレスをlongへ代入して渡すのと同じです。",[11,224,225],{},"参照渡しという話は主にJavaで登場します。参照の本質はオブジェクトのハンドルで、それを通じて一部の情報にアクセスします。ハンドル自体はメモリアドレスを表しませんが、実装には実際のアドレスが含まれるはずです。参照を関数やメソッドへ渡すのは、そのアドレスを含む構造体を渡すと見なせます。Cのポインター渡しに似ているので、動作も似ています。",[11,227,228],{},"ただJavaには8つの基本型と、それぞれのラッパークラスもあり、実装の統一感に欠けます。初期にC++プログラマーを呼び込むためだったとも聞きますが、優雅さは失われています。",[15,230,232],{"id":231},"配列とは何か","配列とは何か？",[11,234,235],{},"基本的な型システムができたら、特殊ですがよく使う複合型、配列を考えます。しかし配列とは何で、本当に存在するのでしょうか。",[11,237,238,239,242,243,246,247,250,251,254],{},"Cには実行時の配列はなく、コンパイル時の構文糖衣としてポインターで実装されます。配列名は0番目の要素へのアドレスです。",[123,240,241],{"code":241},"int a[10]","を宣言したとき、aを使うのは",[123,244,245],{"code":245},"&a[0]","と同じです。角括弧の添字演算も型付きポインターのオフセットで、",[123,248,249],{"code":249},"a[1]","は",[123,252,253],{"code":253},"*(a+1)","と考えられます。具体的には次のようになります。",[115,256,259],{"className":257,"code":258,"language":120,"meta":121},[118],"int b = a[0];\n\n\u002F\u002F 等同于\nvoid *p = (void *)a;\np += 4;\nint b = *((int *)p);\n",[123,260,258],{"__ignoreMap":121},[11,262,263],{},"配列が型付きポインターに基づき、対応するポインターと自由に変換できるため、言語は境界検査をしません。スタックに長さ10の配列を作り、11番目を読み書きしても、一見問題が起きないことがあります。",[11,265,266],{},"「範囲外ならセグメンテーション違反になる」と思うかもしれません。しかしそれはCの検査ではありません。範囲外の読み書きで、読めないメモリを読んだり、書けないメモリへ書いたりして、OSがエラーを出すのです。言語レベルのエラーではありません。",[11,268,269],{},"Cで配列を引数にする書き方は、ポインター、サイズ指定ありの配列、サイズ指定なしの配列の3つです。",[115,271,274],{"className":272,"code":273,"language":120,"meta":121},[118],"void func(int *array);\nvoid func(int array[10]);\nvoid func(int array[]);\n",[123,275,273],{"__ignoreMap":121},[11,277,278],{},"1つ目と3つ目では、func内でlenから元の長さを取得できません。2つ目では実引数の長さが10でなくても、得られる長さは常に10です。長さ情報は型定義にあり、引数渡しなどで型が変わると失われることが分かります。実メモリには要素が連続するだけで追加情報がなく、配列がポインターで実装されるという見方とも合います。",[11,280,281],{},"対してJavaには本物の配列があります。各配列はオブジェクトで、要素型や長さなどがヘッダーに保存されます。だから実行時に範囲外アクセスを検出し、IndexOutOfBoundsExceptionを投げられます。",[15,283,285],{"id":284},"手続き型かオブジェクト指向か","手続き型かオブジェクト指向か？",[11,287,288],{},"実は、それほど問題ではありません。広い意味では、両者は言語の違いというより考え方やパラダイムです。Cでも構造体を使えばオブジェクト指向で書けます。",[11,290,291],{},"狭く定義するなら、カプセル化、継承、多態性という3大特徴を標準で完全に実装する言語だけを、オブジェクト指向言語と呼ぶことにします。",[11,293,294],{},"単純なカプセル化ならCでも構造体へまとめるだけです。しかし重要な目的は、内部実装を隠し、外からは提供されたインターフェースでのみデータへアクセス・操作できるようにすることです。Cの構造体にはアクセス制御がなく、フィールドを自由に変更できるので、その意味でのカプセル化には実質的な意味がありません。JavaやC++とCの大きな構文上の違いに、ドット演算子でメンバーメソッドを呼べることがありますが、実装は特別ではありません。メソッドは第1引数がオブジェクトへのポインターである関数で、コンパイラが自動で追加してthisと呼ぶだけです。ほかは普通の関数と同じです。",[11,296,297],{},"Java、C++、Goは、直接または間接的に合成で継承を実装する点が似ています。合成を使うので、独自コンストラクターでは先に親のコンストラクターを呼びます。Goはとくに明確で、構造体の中へ名前のない親構造体を埋め込みます。親フィールドへのアクセスは、実際にはその親オブジェクトのフィールドへの直接アクセスで、構文糖衣に見えます。",[115,299,304],{"className":300,"code":302,"language":303,"meta":121},[301],"language-go","type Parent struct {\n\ta int64\n}\n\ntype Child struct {\n\tParent\n\tb int64\n}\n\nc := &Child{Parent{}, 0}\na := c.a\n\u002F\u002F或者\na := c.Parent.a;\n","go",[123,305,302],{"__ignoreMap":121},[11,307,308],{},"JavaやC++に比べると、Goの継承はおままごとのようです。子から親の変数へのアクセスを特別に制御せず、先頭文字の大文字・小文字によるパッケージ公開規則をそのまま使います。Javaのprotectedのような、親子関係専用の制御がありません。",[11,310,311],{},"多態性の典型例は、親ポインターが異なる子オブジェクトを指し、共通メソッドを呼ぶと子ごとに違う動作をすることです。JavaとC++は2つの代表的な実装です。JavaにはJVMがあるので簡単です。親型のハンドル経由でも、そこから実オブジェクトの型やメソッド情報を調べられ、具体的な実装を呼べます。つまり実行時多態性です。一方C++はコンパイル時多態性です。各クラスに仮想関数テーブルがあり、インスタンスにはそのテーブルへのポインターが入ります。テーブルは継承で上書きされ得るメソッドの一覧です。コンパイラは親子が同じメソッドを実装した場合、両テーブルの同じ位置に置きます。その呼び出しは「仮想関数テーブルのN番目を呼ぶ」という命令になります。親ポインターから呼んでも、実際には子のテーブルから関数ポインターを得るため、子の実装が動き、多態性が実現します。",[15,313,314],{"id":314},"ジェネリクスの実装",[11,316,317],{},"IDEAの補完のおかげで、ジェネリクスは最もよく使われる高度な言語機能の一つでしょう。しかしJavaに入ったのはJDK 5、C++でその実装方法の一つであるテンプレートが導入されたのはC++11で、比較的新しい機能です。面白いことに、この2つはまったく異なる実装方式を代表します。",[11,319,320,321,324,325,328,329,332],{},"Javaのジェネリクスはコンパイル時の機能で、実行時には消えます。いわゆる型消去です。渡すオブジェクトや型が型引数の条件を満たすか、コンパイル時に確認するだけです。classを手作りしたり、実行時のリフレクションなどで検査を回避すれば、JVMにはどうにもできません。通常",[123,322,323],{"code":323},"List\u003CString>","へ入れられるのはStringだけですが、実行時には単なる",[123,326,327],{"code":327},"List","、あるいは",[123,330,331],{"code":331},"List\u003CObject>","です。何らかの方法でIntegerを入れても、JVMはエラーにしません。",[11,334,335,336,339,340,343,344,347,348,351],{},"C++はコード生成で実装するため、テンプレートと呼びます。コンパイラは各インスタンス化箇所の型引数を調べ、引数の組み合わせごとにジェネリッククラスの全メソッドを生成します。たとえば",[123,337,338],{"code":338},"ClassName\u003C typename T >","に",[123,341,342],{"code":342},"Test(T t)","があり、",[123,345,346],{"code":346},"ClassName\u003Cint> testObj","を作れば、コンパイル結果には本当に",[123,349,350],{"code":350},"Test(int t)","が存在します。Javaと同じく実行時にはジェネリクスを意識せず、生成されたクラスやメソッドは手書きと同じです。ただし型消去でなくコード生成なので、コンパイルを回避すれば検査が消えるJavaより、明らかに安全です。",[11,353,354],{},"C++の欠点は、生成されるクラスが完全でなければならず、型引数を使わない関数も、同じコードなのに繰り返し生成されることです。大きな容量の無駄になり得ます。C#はここを最適化しています。コンパイル時に最終コードを直接生成せず、その型の異なる実装が何種類必要かを集計します。.NETランタイムのCLR、JVMのようなものですが、そのJITが共有機械語を作り、型ごとの特化情報を別テーブルとして各ジェネリック型が持ちます。これで大半のコードを共有できます。詳細は論文を参照してください。ただ、C++を責めても仕方ありません。C#にはランタイムがあります。C++も専用ランタイムを持つか、出力へ組み込まなければ、この動的な共有は難しいでしょう。",[15,356,357],{"id":357},"おわりに",[11,359,360],{},"ここまで決めれば、構文さえまだ決めていなくても、言語の大まかな姿は決まっています。残るのはかなり共通した、順を追った作業です。実装しましょう！",[11,362,363],{},"もちろんGCや特殊な寿命管理など、高度な機能はいくらでも加えられます。VMがあると実装は楽ですが、必須ではありません。GoはGCのコードを最終成果物に直接コンパイルし、実行ファイルごとに小さなVMを付けるような形を取ります。",[11,365,366],{},"大半の人は自分で言語を実装する必要はありませんが、共通点や特徴を知ることは大切です。世界最高の言語はなく、ある状況に最も適した言語があるだけです。だから「最強の言語」論争は滑稽です。どの言語も何かの問題を解決するために生まれます。既存言語と構文以外の特徴が同じ新言語は、長続きしにくいでしょう。新しい問題を解決しないなら、わざわざ学ぶ理由がありません。",[11,368,369],{},"こうした特徴を知ると、思わぬ利点もあります。プログラマー同士の飲み会で大きなことを言いたいときや、技術グループでまた根拠を交えた最強言語論争が始まったとき、思う存分語れます。",{"title":121,"searchDepth":371,"depth":371,"links":372},4,[373,375,376,379,380,381,382],{"id":17,"depth":374,"text":18},3,{"id":36,"depth":374,"text":37},{"id":94,"depth":374,"text":94,"children":377},[378],{"id":212,"depth":371,"text":213},{"id":231,"depth":374,"text":232},{"id":284,"depth":374,"text":285},{"id":314,"depth":374,"text":314},{"id":357,"depth":374,"text":357},[384],"fiddling","2023-04-08 13:16:36","新しいプログラミング言語の設計は、難しくも面白い作業です。複雑なコンパイラ理論や機能の実装詳細をいったん脇に置き、コードがコンピューターのどこで動くかに注目すると、言語の作り方が見えてきます。RISC-VI命令セットを出発点に、基盤となる構造、階層化されたシステム、仮想マシンのモデルをたどり、言語の本質を考えます。",false,"md","https:\u002F\u002Fblog-img.774352199.xyz\u002FuO420B.webp",{"slots":391},{},true,"\u002Ffiddling\u002Fchitchat-about-programming-language",null,{"text":396,"minutes":397,"time":398,"words":399},"28 min read",27.03,1621800,5406,2,{"title":5,"description":386},"架空の言語を設計する流れで、コードの実行環境、型、配列、引数渡し、継承、ジェネリクスを考察。CやJava、Goなどの実装を例に、言語機能の仕組みと設計上の選択を説明します。","プログラミング言語設計：型システム、ランタイムと実装",{"loc":393},"posts\u002Ffiddling\u002Fchitchat-about-programming-language",[407,94,408,409],"プログラミング言語設計","コンパイラ設計","RISC-V","tech","Qg7k1PnjDIEbPJMqnK43ZaSh8oSWEOy-X6uXuhKUhtY",[413,431,448,466,483,501,505,523,541,557,574,590,606,622,639,657,672,689,703,720,738,755,770,787,803,822,839,856,874,888,906,924,940,955,969,986,1001,1016,1031,1045,1059,1073,1088,1102,1116],{"categories":414,"date":416,"description":417,"image":418,"path":419,"readingTime":420,"recommend":394,"tags":425,"title":430,"type":410},[415],"daily","2024-09-01 22:03:10","子どもの頃からの胃腸の不調が大学時代には不思議と消えたものの、就職後の夜更かしと飲酒で再発。慢性胃炎との付き合いは一筋縄ではいきませんでした。吐き気や胃のむかつきが日常になり、何度か検査を受けて生活を振り返るうちに、ようやく腰を据えて治療に向き合うようになりました。","https:\u002F\u002Fblog-img.774352199.xyz\u002F0Hr9l5.webp","\u002Fdaily\u002Fanti-chronic-gastritis",{"text":421,"minutes":422,"time":423,"words":424},"7 min read",6.485,389100,1297,[426,427,428,429],"慢性胃炎","受診記録","胃内視鏡検査","健康記録","慢性胃炎の治療記録",{"categories":432,"date":433,"description":434,"image":435,"path":436,"readingTime":437,"recommend":394,"tags":442,"title":447,"type":410},[415],"2022-04-11 00:13:13","『三体』では、劉慈欣が壮大な歴史を通して個人と集団の関係を描いています。西側の民主主義への疑念と、大多数の人々に運命を委ねることへの悲観が、三部作を貫いています。英雄たちが力を尽くしても、その努力は歴史の流れに押し流される。文化大革命から始まる物語に、少数の傑出した人物と平凡な大衆の対立を読み、人間性と社会について考えました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FLTzbFP.webp","\u002Fdaily\u002Fpeople-in-three-body",{"text":438,"minutes":439,"time":440,"words":441},"19 min read",18.495,1109700,3699,[443,444,445,446],"三体","劉慈欣","SF文学","読書ノート","『三体』における「大多数の人々」",{"categories":449,"date":450,"description":451,"image":452,"path":453,"readingTime":454,"recommend":394,"tags":459,"title":465,"type":410},[415],"2024-01-04 02:06:51","2024年の学習目標は、日本語をN2レベルに引き上げること、SICPとTAPLを最後までやり切ること、POSIXを完全に実装したカーネルを作ること、そしてブログのテーマを更新すること。どれも簡単ではありませんが、今年取り組む方向は決まりました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FV3rSQC.webp","\u002Fdaily\u002Fplan2024",{"text":455,"minutes":456,"time":457,"words":458},"1 min read",0.345,20700,69,[460,461,462,463,464],"年間計画","日本語学習","SICP","TAPL","オペレーティングシステム","2024年の学習計画",{"categories":467,"date":468,"description":469,"image":470,"path":471,"readingTime":472,"recommend":394,"tags":477,"title":482,"type":410},[415],"2024-09-28 16:26:00","ByteDanceで働いて3年。変化の速い環境で、時間まで加速したように感じながらも、どうにか心のバランスを保ってきました。杭州のオフィスのベランダから遠くの山を眺めていた入社当初を振り返り、仕事の壁や心境の変化、忙しさの中で自分のペースを探してきた日々を記します。","https:\u002F\u002Fblog-img.774352199.xyz\u002FhnCaht.webp","\u002Fdaily\u002Fwork-for-3-years",{"text":473,"minutes":474,"time":475,"words":476},"20 min read",19.73,1183800,3946,[478,479,480,481],"ByteDance","エンジニアのキャリア","仕事の振り返り","メンタルヘルス","ByteDanceで3年働きながら、ある程度の正気を保つことも不可能ではない",{"categories":484,"date":485,"description":486,"image":487,"path":488,"readingTime":489,"recommend":394,"tags":494,"title":500,"type":410},[384],"2025-05-28 22:09:00","ブログをAstroに移行したところ、従来のGoogle Analytics導入方法では性能面が気になるようになりました。headタグにJavaScriptを直接追加してイベントを送ることはできますが、ページの性能に影響します。そこでpartytownでスクリプトをメインスレッドから切り離し、読み込みを妨げないようにしました。サンプルコードに手を加えることでGoogle Analyticsの導入に成功し、性能とアクセス解析を両立できました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FQ0w4RN.webp","\u002Ffiddling\u002Fastro-google-tag-manager",{"text":490,"minutes":491,"time":492,"words":493},"4 min read",3.455,207300,691,[495,496,497,498,499],"Astro","Google Analytics","Google Tag Manager","Partytown","アクセス解析","AstroにGoogle Analyticsを導入する（Tag Manager編）",{"categories":502,"date":385,"description":386,"image":389,"path":393,"readingTime":503,"recommend":400,"tags":504,"title":5,"type":410},[384],{"text":396,"minutes":397,"time":398,"words":399},[407,94,408,409],{"categories":506,"date":507,"description":508,"image":509,"path":510,"readingTime":511,"recommend":371,"tags":516,"title":522,"type":410},[384],"2025-04-18 16:43:12","彼女が仕事で北京から上海に引っ越したので、回線の手配も手伝いました。ところが上海電信の500Mは杭州の1000Mより高く、なんとも納得がいきません。そこで上海での透過プロキシ、特定の通信の杭州経由での外部接続、両拠点のLAN相互接続を目指してネットワークを組むことにしました。杭州側はソフトウェアルーターと無線APのシンプルな構成で、普段から自宅経由で通信できる環境があり、次の挑戦に向けた準備はできています。","https:\u002F\u002Fblog-img.774352199.xyz\u002FO6cAGh.webp","\u002Ffiddling\u002Fcross-city-network-setup",{"text":512,"minutes":513,"time":514,"words":515},"11 min read",10.14,608400,2028,[517,518,519,520,521],"Tailscale","mihomo","拠点間ネットワーク","透過プロキシ","ホームネットワーク","上海と杭州の自宅ネットワークをつなぐ",{"categories":524,"date":525,"description":526,"image":527,"path":528,"readingTime":529,"recommend":394,"tags":534,"title":540,"type":410},[384],"2021-12-27 00:09:00","CSAPPの学習では実験が欠かせませんが、Linux環境の構築が壁になりがちです。とくに仮想マシンでは、インストール失敗、互換性、ネットワーク接続などの問題に悩まされます。Windows 10バージョン2004以降なら、WSL（Windows Subsystem for Linux）が有力な選択肢です。従来の仮想マシンの複雑さや性能面の負担を避けながら、Linux環境を手軽に利用できます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FvqOC7N.webp","\u002Ffiddling\u002Fcsapplab0",{"text":530,"minutes":531,"time":532,"words":533},"10 min read",9.585,575100,1917,[535,536,537,538,539],"CSAPP","WSL2","Linux","GDB","実験環境","CSAPP Labの環境構築",{"categories":542,"date":543,"description":544,"image":545,"path":546,"readingTime":547,"recommend":394,"tags":552,"title":556,"type":410},[384],"2024-07-13 17:49:00","Debianをサイドルーターに使うと、OpenWrtやLuCIに依存せず、より安定した柔軟な構成を作れます。Debianを直接設定することでシステムを細かく制御でき、GUIの制約や不安定さを避けられます。一般的なサイドルーター構成と比べて透過プロキシを安定して運用しやすく、性能や効率を重視する場合の選択肢になります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FpPRU5x.webp","\u002Ffiddling\u002Fdebian-as-bypass-router",{"text":548,"minutes":549,"time":550,"words":551},"18 min read",17.525,1051500,3505,[553,554,518,555,520],"Debian","サイドルーター","AdGuard Home","Debianをサイドルーターにする",{"categories":558,"date":559,"description":560,"image":561,"path":562,"readingTime":563,"recommend":394,"tags":568,"title":573,"type":410},[384],"2024-08-16 23:53:00","FakeIPを使った透過プロキシ構成で、従来のサイドルーターの単一障害点、性能不足、複雑なポート転送を改善します。プロキシコアをsing-boxに変えることで、転送性能を高めながら設定も簡単にできます。対応プロトコルが豊富で、従来のClashより最適化も進んでいます。同じ構成はClashでも実現できますが、sing-boxは柔軟な選択肢になります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FS2HHD5.webp","\u002Ffiddling\u002Ffake-ip-based-transparent-proxy",{"text":564,"minutes":565,"time":566,"words":567},"14 min read",13.1,786000,2620,[569,570,520,571,572],"FakeIP","sing-box","ポリシーベースルーティング","トラフィック振り分け","FakeIPを使った透過プロキシの振り分け",{"categories":575,"date":576,"description":577,"image":578,"path":579,"readingTime":580,"recommend":394,"tags":585,"title":589,"type":410},[384],"2024-08-15 23:50:00","サイドルーターを導入すると、メインルーターのポート転送が効かなくなることがあります。ゲートウェイをサイドルーターに変えることで通信経路が変わり、メインルーターを前提とした転送が正常に動かなくなるためです。ゲートウェイはアドレスを変換して内部ネットワークの通信を外部へ転送し、各端末は外部との通信にこれを必要とします。この仕組みを理解すると、ポート転送の問題を解決しやすくなります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FmRqws9.webp","\u002Ffiddling\u002Ffix-port-forward-in-bypass-router",{"text":581,"minutes":582,"time":583,"words":584},"6 min read",5.155,309300,1031,[554,586,587,588],"ポート転送","NAT","ネットワークのトラブルシューティング","サイドルーター環境でポート転送が効かない問題を解決する",{"categories":591,"date":592,"description":593,"image":594,"path":595,"readingTime":596,"recommend":394,"tags":601,"title":605,"type":410},[384],"2023-02-02 23:24:55","春節の帰省列車で、Goをベアメタルで動かす記事を読み、低レベルのシステムインターフェースに興味が湧きました。実際に動く実装を見て、高級言語でOSを作る可能性に胸が躍ります。関連研究を調べると先行例も見つかり、積もった熱意は期待に満ちたプロジェクトへと変わりました。しかし、最後は思いどおりにはいきませんでした。","https:\u002F\u002Fblog-img.774352199.xyz\u002FxB1Ni5.webp","\u002Ffiddling\u002Fgo-os",{"text":597,"minutes":598,"time":599,"words":600},"12 min read",11.81,708600,2362,[602,409,464,603,604],"Go","ベアメタルプログラミング","ランタイム","失敗に終わったプロジェクト：楽しくなかった春節の7日間",{"categories":607,"date":608,"description":609,"image":610,"path":611,"readingTime":612,"recommend":394,"tags":617,"title":621,"type":410},[384],"2022-08-15 01:05:01","システムのリファクタリングで、階層ごとのエンティティ変換に苦労しました。ビュー層の商品VO、ドメイン層のentity、永続化層のPOは似ていても、型のわずかな違いで直接変換できず、ディープコピーが面倒になります。そこでリフレクションを使った汎用的な変換処理を実装し、大量のassemblerメソッドを減らして、保守性と柔軟性を高めることにしました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FBlhm0I.webp","\u002Ffiddling\u002Fgolang-deepcopy-between-different-type",{"text":613,"minutes":614,"time":615,"words":616},"5 min read",4.14,248400,828,[602,618,619,620],"リフレクション","ディープコピー","構造体変換","Goで異なる型の構造体をディープコピーする",{"categories":623,"date":624,"description":625,"image":626,"path":627,"readingTime":628,"recommend":394,"tags":632,"title":638,"type":410},[384],"2025-03-31 23:51:00","Appleヘルスケアの心拍数を定期的にサーバーへ同期し、Grafanaで可視化して直感的に確認できるようにしました。Health Auto ExportのREST API機能でHTTPエンドポイントへデータを送り、InfluxDBに保存します。Grafanaのダッシュボードから、自分の心拍数の変化を追ったり分析したりできます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FF4qD2T.webp","\u002Ffiddling\u002Fheart-rate-to-grafana",{"text":490,"minutes":629,"time":630,"words":631},3.76,225600,752,[633,634,635,636,637],"Apple Watch","Health Auto Export","InfluxDB","Grafana","心拍数モニタリング","My Heart Beats for U：心拍数をGrafanaで可視化する",{"categories":640,"date":641,"description":642,"image":643,"path":644,"readingTime":645,"recommend":649,"tags":650,"title":656,"type":410},[384],"2025-06-10 20:18:00","macOSとiPadOS 26では、新しいデザイン言語Liquid Glassが導入され、アイコンやウインドウの印象が一新されました。とくにiPadのアプリをウインドウで扱えるようになったことは、生産性向上のための端末へ進む大きな一歩です。一方、透明なコントロールセンターやLaunchpadの統合には賛否があり、使い勝手には改善の余地もあります。課題はありつつも、今後につながる更新だと感じました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FTPSaLE.webp","\u002Ffiddling\u002Fmacos-26-trial",{"text":421,"minutes":646,"time":647,"words":648},6.94,416400,1388,5,[651,652,653,654,655],"macOS 26","iPadOS 26","Liquid Glass","Apple Intelligence","OS使用感","macOS 26とiPadOS 26を試してみた",{"categories":658,"date":659,"description":660,"image":661,"path":662,"readingTime":663,"recommend":394,"tags":667,"title":671,"type":410},[384],"2026-06-11 10:00:00","今年もWWDCでmacOS 27の新しいApple Intelligenceが登場しました。macOS 26時代の回避方法はもう使えず、引き続きAppleとの知恵比べです。","https:\u002F\u002Fblog-img.774352199.xyz\u002FfOFucm.webp","\u002Ffiddling\u002Fmacos-27-apple-intelligence-chatgpt",{"text":530,"minutes":664,"time":665,"words":666},9.74,584400,1948,[668,654,669,670],"macOS 27","ChatGPT","中国本土向けMac","中国本土向けMacでApple Intelligenceを使う：地域変更からChatGPTの取り出しまで",{"categories":673,"date":674,"description":675,"image":676,"path":677,"readingTime":678,"recommend":394,"tags":682,"title":688,"type":410},[384],"2025-07-20 23:32:00","MoonTVはNext.jsとReactで作った動画集約プラットフォームで、連続ドラマなどを手軽に楽しむためのものです。LibreTVを改善しようとしたことが始まりで、数か月の開発を経て多くの関心と利用を集めています。Cursorのおかげで効率よく開発できた一方、複数環境への対応や複雑なデータ依存関係には苦労しました。ユーザーが増える中、フィードバックを受けて改善を続けています。","https:\u002F\u002Fblog-img.774352199.xyz\u002FnIeONi.webp","\u002Ffiddling\u002Fmoontv-vibe-coding",{"text":512,"minutes":679,"time":680,"words":681},10.98,658800,2196,[683,684,685,686,687],"MoonTV","LunaTV","Vibe Coding","Cursor","AI支援開発","MoonTV：Vibe Codingを試してみた",{"categories":690,"date":691,"description":692,"image":693,"path":694,"readingTime":695,"recommend":394,"tags":699,"title":702,"type":410},[384],"2024-10-07 16:51:00","BGPをもとに中国国内・国外のIPを振り分けることで、透過プロキシの効率と精度を高めます。国外の宛先をFakeIPで識別すれば、メインルーターでより適切に通信を振り分けられます。sing-boxのDNS設定も見直し、DNSクエリを柔軟かつ効率的に処理して、ネットワーク全体の使い勝手を改善します。","https:\u002F\u002Fblog-img.774352199.xyz\u002FMOmM1s.webp","\u002Ffiddling\u002Fmore-accurate-chnroute",{"text":581,"minutes":696,"time":697,"words":698},5.75,345000,1150,[700,701,571,572],"BGP","IPアドレスデータベース","BGPで中国国内・国外IPの振り分けをより正確にする",{"categories":704,"date":705,"description":706,"image":707,"path":708,"readingTime":709,"recommend":394,"tags":714,"title":719,"type":410},[384],"2025-12-14 14:31:00","友人の一言からシミュレーターに興味が湧き、Microsoft Flight Simulatorを購入。地図やモデルはリアルタイム配信、アカウントは再ログインが必要、チュートリアルは見つけにくく、キーボード操作も難しい。結局フライトスティックを買い、Pico VRまで設定してようやく一通り体験できました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FlfhEuE.webp","\u002Ffiddling\u002Fmsfs2024-joystick-and-pico",{"text":710,"minutes":711,"time":712,"words":713},"9 min read",8.96,537600,1792,[715,716,717,718],"Microsoft Flight Simulator 2024","Thrustmaster TCA","PICO VR","フライトシミュレーション","Microsoft Flight Simulator 2024をあれこれ試す",{"categories":721,"date":722,"description":723,"image":724,"path":725,"readingTime":726,"recommend":394,"tags":731,"title":737,"type":410},[384],"2025-06-05 23:26:00","OnePlusからiPhoneへと何度も機種変更するうち、いじる楽しさからエコシステムへの依存へと関心が変わりました。最近、彼女の一言をきっかけに写真を改善しようとOPPO Find X8 Ultraを購入。Apple環境からの移行では、Androidアプリの質のばらつきと代替探しの難しさを改めて感じました。1か月をかけて、異なるプラットフォームの摩擦に折り合いをつけた記録です。","https:\u002F\u002Fblog-img.774352199.xyz\u002F19NIhZ.webp","\u002Ffiddling\u002Fone-month-using-android",{"text":727,"minutes":728,"time":729,"words":730},"15 min read",14.05,843000,2810,[732,733,734,735,736],"Android","OPPO","iOS","スマートフォン使用感","エコシステム移行","Androidに乗り換えて1か月",{"categories":739,"date":740,"description":741,"image":742,"path":743,"readingTime":744,"recommend":394,"tags":748,"title":754,"type":410},[384],"2026-05-11 22:43:00","GitHub Trendingで旅行計画ツールを見つけ、自分でも動かしたくなりました。どうせ新しいVPSを借りるなら、ついでにもう少し、いや、だいぶ色々入れてしまおうと。","https:\u002F\u002Fblog-img.774352199.xyz\u002FBBdDWW.webp","\u002Ffiddling\u002Fone-trek-twenty-stacks",{"text":512,"minutes":745,"time":746,"words":747},10.34,620400,2068,[749,750,751,752,753],"TREK","Docker Compose","Dockge","VPS","セルフホスティング","TREKひとつのつもりが、20個のスタックに",{"categories":756,"date":757,"description":758,"image":759,"path":760,"readingTime":761,"recommend":394,"tags":765,"title":769,"type":410},[384],"2025-01-16 23:09:00","OPNsenseは、美しい画面と充実した機能を備えるオープンソースのファイアウォール・ルーターです。いくつかの構成を試した末に、透過プロキシやトラフィック振り分けでの可能性に気づきました。BGPベースの振り分けと組み合わせることで安全性と安定性を高められ、IPリストの自動更新で管理もしやすくなります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FxA8C1E.webp","\u002Ffiddling\u002Fopnsense-transparent-proxy",{"text":597,"minutes":762,"time":763,"words":764},11.38,682800,2276,[766,767,518,768,520,572],"OPNsense","FreeBSD","tun2socks","OPNsenseで透過プロキシとトラフィック振り分けを実現する",{"categories":771,"date":772,"description":773,"image":774,"path":775,"readingTime":776,"recommend":374,"tags":780,"title":786,"type":410},[384],"2025-03-15 20:35:00","構文解析では、ユーザー定義型名と通常の変数名を見分けることが課題になります。たとえば`a*b;`は算術式とも宣言とも解釈できます。とくに型指定子に関する文法規則によって変数名が型名と解釈され、正確さや読みやすさに影響します。初期化を伴わない変数宣言は多いため、この曖昧さはソースコードの随所に現れます。","https:\u002F\u002Fblog-img.774352199.xyz\u002F2VKHK9.webp","\u002Ffiddling\u002Fparser-type-variable-ambiguity",{"text":564,"minutes":777,"time":778,"words":779},13.58,814800,2716,[781,782,783,784,785],"構文解析","GLR","シンボルテーブル","スコープ","曖昧性解消","構文解析で型名と変数名の曖昧さを解消する",{"categories":788,"date":789,"description":790,"image":791,"path":792,"readingTime":793,"recommend":394,"tags":797,"title":802,"type":410},[384],"2023-05-24 17:51:09","RISC-Vツールチェーンをインストールするには、まずriscv-gnu-toolchainのソースを取得します。clone時に`--depth=1`を付けるとダウンロード量を減らせます。READMEのPrerequisitesを確認し、必要な依存関係をそろえてから進めます。Debianではコマンドで依存パッケージをまとめて導入できます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FrWNOKx.webp","\u002Ffiddling\u002Fspike-install",{"text":490,"minutes":794,"time":795,"words":796},3.89,233400,778,[409,798,799,800,801],"Spike","riscv-pk","クロスコンパイル","ツールチェーン","RISC-Vツールチェーンとエミュレーターのインストール",{"categories":804,"date":805,"description":806,"image":807,"path":808,"readingTime":809,"recommend":813,"tags":814,"title":821,"type":410},[384],"2026-09-09 23:59:00","これも一種のNTRですよね","https:\u002F\u002Fblog-img.774352199.xyz\u002FNDPUwc.webp","\u002Ffiddling\u002Fsteamdeck-switch-60fps",{"text":564,"minutes":810,"time":811,"words":812},13.905,834300,2781,7,[815,816,817,818,819,820],"Steam Deck","Nintendo Switch","EmuDeck","Eden","Lossless Scaling","フレーム生成","Steam Deckの第二の人生：Switchエミュレーター導入からフレーム補間で60FPSまで",{"categories":823,"date":824,"description":825,"image":826,"path":827,"readingTime":828,"recommend":394,"tags":833,"title":838,"type":410},[384],"2024-06-23 15:31:32","GFWは単に出口のゲートウェイを監視するのではなく、通信経路の脇から国際通信を傍受します。出入国するIPパケットをクラスタへ複製し、詳しく分析・フィルタリングする仕組みです。どこで何をしているかを理解することは、検閲回避の検討に欠かせません。ネットワーク構成を調べることで、遮断の経路や技術、対処方法が見えてきます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FsOpJuL.webp","\u002Ffiddling\u002Ftech-about-gfw",{"text":829,"minutes":830,"time":831,"words":832},"25 min read",24.975,1498500,4995,[834,835,836,837],"GFW","DNSポイズニング","TCP","インターネット検閲","GFWの仕組みを探る",{"categories":840,"date":841,"description":842,"image":843,"path":844,"readingTime":845,"recommend":394,"tags":849,"title":855,"type":410},[384],"2022-04-16 00:01:28","Javaでは`this`を使うことで、コンパイラの定数最適化が効かなくなる場合があります。このコード例の`ab1`と`ab2`は同じstatic final変数`s`を参照しているように見えますが、比較結果は異なります。静的変数を直接参照して文字列を連結する`ab1`に対し、`this`経由の`ab2`では同じ定数伝播の最適化が行われません。わずかな構文の違いが、コンパイル結果を変える例です。","https:\u002F\u002Fblog-img.774352199.xyz\u002FgKtkYe.webp","\u002Ffiddling\u002Fthis-in-javac-string-concat",{"text":490,"minutes":846,"time":847,"words":848},3.88,232800,776,[850,851,852,853,854],"Java","javac","文字列連結","定数伝播","バイトコード","Javaのthisキーワードでコンパイル時の定数伝播が効かなくなる問題",{"categories":857,"date":858,"description":859,"image":860,"path":861,"readingTime":862,"recommend":394,"tags":867,"title":873,"type":410},[384],"2025-01-29 21:58:00","ひとこと投稿機能があれば、静的ブログの記事公開に伴う手間や心理的な負担を減らし、短い思いつきをいつでも共有できます。Cloudflare Workersでバックエンドを実装し、KVで投稿を保存・管理します。フロントエンドはVitePressにVueコンポーネントを埋め込み、投稿を手軽に表示してブログに動きと交流の場を加えます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FhZX6hr.webp","\u002Ffiddling\u002Fvitepress-memos-component",{"text":863,"minutes":864,"time":865,"words":866},"24 min read",23.345,1400700,4669,[868,869,870,871,872],"VitePress","Vue","Cloudflare Workers","Cloudflare KV","マイクロブログ","VitePressにひとこと投稿機能を実装する",{"categories":875,"date":876,"description":877,"image":878,"path":879,"readingTime":880,"recommend":394,"tags":884,"title":887,"type":410},[384],"2025-03-15 16:24:00","ある平凡な午後、Telegramの通知で魅力的なVPSプランを見つけました。中国電信CN2直結、帯域2.5Gという好条件です。IPv6付きで動画配信サービスの地域制限解除にも便利ですが、すべての通信をWARP経由にする必要はありません。以前のスクリプトは手軽な一方、速度と振り分けに不満があり、もっと柔軟な方法を探すことにしました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FMcjrrF.webp","\u002Ffiddling\u002Fvps-warp-ipv6",{"text":613,"minutes":881,"time":882,"words":883},4.09,245400,818,[885,886,752,571,572],"Cloudflare WARP","IPv6","VPSの特定の通信をWARP経由のIPv6で外に出す",{"categories":889,"date":890,"description":891,"image":892,"path":893,"readingTime":894,"recommend":898,"tags":899,"title":905,"type":410},[384],"2026-08-17 23:59:21","いじればいじるほど、もっといじりたくなります。年を取ってもまだまだ元気、まだまだ元気です。","https:\u002F\u002Fblog-img.774352199.xyz\u002FqfxB0h.webp","\u002Ffiddling\u002Fxiaomi17-root-and-hide-root",{"text":710,"minutes":895,"time":896,"words":897},8.83,529800,1766,6,[900,901,902,903,904],"Xiaomi 17","Bootloader","Android Root","ファームウェア書き換え","Rootの隠蔽","Xiaomi 17を普段使いに：ロック解除、ROM書き込み、root化とroot隠し",{"categories":907,"date":909,"description":910,"image":911,"path":912,"readingTime":913,"recommend":394,"tags":918,"title":923,"type":410},[908],"notes","2022-01-20 22:29:00","Lab 1では、masterとworkerという2つの主要な部分からなるMapReduceシステムを実装します。GoのRPCと並行プログラミングを十分に使いこなし、MapReduceの処理の流れも深く理解する必要があります。実装は2つの版を作り、mutexでロックする方式から、よりすっきりしたchannelによる明示的なロックを使わない方式へと改めました。後者のほうが設計もシンプルで分かりやすくなっています。実習を理解する鍵は、関連資料、特にフローチャートとその説明をしっかり読むことです。","https:\u002F\u002Fblog-img.774352199.xyz\u002FibVwPJ.webp","\u002Fnotes\u002F65840\u002Fmapreducelab",{"text":914,"minutes":915,"time":916,"words":917},"13 min read",12.39,743400,2478,[919,920,602,921,922],"MIT 6.5840","MapReduce","RPC","並行プログラミング","6.5840 Lab 1：MapReduce",{"categories":925,"date":926,"description":927,"image":928,"path":929,"readingTime":930,"recommend":394,"tags":934,"title":939,"type":410},[908],"2022-01-16 17:32:00","MapReduceは、大規模なデータセットの処理を簡単にするための効率的な並列計算モデルです。利用者はMapとReduceという2つの主要な関数を定義することで、複雑なタスクを簡単な操作に分解できます。データの分配やタスクの割り当てはフレームワークが自動で管理するため、開発者は低レベルの細部に気を取られず、アルゴリズムそのものに集中できます。分散システムで広く使われていることからも、その柔軟性と実用性が分かります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FApIDdC.webp","\u002Fnotes\u002F65840\u002Fmapreducepaper",{"text":710,"minutes":931,"time":932,"words":933},8.085,485100,1617,[920,935,936,937,938],"分散システム","論文ノート","並列計算","耐障害性","MapReduce論文を読む",{"categories":941,"date":942,"description":943,"image":944,"path":945,"readingTime":946,"recommend":394,"tags":950,"title":954,"type":410},[908],"2022-12-16 02:06:10","Lab 2Aでは、Raftのリーダー選出とハートビートを実装し、さまざまな厳しい条件でも任期の交代や選挙が正常に行われるようにします。実習全体は4段階からなり、この後に実装する分散KVストアの土台になります。明示的なロックを使わない設計によって、Raft構造体を簡潔にします。実習の手引きには必要な背景知識が載っていますが、前の実習と比べると参考資料に頼れる部分はほとんどなく、自力で実装することが重視されます。","https:\u002F\u002Fblog-img.774352199.xyz\u002Fc11Uk4.webp","\u002Fnotes\u002F65840\u002Fraftlab2a",{"text":548,"minutes":947,"time":948,"words":949},17.515,1050900,3503,[919,951,602,952,953],"Raft","リーダー選出","分散合意","6.5840 Lab 2A：リーダー選出",{"categories":956,"date":957,"description":958,"image":959,"path":960,"readingTime":961,"recommend":394,"tags":966,"title":968,"type":410},[908],"2022-12-03 21:40:09","Raftは、ログレプリケーションの効率を高めるために設計された合意アルゴリズムです。複数のマシンからなるクラスタに適しており、一部のマシンが故障してもサービスを継続できます。複製状態機械モデルを使い、ログに命令の順序を記録することで、クラスタ内の各マシンが同じ状態に到達できるようにします。論文『In Search of an Understandable Consensus Algorithm』は、Raftの設計思想とPaxosとの比較を詳しく論じ、その理解しやすさを示すとともに、信頼できる大規模なソフトウェアシステムを構築するための土台を提供しています。この記事は、その中心的な概念と応用を理解するための読書メモです。","https:\u002F\u002Fblog-img.774352199.xyz\u002F7mmvIZ.webp","\u002Fnotes\u002F65840\u002Freftextendedpaper",{"text":962,"minutes":963,"time":964,"words":965},"30 min read",29.245,1754700,5849,[951,953,967,936],"ログ複製","Raft論文を読む",{"categories":970,"date":972,"description":973,"image":974,"path":975,"readingTime":976,"recommend":980,"tags":981,"title":985,"type":410},[971],"projects","2021-11-27 14:43:00","MYDBは、データベースの基本原理を学び、実装してみるための個人プロジェクトです。空き時間を使い、半月あまりかけて作りました。大学のデータベースシステムの授業で基礎には触れたものの、インターン中は授業を口実にサボってばかりでした。面接で正直に答えても大きな問題にはなりませんでしたが、それをきっかけに自分の知識を見直し、実際に手を動かして学ぼうと考えるようになりました。そうして生まれたのがこのプロジェクトです。","https:\u002F\u002Fblog-img.774352199.xyz\u002Fxfci2J.webp","\u002Fprojects\u002Fmydb\u002Fmydb0",{"text":710,"minutes":977,"time":978,"words":979},8.03,481800,1606,1,[982,850,983,984],"MYDB","データベース実装","データベースアーキテクチャ","MYDB 0. プロジェクト構成と、先に伝えておきたいこと",{"categories":987,"date":988,"description":989,"image":990,"path":991,"readingTime":992,"recommend":394,"tags":997,"title":1000,"type":410},[971],"2021-11-28 16:10:00","MYDBではXIDファイルでトランザクションを管理します。各トランザクションには1から増える一意のXIDがあり、XID 0は常にコミット済みのスーパートランザクションです。TransactionManagerがこのファイルを管理し、実行中・コミット済み・中止済みという3つの状態を記録します。この仕組みにより状態を正確に照会・管理でき、システムの安定性と信頼性を支えます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FH4zZAK.webp","\u002Fprojects\u002Fmydb\u002Fmydb1",{"text":993,"minutes":994,"time":995,"words":996},"8 min read",7.42,445200,1484,[982,850,998,999],"トランザクション管理","XID","MYDB 1. まずはシンプルなTMから",{"categories":1002,"date":1003,"description":1004,"image":1005,"path":1006,"readingTime":1007,"recommend":394,"tags":1011,"title":1015,"type":410},[971],"2021-12-25 18:26:00","MYDBはMySQLに似たC\u002FS構成を採用し、複数のクライアントがソケットでサーバーへ接続してSQLを実行し、結果を受け取れます。通信には専用のバイナリー形式を使いますが、実装を簡単にするならプレーンテキストも選択肢です。サーバーとクライアントの基本的な転送構造によって、データのやり取りと処理を行います。","https:\u002F\u002Fblog-img.774352199.xyz\u002FPAHrUZ.webp","\u002Fprojects\u002Fmydb\u002Fmydb10",{"text":581,"minutes":1008,"time":1009,"words":1010},5.76,345600,1152,[982,850,1012,1013,1014],"Socket","クライアントサーバー構成","通信プロトコル","MYDB 10. サーバー・クライアントの実装と通信プロトコル",{"categories":1017,"date":1018,"description":1019,"image":1020,"path":1021,"readingTime":1022,"recommend":394,"tags":1026,"title":1030,"type":410},[971],"2021-11-30 23:18:00","データマネージャー（DM）は上位モジュールとファイルシステムをつなぎ、ページとキャッシュを管理しながら、データの安全性と復旧を支えます。キャッシュには従来のLRUではなく参照カウント方式を採用し、汎用性と効率を高めて、この先のデータ操作の土台を作ります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FWdIGoG.webp","\u002Fprojects\u002Fmydb\u002Fmydb2",{"text":512,"minutes":1023,"time":1024,"words":1025},10.395,623700,2079,[982,850,1027,1028,1029],"参照カウント","キャッシュ設計","共有メモリ","MYDB 2. 参照カウント方式のキャッシュ基盤と共有バイト配列",{"categories":1032,"date":1033,"description":1034,"image":1035,"path":1036,"readingTime":1037,"recommend":394,"tags":1041,"title":1044,"type":410},[971],"2021-12-05 15:28:00","DMはファイルシステムをページとして抽象化し、ページ単位で読み書きとキャッシュを行います。データページのデフォルトサイズは8Kで、大量の書き込みではサイズの調整によって性能を高められます。実装済みの汎用キャッシュ基盤を使い、ここではページ構造を具体的に定義して、効率よくページを管理します。","https:\u002F\u002Fblog-img.774352199.xyz\u002FjlFC4E.webp","\u002Fprojects\u002Fmydb\u002Fmydb3",{"text":993,"minutes":1038,"time":1039,"words":1040},7.14,428400,1428,[982,850,1042,1043],"データページ","キャッシュ管理","MYDB 3. データページのキャッシュと管理",{"categories":1046,"date":1047,"description":1048,"image":1049,"path":1050,"readingTime":1051,"recommend":394,"tags":1055,"title":1058,"type":410},[971],"2021-12-08 22:55:00","MYDBでは、クラッシュ後にデータを復旧できるよう、ログファイルが重要な役割を担います。DMは下位のデータを操作するたびにログを生成・記録し、連続したログ列を作ります。チェックサムと各操作の記録を含む所定のバイナリー形式で保存することで、再起動時にデータの状態を正確に再構築し、整合性と完全性を保ちます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FTRcbsj.webp","\u002Fprojects\u002Fmydb\u002Fmydb4",{"text":914,"minutes":1052,"time":1053,"words":1054},12.685,761100,2537,[982,850,1056,1057],"データベースログ","クラッシュリカバリ","MYDB 4. ログファイルと復旧戦略",{"categories":1060,"date":1061,"description":1062,"image":1063,"path":1064,"readingTime":1065,"recommend":394,"tags":1069,"title":1072,"type":410},[971],"2021-12-11 15:16:00","ページインデックスはDM層の重要な構成要素です。各ページの空き容量をキャッシュすることで挿入処理を効率化し、上位モジュールが長い探索をせずに適切なページを素早く見つけられるようにします。実装ではデータ項目（DataItem）の抽象化とも密接に連携し、データベースの効率的な動作を支えます。","https:\u002F\u002Fblog-img.774352199.xyz\u002F22PSG1.webp","\u002Fprojects\u002Fmydb\u002Fmydb5",{"text":530,"minutes":1066,"time":1067,"words":1068},9.86,591600,1972,[982,850,1070,1071],"ページインデックス","データ管理","MYDB 5. ページインデックスとDMの実装",{"categories":1074,"date":1075,"description":1076,"image":1077,"path":1078,"readingTime":1079,"recommend":394,"tags":1083,"title":1087,"type":410},[971],"2021-12-18 14:58:00","VMは二相ロックでスケジュールの直列化可能性を保証し、多版型同時実行制御（MVCC）を導入して読み取りと書き込みの相互ブロックを解消します。また、データベース操作の競合を定義し、特に更新と読み取りの関係を整理することで、トランザクションの分離レベルを理解する土台を作ります。","https:\u002F\u002Fblog-img.774352199.xyz\u002F8YzotA.webp","\u002Fprojects\u002Fmydb\u002Fmydb6",{"text":727,"minutes":1080,"time":1081,"words":1082},14.665,879900,2933,[982,850,1084,1085,1086],"MVCC","トランザクション分離","二相ロック","MYDB 6. レコードのバージョンとトランザクション分離",{"categories":1089,"date":1090,"description":1091,"image":1092,"path":1093,"readingTime":1094,"recommend":394,"tags":1098,"title":1101,"type":410},[971],"2021-12-23 21:20:00","VMでは、MVCCに伴うバージョンの飛び越しとデッドロックに対処する必要があります。MYDBはトランザクションに印を付けるだけで取り消しやロールバックを行い、abortedなトランザクションのデータがほかへ影響しないようにします。この設計により並行処理の効率と信頼性を高め、従来の2PLで起こりがちなデッドロックを避けて、システム全体の安定性と性能を向上させます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FBF3yDW.webp","\u002Fprojects\u002Fmydb\u002Fmydb7",{"text":597,"minutes":1095,"time":1096,"words":1097},11.32,679200,2264,[982,850,1099,1100],"デッドロック検出","バージョン管理","MYDB 7. デッドロック検出とVMの実装",{"categories":1103,"date":1104,"description":1105,"image":1106,"path":1107,"readingTime":1108,"recommend":394,"tags":1112,"title":1115,"type":410},[971],"2021-12-24 21:01:00","MYDBはB+木によるクラスタ化インデックスを実装します。IMはバージョンマネージャー（VM）を経由せず、データマネージャー（DM）と直接やり取りし、インデックスデータをデータベースファイルへ直接書き込みます。この章では二分木インデックスの構造を詳しく説明し、葉フラグ、キー数、兄弟ノードの識別子など、インデックス検索の基盤となる要素を扱います。","https:\u002F\u002Fblog-img.774352199.xyz\u002Ff92X4o.webp","\u002Fprojects\u002Fmydb\u002Fmydb8",{"text":421,"minutes":1109,"time":1110,"words":1111},6.53,391800,1306,[982,850,1113,1114],"B+木","データベースインデックス","MYDB 8. インデックス管理",{"categories":1117,"date":1118,"description":1119,"image":1120,"path":1121,"readingTime":1122,"recommend":394,"tags":1126,"title":1129,"type":410},[971],"2021-12-25 15:44:00","テーブルマネージャー（TBM）は、フィールドとテーブルの構造を管理します。ParserはSQL風の文を構造化して解析し、文に含まれる情報を対応するクラスへまとめることで、その後の操作を簡単にします。この章ではMYDBのSQL構文も紹介し、管理処理全体を理解する土台を作ります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FzOMyv5.webp","\u002Fprojects\u002Fmydb\u002Fmydb9",{"text":993,"minutes":1123,"time":1124,"words":1125},7.99,479400,1598,[982,850,1127,1128],"SQL解析","テーブル管理","MYDB 9. フィールドとテーブルの管理",1789914057044]