UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【Cline】Clineを軽く触ってみた

話題のClineを軽く触ってみた

まず感じたのは、LLM APIの課金コスト感覚がないから怖い

Clineは API Provider を選択できるのだが、

持っていたOpenAIアカウントを利用しようとしたところ、いきなり「現在のクォータを超過した」とのエラーが発生した

OpenAIの場合、1 分あたりのトークン数 (TPM)、1 分または 1 日あたりのリクエスト数 (RPM/RPD)の上限がモデルによって設けられているので、これを超えている可能性がある


OpenAI Platform

このクォータを下回ったとて大量のトークン数になる可能性があり、ちょっと怖いなと感じた

というわけで、クレカに紐づいてない、かつ、OpenAIよりクォータが緩い Geminiを使ってみることにした

GeminiのAPIトークン取得は以下より可能 ai.google.dev

設定

VSCodeプラグインで Cline をインストール

その後、設定画面を開いて先ほどのAPIキーなどを設定する

この時、Custom Instructions には日本語でやり取りするために以下の指示をしておいた

必ず日本語で応対してください。

あとはこの辺の設定

上から訳すと

  • ファイルとディレクトリを読み取る
    コンピュータ上の任意のファイルを読み取るためのアクセスを許可するかどうか
  • ファイルを編集する
    コンピュータ上のあらゆるファイルの変更を許可するかどうか
  • 安全なコマンドを実行する
    安全なターミナルコマンドの実行を許可する。モデルによってコマンドが潜在的な破壊的であると判断された場合、承認が必要になる
  • ブラウザを使用する
    ヘッドレスブラウザで任意のWEBサイトを起動して操作できるようにするかどうか
  • MCPサーバーを使用する
    ファイルシステムを変更したりAPIと対話したりする可能性のある構成済みのMCPサーバーの使用を許可する

今回はファイルとディレクトリを読み取るブラウザを使用するにチェックを入れた

デモ

2つの入力を与えて、その差分を描画するWEBアプリを作ってもらうことにした

前提として、Next.jsのプロジェクトはすでにあり、renderDiffという2つの入力の差分をレンダリングする関数もすでにあったので、これを利用してブラウザ表示までできるようにしてもらった

まず、目標と手順が書かれていておぉと思ったのと、ファイルを読むためにアクセス許可を求められたので設定がちゃんと機能していることがわかった

ファイルを読んでrenderDiffが何をしているのかを理解したら、今度は新しいファイルdiff-viewer.tsxを作ろうとしている

これもちゃんと許可が求められるので、許可を出すと作成された

次に、page.tsxを修正しようとするのだが、これは失敗していた

よくみると、page.tsx はNext.jsのプロジェクトのインストール時からあるファイルでサンプルの実装がされているのだが、そのコードを残したままその上に追記するようなコードになっていた

これは意図的かもしれないし、これくらいなら良い

最後にこのアプリを立ち上げてブラウザで確認というところまでやろうとしたが、トークン切れてできなかった

課金して続きは後日やることにする

まとめ

これくらい程度ならClineじゃなくてもできるかもしれないが、VSCodeからかなりお手軽に試すことができた

1つのプロンプトでここまでやってくれるのはすごいなぁと思いつつ、参画プロジェクトでの活用方法を考えたいと思った

【JavaScript】Number型より正確な計算をしたい場合のライブラリbignumber.js

bignumber.js というライブラリを知ったので調査

mikemcl.github.io

JavaScriptの数値はIEEE 754 倍精度浮動小数点数(double)のため、数を表現するために使えるビット数に限りがあり、少数の計算が正しくできない

double は、例えば 1 / 10の結果(0.1) 2進数への変換で無限に続く循環小数になってしまうため、丸め誤差が発生してしまう

そのため、JavaScriptでより正確な計算をする場合、外部ライブラリを用いなければならず、 bignumber.js はその少数計算ライブラリの1つである

主な特徴

  • 整数と小数に対応
  • シンプルなAPIながらフル機能
  • JavaBigDecimalJavaScriptで実現したものより、高速かつ軽量で扱いやすい
  • サイズが小さい(gzip圧縮後で8 KB)
  • JavaScriptのNumber型のtoExponential、toFixed、toPrecision、toStringメソッドを再現
  • toFractionメソッドと正確に丸められるsquareRootメソッドを含む
  • 暗号学的に安全な疑似乱数生成をサポート
  • 依存関係なし
  • 幅広いプラットフォーム互換性:JavaScript 1.5(ECMAScript 3)のみを使用
  • 包括的なドキュメントとテストセット

基本的な使い方

bignumber.js は、Number、String、BigNumber型の値を受け入れる単一のコンストラクタ関数をエクスポートしている

初期化

// 文字列から初期化
const a = new BigNumber("123.4567");

// 数値から初期化(ただし、0.1などそもそも丸め誤差になっているものは注意が必要)
const b = new BigNumber(123.4567);

// 他の BigNumber から初期化
const c = new BigNumber(a);

基本演算

const x = new BigNumber('0.1');
const y = new BigNumber('0.2');

// 加算
console.log(x.plus(y).toString()); // '0.3'

// 減算
console.log(x.minus(y).toString()); // '-0.1'

// 乗算
console.log(x.multipliedBy(y).toString()); // '0.02'

// 除算
console.log(x.dividedBy(y).toString()); // '0.5'

// べき乗
console.log(x.pow(2).toString()); // '0.01'

除算を含む演算 (除算、平方根、基数変換、負の累乗演算など) の結果の小数点以下の最大桁数は、コンストラクタのsetメソッドを使用して設定できる

BigNumber.set({ DECIMAL_PLACES: 2, ROUNDING_MODE: BigNumber.ROUND_HALF_UP });

const z = new BigNumber('1.005');
console.log(z.toFixed()); // '1.01'

あとは比較など

const p = new BigNumber('10');
const q = new BigNumber('20');

console.log(p.isLessThan(q)); // true
console.log(p.isEqualTo(q));  // false
console.log(p.isGreaterThan(q)); // false

参考

JavaScriptの数値計算はどれくらい正確なのか

【VSCode】Undoが複数回実行される

vscodevimを使っていると、uでのUndoが謎に複数回実行されて戻りすぎてうざい

調べたところ以下の設定をすると直るらしい

    "vim.normalModeKeyBindingsNonRecursive": [
        {
            "before": [
                "u"
            ],
            "commands": [
                "undo"
            ]
        },
        {
            "before": [
                "<C-r>"
            ],
            "commands": [
                "redo"
            ]
        },
    ],
  • "before": ノーマルモードで押すキーの組み合わせ
  • "commands": そのキーが押された際に実行されるコマンド

設定の内容

  1. "before": ["u"]

    • u キーが押されたときに undo コマンドを実行
    • これにより、ノーマルモードのデフォルトの u キー(Vimの「undo」)動作がそのまま使える
  2. "before": ["<C-r>"]

    • <C-r>(Ctrl + r)が押されたときに redo コマンドを実行
    • これにより、ノーマルモードのデフォルトの <C-r> キー(Vimの「redo」)動作がそのまま使える

参考

【VSCode】vscodevimのUndo/Redoが想定より多く操作する問題に対処する - suer TIL

【DDD】イベントストーミングの入門動画を見た

以前、モノタロウのイベントで尾高さんが紹介していたイベントストーミング入門の動画を見た

イベントストーミングの手法は知っていたが、人がやっているのを見たことはなく、1から作られているのを見るのは楽しかった

www.youtube.com

手順と学んだことテクニックは以下

①まずオレンジ(イベント)の付箋を書き出す

②オレンジ(イベント)の付箋を順番に並べて矢印で繋げる

③各オレンジ(イベント)の付箋の前に、青(コマンド)と黄色(Aggregates)の付箋をおく

このとき、以下のやり方により、かなり楽に作図することができるようになった

  • 青(コマンド)と黄色(Aggregates)とオレンジ(イベント)の付箋は1まとまりとしてよく使うので一緒にしておくと便利
  • この3つの付箋の間は矢印で繋げず、並べておくだけで良い
  • Aggregatesは難しいので後回しで良い

④イベントの先は紫(ポリシー)の付箋もしくは黄緑(ReadModel)の付箋

ポリシーは「いつでも」実行されるという場合に配置して、役割としては以下がある

  • 暗黙の方針:明示的な合意がない場合
  • 明示的なポリシー: 全員が従っていることを前提にする
  • 自動化: リスナー、サーガ、 プロセスマネージャー

もしくは「条件、場合によってはどうする」みたいなのを書く

まずは自動的に付箋を置いてしまって、条件がない場合は空白のままにすると楽

ReadModelは「誰かが見てコマンドを実行する」場合に書く

ピンク(システム)の付箋は、外部システムを表す

こうやってイベントをどんどん繋げていく

⑤イベントの始まりが曖昧な場合は地球儀付箋をおいておく

⑥後回しにしていたAggregatesを考える

目的語を見ると良い

「商品の注文をする」→「注文」

後で変えてもいいので気軽に決めてしまう(チームで合意はする)

⑦これまで作った図を残しつつ、他のスペースにAggregatesごとに並べる

図から引っ張ってくるときに、抜け漏れがないように注意する

⑧完成したらコンテキストで分ける

以上


これまで面倒に感じていた部分や、他の人がどうやっているんだろうという疑問などが解消されて勉強になった

2024年振り返り

2024年の振り返り

今年は30代後半にして新しいチャレンジが多く、自分のやりたいことやスキルなどを改めて見直すような1年だった

🏢仕事

大きな出来事として、これまでやっていた仕事が突然終わり、新しい現場に参加することになった

それ自体はそんなにネガティブではないが、コロナ以降に新しい現場に参加するのは初だと気づき、知らぬ人の中でリモートワークするのが思ったより大変だと感じた

しかも今まで最初のエンジニアとして人を受け入れる立場がほとんどだったので、出来上がったチームに入るのも初めてだった

まるで大縄跳びをみんなで飛んでいる中に飛び込む感じ

しばらく綱を回す側だったので、飛ぶのは久々だから足引っ掛けないようにしないと…とか気疲れが多かった気がする

なんかぎこちない飛び方だったし、足も引っ掛けた気がするが、「死にはしない」と気持ちは落とさないように頑張った

ブログの継続

アウトプットとして、今年は1年ぶりに1月の仕事始めから12月の仕事納めまでの毎日(月〜金)ブログを書くというルールが達成できた

今年で4年目(2023年は時間がなく断念)

だいたい夜や土日にまとめて書くのだが、コロナで寝込んだ日の分も、子が熱で保育園を休んだ日の分も、月〜金であればその分だけ書いた

新環境では、これまでやってこなかったこと、知らなかったことが多かったのでネタには困らなかったが、毎日分書くのは大変だった

ただ、昔の記事に助けられることが多いので、やはりやっていてよかったと思うことの方が多い

👪プライベート

1歳の子供と過ごす日々が本当に楽しかった

いろんなとこにお出かけしたり、シーズンのイベントを楽しんだり、だいぶ癒された

読書

Audibleにしてから、家事の合間に小説本を読む(聴く)ようになった

  • 法廷遊戯
  • 同姓同名
  • 正義の申し子
  • 悪い夏
  • 二木先生
  • 鏡の国
  • ラブかは静かに弓を持つ
  • ナチュラルボーンチキン
  • 汚れた手をそこで拭かない
  • 正体
  • ツミデミック

技術書以外の本を読む時間を惜しむたちだったので、ながらで聴けるAudibleは自分としては良き体験だと思う

🌅来年

来年は大縄跳びで元気に跳ねていられたらと思う

【アルゴリズム】Interleaving

2つの配列を組み合わせる Interleaving(インターリービング) という手法を知ったので調べた

参考になった記事 qiita.com

Interleavingは、2つの配列の要素を交互に組み合わせて1つの配列にする手法

2つのランキングアルゴリズムの結果を交互に組み合わせて統合したランキングを作り、同一のユーザー群にそのランキングを提示して性能を評価したりするのに使う

アルゴリズムはいくつかあり、

  • Balanced Interleaving
  • Team Draft Interleaving
  • Probabilistic Interleaving
  • Optimized interleaving

などがある

Balanced Interleave、Team Draft Interleaving、Probabilistic Interleaving の違いは以下

Balanced Interleave

概要

  • 入力された2つの配列から、どちらから先に追加するかを選び、交互に要素を選んで統合する手法

特徴

  • 簡単なデータ統合や均等な配列結合に適している
  • どちらから先に追加したかによってあらかた2つの配列の優劣が決まってしまう問題があり、一様な確率で1つの要素をランダム選択した場合にバイアスがかかってしまう

2. Team Draft Interleaving

概要

  • 各ランキングリスト(検索結果など)を「チーム」として扱い、先攻後攻をランダムにしながら交互に順位の高い項目を選ぶ
  • 両チームにある要素は先に選ばれたチームのものとしてランキングに追加され、すでに選ばれた項目は除外される

特徴

  • ランダム選択によるバイアスはなく、公平に評価される
  • 統合した配列の中で突出して選択される要素があった場合、片方の配列の方がその要素の順位が高いにも関わらず、どちらの配列も同等に評価され優劣がつかない問題がある(元配列の順位の重みづけが考慮されていない)

3. Probabilistic Interleaving

概要

  • 2つのランキング結果から交互に要素を追加していく際に、できるだけ順位を保持しつつも、相対的に低い確率で任意の順序を選んで結合する手法
  • 基本的に順位の高いアイテムほど選ばれる確率が高いが、完全に確定的ではない

特徴

  • ランダム選択によるバイアスはなく、公平に評価される
  • 元配列の順位の重みづけが考慮される

他参考

https://disk.yandex.ru/i/1nhkaIY2ULQM-A

https://data.gunosy.io/entry/2018/10/15/080000

https://www.nogawanogawa.com/entry/interleaving

【React】複数のuseRefをまとめたい

外側から受け取ったrefとは別に、コンポーネント内部で定義したrefも一緒に子コンポーネントに渡したい場合を調べた

調べたところ、カスタムhookで作る必要があった

useMergeRefという名でよくutilとして実装されている模様

実装例:

import { useCallback } from 'react';

function useMergeRef<T>(...refs: Array<React.Ref<T> | undefined>) {
  return useCallback((node: T | null) => {
    refs.forEach(ref => {
      if (!ref) return;

      if (typeof ref === 'function') {
        ref(node); // 関数型refの場合、直接呼び出す
      } else if (ref && 'current' in ref) {
        (ref as React.MutableRefObject<T | null>).current = node; // オブジェクト型refの場合、currentに設定
      }
    });
  }, [refs]);
}

export default useMergeRef;

使い方

外部refと内部refをマージして渡す

import React, { forwardRef, useRef } from 'react';
import useMergeRef from './useMergeRef';

type Props = {
  externalRef?: React.Ref<HTMLDivElement>;
};

const MyComponent = forwardRef<HTMLDivElement, Props>(({ externalRef }, forwardedRef) => {
  const internalRef = useRef<HTMLDivElement>(null);

  const mergedRef = useMergeRef(internalRef, externalRef, forwardedRef);

  return <div ref={mergedRef}>Hello, World!</div>;
});

export default MyComponent;

これで外部refと内部refを簡単に統合して扱えるようになった