ソフトウェア開発」カテゴリーアーカイブ

useEffect, useCallback, useMemoに関しての使い分け

Claudeに課金をしたので、先日より取り組んでいるElectron製のアプリをちまちまと助けを借りながらいじっているのですが、

まずは、提示された内容を元に書き写すような形で進めています。

その中で、AIあるあると言えばあるある何でしょうけれど、生成されるコードがコロコロ変わる問題にぶち当たっています。

結局のところ、目的を達成する上でプログラミングの書き方としては複数のやり方があって、その背景をAIに伝えない限りはどの手法が適切なのかはわからず、その生成されるコードが変わるわけですね。

言葉で言ってしまえば、そりゃそうなんだけど、なかなかのストレスです。
完全に任せるわけではない、AIサポートの開発における難しさを感じますね。。。

こういうものを見ていると、結局コードに関しての知識は必要になりそうだな、という気がしてきます。

というわけで、今回は自分の学習記録として、useEffectとuseCallback。そして調べているうちに出てきたuseMemoに関して書いてみようと思います。

useEffect – 副作用の管理

特徴

  • コンポーネントのレンダリング後に実行される
  • DOM操作、データフェッチング、購読、タイマーなどの副作用を扱う
  • クリーンアップ関数を返すことで、コンポーネントのアンマウント時や依存配列の値が変わる前に実行される処理を定義できる

使用例

import React, { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // 副作用: APIからデータをフェッチ
    setLoading(true);

    // userIdが変わるたびに新しいユーザーデータを取得
    fetch(`https://api.example.com/users/${userId}`)
      .then(response => response.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      });

    // クリーンアップ関数
    return () => {
      // コンポーネントのアンマウント時やuserIdが変わる前に実行
      console.log('User profile cleanup');
    };
  }, [userId]); // 依存配列: userIdが変わったときだけ実行

  if (loading) return <div>Loading...</div>;
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

いつ使うべきか

  • 外部データの取得
  • イベントリスナーの設定と解除
  • DOM要素の直接操作
  • タイマーの設定とクリア
  • 外部サービスへの購読と解除

useCallback – 関数のメモ化

特徴

  • 関数をメモ化し、不要な再生成を防ぐ
  • 依存配列の値が変わるまで、同じ関数インスタンスを保持する
  • 子コンポーネントに渡す関数のパフォーマンス最適化に役立つ

使用例

import React, { useState, useCallback } from 'react';

// 子コンポーネント(React.memoでメモ化)
const ExpensiveList = React.memo(({ items, onItemClick }) => {
  console.log('ExpensiveList rendered');
  return (
    <ul>
      {items.map(item => (
        <li key={item.id} onClick={() => onItemClick(item.id)}>
          {item.name}
        </li>
      ))}
    </ul>
  );
});

function ItemManager() {
  const [items, setItems] = useState([
    { id: 1, name: '項目1' },
    { id: 2, name: '項目2' },
  ]);

  const [count, setCount] = useState(0);

  // useCallbackを使用して関数をメモ化
  const handleItemClick = useCallback((id) => {
    console.log(`Item ${id} clicked`);
  }, []); // 空の依存配列: 関数は再作成されない

  return (
    <div>
      <h1>アイテム管理</h1>
      <ExpensiveList items={items} onItemClick={handleItemClick} />
      <div>
        <p>カウント: {count}</p>
        <button onClick={() => setCount(count + 1)}>
          カウント増加
        </button>
      </div>
    </div>
  );
}

いつ使うべきか

  • `React.memo`でラップされた子コンポーネントに関数を渡す場合
  • `useEffect`の依存配列に関数を含める場合
  • イベントハンドラーが複雑で、不要な再作成を避けたい場合
  • 関数が他のフックの依存関係になっている場合

useMemo – 値のメモ化

特徴

  • 計算結果をメモ化し、不要な再計算を防ぐ
  • 依存配列の値が変わるまで、前回の計算結果を再利用する
  • 計算コストが高い処理の最適化に特に役立つ

使用例

import React, { useState, useMemo } from 'react';

function ExpensiveCalculation({ numbers }) {
  const [count, setCount] = useState(0);

  // 計算コストが高い処理をuseMemoでメモ化
  const sumResult = useMemo(() => {
    console.log('Heavy calculation running...');
    // 重い計算の例
    return numbers.reduce((total, num) => {
      // 人為的に処理を重くする
      for (let i = 0; i < 1000000; i++) {}
      return total + num;
    }, 0);
  }, [numbers]); // 依存配列: numbersが変わった時だけ再計算

  return (
    <div>
      <h2>計算結果: {sumResult}</h2>
      <p>カウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        カウント増加(計算には影響しない)
      </button>
    </div>
  );
}

function App() {
  const [numbers, setNumbers] = useState([1, 2, 3, 4, 5]);
  return (
    <div>
      <ExpensiveCalculation numbers={numbers} />
      <button onClick={() => setNumbers([...numbers, numbers.length + 1])}>
        数字を追加
      </button>
    </div>
  );
}

いつ使うべきか

  • 計算コストが高い処理の結果をキャッシュしたい場合
  • レンダリングごとに再生成したくないオブジェクトがある場合
  • 大きな配列やオブジェクトの変換や加工を行う場合
  • コンポーネントの再レンダリングが頻繁に発生する場合

まとめ

結局のところ、どこまでキャッシュさせることが可能な内容何だっけ?ってところなんでしょうね。

計算コストが高くても、再レンダリングが頻繁に発生しようとも、表示内容が再計算必要なものであればuseEffectにするしかないんだろうし。。。くらいに覚えておくことにします!

Tailwindcssの適用にてんやわんや

Electronのプロジェクト構成として、Next.jsをフロントエンドに選択。
CSSとしてはTailwindcssを適用しようとしていたのですが、見様見真似でやっているものの、動いているコードを見る限り正常にTailwidがあたっているように見えない。

ということで、もう一度インストールから見直してみることに。

$ npm install -D tailwindcss autoprefixer postcss

インストール自体は上記コマンドで問題なくインストールできているようです。
これに、初期化するコマンドが必要となるのですが

$ npx tailwindcss init -p
npm error could not determine executable to run
npm error A complete log of this run can be found in: /XXXXX

というようにエラーが出ていることがわかりました。

おかしい。。。Claudeに聞いてみてもセットアップの仕方は上記コマンドで問題ないはずなのですが、、、と調べてみるとどうやらtailwindcssのv4系ではセットアップ方法が変わったようで、上記のコマンドはv3系のもののよう。

そんなわけで、一旦インストールするtailwindcssをv3系にしてみます

$ npm install -D tailwindcss@3.4.17 autoprefixer postcss
$ npx tailwindcss init -p

上記でエラーが解消されました。

v4系のセットアップは、ViteかPostCSSなどによってやり方が変わっているよう。

もう、頭から引っかかりまくっているので大変です。。。
やっぱりフロントエンドは中途半端に手を出すときっついです。

Electron + Next.js + TypeScript

Electronを利用してのアプリケーション開発で、いくつかの選択肢が存在するけれど、どうせならNext.jsやTypeScriptを使ってみたいと思っていた。

いくつか探したところ、ちょうどいいサンプルがあったのでそれをベースにアプリを作ることにする

Electron with Typescript application example
https://github.com/vercel/next.js/tree/canary/examples/with-electron-typescript

利用の方法はReadmeにかかれているが、下記のような形(プロジェクト名をelectron-exampleにした場合
npx, yarn , pnpmそれぞれ書かれている

npx create-next-app --example with-electron-typescript electron-example
yarn create next-app --example with-electron-typescript electron-example
pnpm create next-app --example with-electron-typescript electron-example

これで作られるフォルダ構成としてはざっくりこんな感じ

npm run devを実行してみると

起動した。

ハマったこと

Electron超初心者のわたしがハマったこととしては、、build後のフォルダ構成が下記のように増えたことだった。

今振り返って考えてみると、これはTypeScriptをコンパイルしてできたファイルになるので、それらは管理対象外なんですよね。

チュートリアルやQiitaを見ながらいじっていたので、main/index.jsやそれをコピーしてmain/main.js等としたりしていたので全然動きませんでした。

それらを考えるとコンパイルによって自動生成されるコードはGithubの対象外にするべきなので、gitignoreは下記を追加しています

/.next/
/out/
main
dist
renderer/.next
renderer/out

修正してもビルドしたらもとに戻ったり、思ったものが表示されなかったりと、余計な時間を使ってしまいましたが、ようやくスタートできそう

デザインシステム構築の実践イベントに参加してきた

3月7日に表参道スパイラルホールで開催されたFigmaJapan社主催のイベント「スケーラブルなデザインシステム構築の実践」というイベントに縁があって参加してきました

https://designsystem102.splashthat.com/TW

デザインシステム。
フロントエンドの世界を主戦場としているわけではないのですが、言葉自体は把握していて、主には mozaic.fm というPodcastでよく話に上がっているので気になっていました。

デザインが特に意識されるのはToCの分野が多い認識でToBに関してはあまり必要性が認識されていない事が多い。
前職でもよくあったのが、画面にできるだけ情報を詰め込むような形。

結局これは、もともと使っていた画面や紙がそれだけの情報量を一目で見ることができ、それを用いた業務にユーザが最適化していることに起因していると思う。
画面を分割したりスクロールやタブが発生すると業務効率が落ちるというクレームが入る。

ただ、その流れは確実に変わってきていると思っていて、それは何よりもユーザがスマホやタブレット端末を日常使いするようになり、デザイン要素を取り込んだアプリケーションに慣れてきたという側面が強いのではないかと思っている。

そんなわけで、これからアプリケーション開発を行っていくうえでデザインシステムの構築みたいなものというのは、どういうシーンで必要で強みになり、どういうシーンでは逆に不要となるのだろうか?というのが自分の中での問いになった。

そんなモヤモヤしながらもしっかりと学習していない中でたまたまFigmaJapan社の方とメールする機会あり、本イベントを紹介いただいたのでホイホイと参加してみた。

こちらのイベントは後ほどYoutubeへ公開されるということなので、興味がある方はFigmaJapanさんの公式Xを追っていると出てくると思う。

実践編ということだけあって、登壇されたYahoo!社もHonda社も少し規模が違いすぎる感覚だった。
そもそも、自社プロダクトを持っているわけでもない立ち位置での話なので、デザインシステムの構築をお手伝いする立場?請負でそれを適用する??
そもそもデザインシステムを作ったこともないのに??

自分の立ち位置にツッコミどころ満載である。

うーん、面白そうで大事そうではあるけれど、やはりちゃんと理解して腹落ちするところから進めないとダメだろうな、、、ということでこちらのYoutubeを一旦見ておこう。
そのうえで公開されるであろう今回のイベントを見返してみたいと思う。

Electronを触り始めた

ちょっと秘匿性の高いデータを取り扱うアプリケーションを作りたくなって、そう考えるとWebアプリは面倒かもな?と。

かといってAccessで作るのも手軽なんだけど芸がないな~と思ってElectronに手を出してみた

https://www.electronjs.org/ja

概要レベルは知っていたけれど、実際にコードを見て改めて面白いな、と思った

スタンドアロンのアプリケーションとなるのだから、いわゆるフロントエンドとバックエンドが一つになっているんだけど、ElectronはそれをWebの技術を使って実装している。

つまりは、一つのアプリケーションにNode.jsで作られたバックエンドであるメインプロセスと、Web技術。ReactやViewなどが利用可能なレンダラープロセスが明確に分離されて存在している。

そして、それらをpreload.jsでつなぎ合わせている。

通常httpなどでそれらをつなぐことになる部分はipcが唯一の通信手段として存在している。。と。

面白い仕組みだ。

悩ましいな、と思うのはいわゆるAIを用いたコーディングスタイルを考えるとこのあたりの仕組みの理解をすっ飛ばしてものができてしまうんですよね。
結果論で言えばそれで問題なくものが作られる世界であればそれはそれで効率のいい話ではあるんだけど、、、

とりあえず、最近ろくにフロントエンドに携わっていないのでNext.jsとかどこまでできるんだろう?という不安はあるものの、やれる範囲まで頑張ってみようかと思っています

Fly.io のAppを削除する

Obsidian の Self-hosted LiveSync をFly.ioで作ろうとしたものの、App作成スクリプトの使い方を誤っていたようで、作り直す必要が生じてしまった。

基本的にFly.ioはCLIからの操作になるのだが、削除自体はDashboardからできるようだった

ログインすると、登録されているAppが表示されている。
Obsidian用に1GBのDBが構築されているのがわかる

Appを選択して、左下の「Settings」を選択する

「Delete app」を選択すれば削除ができる。

アプリケーションの削除が設定ページにあるという発送に思いつかず、結構探し回ってしまった。

これで削除が完了して、余計なインスタンスを維持する必要もなくなって安心。安心。

Garminが充電できなくなった

早いよ。早いよダニー

購入してまだ一月も経っていないのに、Garminが充電できなくなってしまった。
正確に言うと、一瞬充電中のマークはつくけれどすぐに消えてしまうような感じ。
すごい接触不良臭い。

接触不良だと仮定して、充電ケーブル側の問題なのか、時計側の問題なのかの二択になるはず。
と、充電ケーブルを見てみると・・・

ちょっと分かりづらいかもしれないですが、一番手前のピンが他のピンと比べて短い用に見える。なんか変。

もともとの状態がわからないので確証はないけれど、これじゃないかな?とネットで調べてみると。。。

GARMIN(ガーミン)充電できないときにやるべき3つのこと【解決策】
https://cediablog.com/garmin_battery_checkpoint

上記ブログでまさに同じような状態になっている写真が。
これは確定ではないだろうか。

保証期間内なので公式の修理に出してもいいんだけど、修理に出すにはあれこれ手順が必要そうな気がする。
その間、Garminと離れ離れになるのは耐えられない(恋人気分)

というわけで、Amazonで充電ケーブルをポチった

2枚 L字型 ガーミン 充電ケーブルGarmin Watch用充電器 USB C充電ケーブル

公式の充電ケーブルは、Garminに差し込むと浮いてしまうのだけど、このケーブルはL字型になっているので充電中の姿勢が安心感がある。

というか、公式のケーブルでピンが折れてしまったりするのは充電中に変な負荷がかかってしまうのが原因なのではないだろうか?
そんなことまで思えてしまう。

なにはともあれ、バッテリーが切れるギリギリセーフなタイミングでケーブルが届いたので、電源オフになることなく充電することが出来ました。

さて、公式のケーブルに文句をいうか悩むところですね。。。
すでに原因の特定と回避策を実施してしまった手前、別にいいかなという気もする。
でも、せっかくなので公式の反応を見てみてもいいかもしれない。
お金かかってしまっているわけだし。

でも、時計側を送ってくれとか言われたら涙目になりそう

Watch Face を作ってみたい

Garmin の Watch face はConnectIQアプリで入手することができるのですが、有料のものが多いのと、ちょっとごちゃごちゃしすぎる感じがします。

かといって、文字盤を自作することができるとして用意されているFaceItは項目数的にしょぼい。

であれば、自作することが出来ないだろうか?と思って調べてみるとVSCodeで開発環境を作ることができるということだったので、まずは開発環境を整えてみた

前提

VSCodeインストール済み
Javaインストール済み

公式の環境作成に関するページはこちら
https://developer.garmin.com/connect-iq/connect-iq-basics/getting-started/

SDKインストール

SDK取得のページからSDK Managerをダウンロード。起動する。
基本的にポチポチと進めていくことでSDKをインストールすることが出来た。
バージョンに関しては、執筆時点では 7.4.3が最新のようなのでこちらをCurrentとする

無事にインストールが済んだら、続いてVSCodeに拡張を追加していく

VCSCodeへのインストールと設定

VSCodeのExtensionとして「Monkey C」を検索、インストールする。
その後、VSCodeを再起動してコマンドパレット(Ctrl+Shift+P)から「Generating a developer Key」を選択。適当なフォルダを選択してKeyを出力する。

その後、Monkey C : New Projectを選択します

プロジェクト名を適当に入力。
WatchFaceなので安直にface1とかにしてみました

続いて、なんのプロジェクトかを選択します。
ここではWatch Faceですが、その他の選択肢が若干気になりますね。。。

テンプレートとしては、Settingもできたほうがいいと考えて「Simple with Settings」を選択します。

対応するAPIレベルを選択します。
APIレベルに関しては、どの機種がどのレベルを対応しているかの一覧が公式にあるので、必要に応じて選ぶことになります。

得に今回は複数の機種での用途を考えないので自分が持っている265が5.0.0だったのでそれを選択してみました

どの製品を対象とするのかを選択します。
このあたりはシミュレーターやストアへの公開時設定に影響を及ぼしそうです

無事、プロジェクトを作ることが出来ました。

Run and Debugをそのまま押下すると。。

無事にシミュレータも起動させることが出来ました!

ちょっと遊んでみたいと思います!

請負開発とアジャイル開発

Qiitaから定期的に好評記事の一覧がメールされてくるわけですが、パラパラっと見ていたら面白い記事が

ウォーターフォールの反省とアジャイルの成功に必要なもの #SIer – Qiita

わかる。

実際に私自身、前職では自社パッケージの開発を行っていて、現在は準委任や請負両方とも関わっていたりするので、言わんとしていることはよく分かる。
そして、携わっていた準委任で参画しているスクラムの案件がそれなりに終りを迎えつつあって、色々と思うところがあったので多少乱雑ではあるけれど書いてみた。
あくまで個人の感想ではあります。

請負で契約に縛られるのは誰なのか

記事では、「問題の原因は請負開発」とあって、そのインセンティブ構造だとかに対して触れられている。

ベンダー側の立場で利益を案件単位での利益を最大化するのであれば、当初契約締結時の仕様を最低限満たすものを、最小の労力で作り上げる事になる。
作りながら「この機能はこういうケースも対応できたほうがいいのでは?」ということに気づいても、当初見積もりからずれる行為であれば事前の要件として明記されていない限りは基本実施しない。
それは、怠慢とかそういうことではなくて、見積もりの前提が崩れ、その見積もりを下に作られているスケジュールからずれ、納期に影響を与える可能性がある。
言い方は悪いが「余計なものを作っていたら間に合いませんでした」って話になりかねないのだ。

残念なところはユーザー側の立場からも話が出ることはある。
RFPのような形で契約を進めていく場合、そのRFP記載内容からズレたことを行おうとした場合にはユーザー側でも承認プロセスを巻き直す必要がある事が多い。
きっちりかっちりした企業・プロジェクトであればなおのこと、「仕様書にかかれているかどうか」を担当者も判断基準にしている。

このあたり、システムに対して明るくない担当者であるケースも多いのでしょうがないところではある。
ユーザー企業側でシステム全てに詳しい人を割り当てることができるのか?とか考え始めると大変だなぁと思うわけです。

請負におけるベンダー側のインセンティブ

すべての開発者がそうだというような性善説を唱えるわけではないけれど、開発者は基本的に良いものを作りたいと考えていると思う(作れるかは別として)。
お蔵入りするためのものを開発なんてしたくないし、大きいシステムや影響の強いシステムを稼働させるのに臆病になることはあっても、やるからにはいいものを作りたい。

先に書いたように、営利企業である限り利益を生まなければならない以上限界はある。
ただ、最低限請負開発を回していると、要件的に問題がなければそれはいいのだが、ユーザ企業側に不満が残る最低限開発だとリピートされるかが怪しい

請負をする以上、案件を取ってくると言うことが必要になるうえで、顧客満足度を高めて、多少高くてもリピートされることをインセンティブにするという考え方になるのかなぁ、と思う。
サスティナブル的な感じだろうか。

内製か外注かの選択

記事でも書かれている、内製化の流れというのは何となく分かる。

一方で、書かれているようにエンジニアを抱える以上、それに付随した組織改革とエンジニアを(数とスキルの両面で)維持する必要が生じてくる。
ベンダーであれば、様々なプロジェクトを通して色々な経験ができる可能性はあるけれど、ユーザ企業の場合は必ずしもそういう環境を提供できる企業ばかりではないと思っている。
このあたりは、ユーザ企業含めて業界の構造がどうなっていくのかは楽しみだ
自社で内製化のために雇用した人材が維持できず、結局は会社対会社でその部分を担保しようとしているのが今だと思っている。

記事では要件が固まっている場合には内製で行うメリットがないとしているが、これに関しては違和感を感じる。

内製でするべきかどうかは、その作るシステムが自社にとって競争優位を生み出すものかどうかなのではないかな、と。
作り上げる時点で何を作るのかの要件が定まっていたとしても、今後、そのシステムを元に戦っていくのであれば自社で抑えておく必要はあるし、その部分を他社に任せてしまうのは良くない。

「要件が固まっている」が”今後変わることがない”という意味であれば別だけど、変わることのないシステムなんてあるのだろうか?と思ってしまうのはエンジニアサイドの視点なのかもしれない。

一方で、要件が固まっていて特に自社の競争優位に大きな影響を与えないシステムに関しては外注を・・・と思ったけれど、よほどのニッチな領域でない限り、パッケージ導入やAI、ローコードツールによる簡易的なものづくりを内製で・・・ってなっていくんだろう。

数年で取り巻く環境は目まぐるしく変わっていくので、身の振り方は常に考えておかないといけないところですね。

EM Conf JP 2025

いつも楽しみにしているfukabori.fmが更新。
今回は来年二予定されているEMコンフに関しての紹介

122. EMConf JP 2025 w/ dora_e_m | fukabori.fm

ちなみに、11/14現在ではEM Conf JP 2025 のチケット購入は Coming Soon 状態
開催日は2/27ということでまだ結構時間がありますね
平日ということなので仕事を休めれば、行ってみたいところ。

EM。
難しい肩書だと思っています。

プロジェクト、ビジネスのマネジメントではなくエンジニアリングのマネジメントという位置づけ?
多分組織によってどこまでそれが許されるんだろうか?ということとか、そもそもジョブ定義として共通化なんてされていないんだろう。

そもそもの話として、そこまで多い人数のいない組織の場合、そのあたりの区別は曖昧で結局全てをマネジメントしないといけない状態になる認識でいる。
しっかりと役割として分担できるほどの人的にも金銭的にも余裕なんざないのである。

それでも学びは多いはずだし、そういう状態に持っていくことができればいいとは思うので、やさぐれていないで話を聞きに行きたいと思うところ。

スタッフの応募はすでに締め切られてしまっているのであくまで一参加者として。
楽しみであります