React 19 Ref
In React 19, ref can directly be passed to a component as a property, and forwardRef become unrecommanded.
About ref
In React, a ref (reference) let you operate lower-level imperative API on the following elements:
- DOM nodes
- Class component instances
Usually it is created with useRef hook.
function Chat() {
const endRef = useRef();
useEffect(() => {
endRef.current.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
return (
<div className="chat-window">
{messages.map(m => <Message key={m.id} />)}
<div ref={endRef} />
</div>
);
}
Sometimes we need to pass ref down to point to one component of a child component, below are suitable situations:
- When you build a HOC component
- When you wrapping a core component with customized design (like wrapping a material UI Input)
Note that usually it is not a good practice, since it increase the complicity and voilate the capsluating philosoph, we should be careful about the usecases.
Improved ref API in React.19
Before React 19, it is not allowed to pass ref as a property, Instead, forwardRef is needed:
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
const FancyInput = forwardRef(function FancyInput(_, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
clear: () => { if (inputRef.current) inputRef.current.value = ''; }
}), []);
return <input ref={inputRef} className="border rounded p-2" />;
});
export default FancyInput;
// Parent.jsx
import React, { useRef } from 'react';
import FancyInput from './FancyInput';
function Parent() {
const fancyRef = useRef();
return (
<>
<FancyInput ref={fancyRef} />
<button onClick={() => fancyRef.current.focus()}>Focus</button>
<button onClick={() => fancyRef.current.clear()}>Clear</button>
</>
);
}
Note in the example, useImperativeHandle is used to defines the customer handler of ref. By declaring useImperativeHandle in the component, we can:
- rewrite the ref handler behavior
- safely limit the handlers of the ref
By using useImperativeHandle, the original ref donot directly pass to the input, instead in the component we define a new ref, to let the ref operates indirectly.
However, from React 19, forwardRef is not recommended, and ref can be passed directly, which is more concise and have better readability:
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
function FancyInput({ ref }) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
clear: () => { if (inputRef.current) inputRef.current.value = ''; }
}), []);
return <input ref={inputRef} className="border rounded p-2" />;
});
export default FancyInput;
// Parent.jsx
import React, { useRef } from 'react';
import FancyInput from './FancyInput';
function Parent() {
const fancyRef = useRef();
return (
<>
<FancyInput ref={fancyRef} />
<button onClick={() => fancyRef.current.focus()}>Focus</button>
<button onClick={() => fancyRef.current.clear()}>Clear</button>
</>
);
}
Java Optional Best Practices
JavaのOptionalは、値が存在する場合も存在しない場合もあるコンテナオブジェクトです。これにより、nullチェックの手間を減らし、メソッドの戻り値として「値があるかどうか」を明示的に伝えることができます。Optionalは以下のような利点があります:
明確な意図: メソッドが値を返さない可能性があることを示す。 安全な操作: 明示的なnullチェックを回避し、NullPointerExceptionのリスクを減少させる。 関数型スタイル: map, filter, flatMap などを活用したチェーン処理が可能。
Optionalの作成
Optionalは主に2つのファクトリーメソッドを使って生成します。
- Optional.of(T value):
- 値が必ず非nullであることを期待します。
- nullを渡すと、NullPointerExceptionが発生します。
- Optional.ofNullable(T value):
- 値がnullの場合は空のOptional(Optional.empty())を返し、非nullの場合は値を保持します。
作成例:
// Method that processes an input string and returns an Optional.
public static Optional<String> processValue(String input) {
// Return empty if input is null or blank
if (input == null || input.trim().isEmpty()) {
return Optional.empty();
}
// Otherwise, return a trimmed value wrapped in an Optional
return Optional.of(input.trim());
}
Optionalの利用方法
Optionalの利用は主に以下のユースケースに分類されます。
-
値の存在チェック
- isPresent() / isEmpty():
- 値が存在するかどうかを確認する。
- 例: if (optional.isPresent()) { ... }
- isPresent() / isEmpty():
-
値の取得
- get():
- 値が存在する場合に返すが、存在しない場合はNoSuchElementExceptionをスローします。
- 注意: 直接get()を使うのはリスクがあるため、他のメソッドと組み合わせることが望ましい。
- orElse(defaultValue):
- 値が存在しない場合にデフォルト値を返します。
- orElseThrow(exceptionSupplier):
- Optionalが空の場合に、指定した例外をスローします。
- get():
-
値の処理
- ifPresent(Consumer):
- 値が存在する場合に、Consumer(値を受け取って何らかの処理を行うラムダ式)を実行します。
- ifPresentOrElse(Consumer, Runnable):
- 値が存在する場合はConsumerを、存在しない場合はRunnable(引数を取らない処理)を実行します。
- ifPresent(Consumer):
-
Optionalのチェーン処理
- map(Function):
- 値が存在する場合に、Functionを適用し結果を新しいOptionalとして返します。
- filter(Predicate):
- 値が条件を満たすかどうかをチェックし、満たさない場合は空のOptionalを返します。
- flatMap(Function):
- ネストされたOptionalの解除に利用します。
- or(Supplier):
- Optionalが空の場合に、新たなOptionalを返すために利用します。
- map(Function):
利用例:
String value1 = " Hello, World! ";
Optional<String> opt1 = processValue(value1);
// 存在チェック
if (opt1.isPresent()) {
System.out.println("Value exists!");
} else {
System.out.println("Value is empty.");
}
// 値の取得
try {
// 値がなければ例外がスローされる
String result = opt1.orElseThrow(() -> new IllegalStateException("Value is empty"));
System.out.println("Result: " + result);
} catch (IllegalStateException ex) {
System.err.println(ex.getMessage());
}
// デフォルト値を利用
String defaultResult = opt1.orElse("Default Value");
System.out.println("Default Result: " + defaultResult);
// 値の処理
opt1.ifPresent(val -> System.out.println("Processed value1: " + val));
// ifPresentOrElseを使用して、存在する場合は処理し、存在しない場合は別の処理を実行
opt1.ifPresentOrElse(
val -> System.out.println("Processed value1: " + val),
() -> System.out.println("Value is empty")
);
// チェーン処理:変換とフィルタ
Optional<Integer> lengthOpt = opt1
.map(String::toUpperCase) // 値を大文字に変換
.filter(val -> val.length() > 10) // 長さが10より大きいかフィルター
.map(String::length); // 文字列の長さを取得
lengthOpt.ifPresent(len -> System.out.println("Length of processed value: " + len));
// orを使用して、Optionalが空の場合に代替値を提供
Optional<String> opt2 = opt1.or(() -> Optional.of("Default Greeting"));
System.out.println("Result from opt2: " + opt2.get());
Optionalのベストプラクティス
-
戻り値としての利用:
- Optionalはメソッドの戻り値に利用し、値が存在しない可能性を明示する。
-
メソッド引数としては使用しない:
- Optionalを引数にすると、呼び出し側に無駄なラッピングを強いるため、シンプルなnullチェックやオーバーロード、あるいは別のパラメータ設計を検討する。
-
直接get()の使用を避ける:
- 値の取得はorElse, orElseThrow, ifPresentなどのメソッドを利用して、安全に扱う。
-
不必要なオブジェクト生成を避ける:
- チェーン操作を利用して、コードをシンプルに保つ。
Python Development Setup, pyenv, uv
This article introduce how to setup python development environment for Web development.
For data science / machine learning development environment, you might prefer other approaches, like anaconda.
Details
Install uv
US is the modern solution and handles both Python versions AND package management. It's like having nvm + npm in one tool.
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
Use uv
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install and use Python
uv python install 3.12
uv python pin 3.12 # Sets Python version for project
Use uv to initialize the project
cd my-project
uv init --python 3.12
Then the following files are generated:
tree
├── main.py
├── pyproject.toml
└── README.md
pyproject.toml is just like package.json
You can use
# install deps
# it automatically use venv
uv sync
# add new package
uv add fastapi sqlalchemy alembic
Check the pyproject.toml file's
If want to init a fastapi project, using fastapi's template here might be a better choice.
git clone [email protected]:fastapi/full-stack-fastapi-template.git my-full-stack
cd my-full-stack
git remote set-url origin [email protected]:octocat/my-full-stack.git
git push -u origin master
Git Cheat Sheet
問題の背景
チームで開発する際、よくあるパターンとして、
- developブランチから、featureブランチAを切って実装、PullRequestを作成し、レビュー待ち
- その間に、featureブランチAにfeatureブランチBを切って、新しい機能を実装します
- featureブランチAのレビューを経て承認され、スカッシュマージによってdevelopブランチへ統合され
- この時、featureブランチBのコミットがfeatureブランチAの元のコミットに含まれてしまうことがあって、developブランチと多くのマージコンフリクトが発生してしまいました。
問題発生の原因
- スカッシュマージによって個々のコミットがまとめられたため、ブランチBには依然としてブランチAの個々の変更が残っていること
- その結果、developブランチに既に存在するスカッシュコミットとブランチBの変更が重複して適用され、コンフリクトが発生したこと
解決策:リベースによる解決
ブランチBをブランチA由来のコミットを取り除いて、developブランチ上のスカッシュコミットに合わせてリベースすることで、効率よく解決できます。
具体的には、以下の手順で行います:
git checkout feature/branch-b
git rebase --onto develop HASH_BASE feature/branch-b
このコマンドは、ブランチ B の中で HASH_BASE より後のコミットだけを、develop ブランチ上に再適用します。 HASH_BASEは、ブランチ A が develop から分岐した時点のコミットハッシュにすると、元ブランチ A のコミットがブランチ B に含まれなくなります。
リベース中にコンフリクトが発生した場合、各コンフリクト箇所で適切に修正し、 以下のコマンドでリベースを続行します。
git add <修正済みファイル>
git rebase --continue
リベースが正常に完了したら、ブランチ B の変更を develop ブランチへPRを作成してマージしましょう。
この方法により、履歴がクリーンになり、将来的なマージやデバッグ作業が大幅に楽になります。
Remote ブランチにコミットしました
問題の背景
リモートブランチをLocalにFetchせずに、チェックアウトし、
git checkout origin/branch-a
をすると、そのまま作業し、コミットしたら、プッシュできない。下記のエラーメッセージ表示されました:
error: src refspec feature/branch does not match any
error: failed to push some refs to 'github.com:organization/project.git'
問題発生の原因
Fetchが忘れて、RemoteブランチをCheckoutするとき、実際のHEADはそのブランチではなく、detached HEADの状態です。 すると、ブランチに所属せず、特定のコミットを指している状態です。
git checkout origin/main
# または
git checkout <コミットID>
HEAD → origin/main の最新コミットを直接指す(ローカルブランチではない)
ブランチは指していない
→ この状態でコミットすると、その履歴はどのブランチにも属しません。
そのまま作業して、コミットできるか、そのコミットはブランチ属していない、浮いた状態です。
git log
, git reflog
で確認できますが、後で消える可能性がある
あくまで一時的な作業や、過去のコミットを試す時に使うモード
解決策
- ブランチからそのコミットハッシュをcherry-pickしたら解決
git log
# copy the コミット hash abc1234
git checkout branch
git cherry-pick abc1234
git push origin branch
- このコミットから新しいブランチを作成で解決
git branch feature/tmp abc1234
リベースの後で--force-with-lease
でプッシュ
git rebaseの後、--force でプッシュが必要でしょう。 このとき、--force-with-leaseでプッシュするとより安全にプッシュできます。
git push --force-with-lease
すべてのCommitを一つにする
GitHubで他の人が作ったボイラープレートをクローンして、自分のプロジェクトを始めることはよくあります。しかし、元のコミット履歴は不要なので、削除したほうがよいでしょう。 以下の手順でクリーンなリポジトリを作成できます:
方法1: 履歴のない新しいブランチを作成
# Navigate to your repository
cd your-repo
# Create a new orphan branch (no commit history)
git checkout --orphan clean-master
# Add all files
git add -A
# Create the first commit
git commit -m "Initial commit"
# Delete the old master branch
git branch -D master
# Rename the current branch to master
git branch -m master
# Force push to your remote repository
git push -f origin master
方法2: .gitフォルダを削除して再初期化
# Navigate to your repository
cd your-repo
# Remove the .git folder (this deletes all history)
rm -rf .git
# Initialize a new repository
git init
# Add all files
git add -A
# Create the first commit
git commit -m "Initial commit"
# Add your remote repository
git remote add origin https://github.com/yourusername/your-repo.git
# Push to your repository
git push -u origin master
google-analtyics-add-custom-properties
- Setting deviceId as a user property via gtag('set', 'user_properties', {'deviceId': deviceId}); means it will be associated with all subsequent events, including automatic ones. This is generally the recommended way to handle persistent user-level identifiers.
The custom_map in the config call within ClientTrackingInitializer (window.gtag('config', GA_TRACKING_ID, {'custom_map': {'dimension1': 'deviceId'}})) is used to map an event parameter or user property named deviceId to a custom dimension (in this case, dimension1) in your GA4 reports. For this to effectively map a user property, the custom dimension in
GA4 should be user-scoped.
Why this setup should generally work for your goal:
When gtag('set', 'user_properties', {'deviceId': deviceId}) is called, any events fired after this (including automatic page_view events if this set happens before the config that triggers them, or subsequent page_view events on SPA navigations) will have this user property associated.
User properties are automatically sent with events to GA4.
what-to-verification
意思決定の全てはROI
複数人が関わっているプロジェクトのやり方、難易度はグッと上がるです。 なぜなら、人々のコミュニケーション、すり合わせ、タスク間の依存関係、を考えなければならないです。しかもこれらのプロジェクトのインパクトが高い、できれば大きな利益が出る、うまくできないと大きな損失が出る可能性があるのできちんと管理する必要があります。
チームでのプロジェクトの進め方は、個人プロジェクトの管理方法に加えて、以下三つの要点があります:
- プロジェクトを分解をする
- MECEで分解
- 前後依頼を確定
- 各タスクを関与する人を確定、評価するかどうかを確定
- 各マイルストーンの確認時点を定める
プロジェクト管理についての理解1、一人プロジェクト
これまでいくつかの会社で、さまざまなプロジェクトの管理やリードに関わってきました。
その中で得た知見を、将来の自分のためにも簡単にまとめておきたいと思います。
プロジェクトとは、「限られたリソースを使い、限られた期間で、特定の目的を達成する取り組み」です。
その目的を実現するためには、適切な管理が欠かせません。
プロジェクトの規模によって管理方法は大きく異なるため、私は以下の3つに分類できると考えています。
- 一人プロジェクト
- チームプロジェクト
- 複数組織が関わるプロジェクト
今回はこの中でも、「一人プロジェクト」の管理についてまとめてみます。
一人プロジェクトとは?
プロジェクトの定義を広く捉えれば、さまざまな取り組みがプロジェクトとして扱えます。
たとえば、以下のようなものも一人プロジェクトに該当します。
- 個人旅行の計画
- ブログの運営
- 上司に依頼された勉強会の企画
一人で進めるプロジェクトは、特に管理が軽視されがちです。
単なるタスクのように感覚的に進めてしまうことも多いでしょう。
しかし、「これはプロジェクトだ」と意識し、適切に管理することで、より楽しく、より良い結果を得ることができます。
一人プロジェクト管理で意識すべき3つのポイント
1. 目的を明確にする
- 「なぜそれをやるのか?」を繰り返し問いかけ、問題を言語化します。
- 曖昧なまま進めると、途中で迷子になったり、やり直しが発生したりします。
特に他人から頼まれたプロジェクトでは、目的が明確にされていないことが多いです。
例:勉強会の幹事を任された場合
- チームのコミュニケーションを活性化するため?
- AIなど最先端技術を学ぶ場として?
- プレゼン能力を伸ばすため?
- チームカルチャーを育てるため?
目的によって、トピック選定、参加メンバー、運営方針がすべて変わってきます。
だからこそ、最初に目的を明確にすることが最重要です。
2. マイルストーンに分解する
- タスクが小さく見えても、実際は難しい部分や不確実な要素が隠れていることがあります。
- あらかじめ全体像を把握し、マイルストーン(節目)に分解しておくことで、計画的に進めることができます。
また、マイルストーンは進捗の報告タイミングとしても活用できます。
3. 報連相(報告・連絡・相談)を怠らない
一人で進めるからこそ、「見える化」が重要です。
上司や依頼者に対して、今どこまで進んでいるか・どんな課題があるかを適切に共有しましょう。
これには以下のメリットがあります:
- 認識違いがあっても、早い段階で軌道修正できる
- 環境や要件の変化にも柔軟に対応できる
- 自分の成果が評価されやすくなる
おわりに
一人で動くプロジェクトこそ、意識的に「プロジェクト」として扱うことで成果が変わってきます。
- 目的の明確化
- マイルストーンの設計
- 可視化と報連相
この3つを意識すれば、小さな取り組みでも効果的に、そして気持ちよく進めることができるでしょう。
Redis
一文でRedisの機能やユースケースをまとめてみる。
Redis とは
Redisは様々なデータ構造に対応したインメモリデータストアです。
具体的に言うと、下記のデータ構造を対応しています:
- Strings (simple binary-safe blobs)
- Lists (linked lists, with operations like LPUSH, LRANGE, etc.)
- Hashes (maps/dictionaries of field→value pairs)
- Sets (unordered collections of unique elements)
- Sorted Sets (elements ordered by a score, i.e. your “sorted array”)
- Bitmaps (compact bit arrays)
- HyperLogLogs (probabilistic cardinality counters)
- Streams (append-only log data structures)
- Geospatial indexes (store and query latitude/longitude points)
データ構造の対応ではなくて、便利な操作機能も提供しており、普段のデータベースで実装しにくい機能を簡単に実装できます。