サイボウズ株式会社の「kintoneフロントエンド」コースにて、2025年8月18日から2025年8月29日の2週間にかけて、インターンをさせていただきました。
少し時間が経ってしまいましたが、この記事はその振り返りです。
やったこと
kintone のフロントエンド刷新の一環として、kintone のカレンダービューの部分を Closure Library から React に書き換えるということを、もう一人のインターン生と共に行いました。
その中でも私はロジック部分を主に担当し、もう一人のインターン生がデザイン部分を主に担当しました。
具体的には次のとおりです。
- 選択している年月に合わせてカレンダーを表示する
- 選択している年月に合わせてデータを取得する(タイムゾーンを考慮したAPI呼び出し)
- 取得したデータをカレンダーに表示する(日時フィールドの正確な表示)
データ周りの肝となる部分を担当させてもらいました。
実装で躓いたところ
日付時刻の計算
カレンダーの選択している年月に合わせてデータを取得する際、タイムゾーンについて考慮する必要がありました。
kintone では、利用者のシステムタイムゾーンとは異なるタイムゾーンを設定できるようになっています(日本にいても JST (UTC+9) ではなく PST (UTC-8) などの別地域のタイムゾーンに設定可能)。そのため、システムタイムゾーンと UTC しかサポートしない JavaScript の標準 Date API だけでは、時差を正確に計算することが困難です。
この問題に対処する方法として、以下の2つの選択肢があります。
- ライブラリ利用: Day.js や date-fns などのタイムゾーンデータを持つライブラリを使う
- バックエンド連携: バックエンドからタイムゾーン情報を受け取る
kintone では歴史的経緯もあり、後者を採用しています。
具体的には、日時データは UTC でバックエンドから渡され、それに加えてタイムゾーン設定を加味した時差データも受け取ります。フロントエンド側ではこれらを組み合わせて「UTC のデータ(保存データ)+ 時差情報(サーバから)→ ユーザーのタイムゾーンに合わせた日時表示」という計算を独自に行っています。
このため、既存実装を参考にしつつ、テストを書いてひたすら試すということを行いました。
かなり複雑だったのですが、テスト駆動開発で行ったおかげで、余計な手戻りを最小限にしつつ、実装できたと思います。
useState の仕様理解不足による無限ループ
useState の初期化方法が原因で、意図せず再レンダリングの無限ループを引き起こしてしまいました。
年月データのパースエラー時に通知を出す処理を実装する際、useState の初期値を生成する関数内にその処理を実装し、その関数の実行結果を渡していました。
// NG: レンダリングのたびに関数が実行される
// 関数の実行結果を渡している
const [todos, setTodos] = useState(createInitialTodos());
このように記述すると、コンポーネントが再レンダリングされるたびに関数が再実行されます。私のコードでは、この関数内でstateを更新する副作用(通知処理)があったため、「state更新 → 再レンダリング → 関数実行」という無限ループに陥っていました。
関数そのものを渡すことで、Reactが初回レンダリング時に一度だけ実行してくれます。
初期 state が再生成されることを防ぐ
// OK: 初回レンダリング時のみ実行される
// 関数そのものを渡している
const [todos, setTodos] = useState(createInitialTodos);
この失敗は、Reactのレンダリングの仕組みやパフォーマンスに関する理解を深める良い機会となりました。公式ドキュメントを正しく読み解き、なぜそう書くのかを意識してコードを書くことの重要性を痛感しました。
DOM表示の制御
DOM表示の制御に && を用いるとき、判定条件によっては実装意図に反する値が表示されてしまいます。
これは、schedules という配列が存在し、かつ指定した件数以上のデータがある場合にその件数を表示するというコードです。
import type { FC } from "react";
interface Props {
schedules?: string[];
minCount?: number;
}
const Notification: FC<Props> = ({ schedules, minCount = 1 }) => {
return schedules?.length && schedules.length >= minCount && <span>予定が{schedules.length}件あります。</span>;
};
const Sample: FC = () => {
return (
<>
<div>
<h2>予定が1件以上ある場合</h2>
<Notification schedules={["予定1", "予定2"]} minCount={1} />
</div>
<div>
<h2>予定が0件の場合</h2>
<Notification schedules={[]} minCount={1} />
</div>
</>
);
};
export default Sample;
予定が指定件数以上ある場合は、「予定が〜件あります」と表示され、それ未満の場合は表示されないようにしたかったのですが、実際に表示してみると次のようになります。
schedules が空配列で渡されてしまうと、schedules.length は 0 であるため、falsy となり、そのまま 0 が返されてレンダリングされてしまいます。
最初は三項演算子で falsy のときに null を返すようにして修正したのですが、
schedules?.length && schedules.length >= minCount ? <span>予定が{schedules.length}件あります。</span> : null;
最終的には、schedules が undefined でないことをこの実装より手前でチェックすることで、より根本的な修正を行いました。
TypeScript では、false, undefined, null 以外にも、0 や NaN も falsy として扱われます。また、&& が絡んだ条件式が途中で false となったときは、その falsy な値が返ってきます。
この2点を意識していなかったために、躓いてしまった出来事でした。
Falsy (偽値) - MDN Web Docs 用語集 | MDN
論理積演算子 (&&) - JavaScript | MDN
React 19.2 以降では、Activity コンポーネントを用いることでも防げると思いますが、React と同様に TypeScript もしっかり理解する必要があるなと痛感した出来事になりました。
<Activity> - React
インターンで感じたこと、学びになったこと
1. テスト駆動開発について
複雑なタイムゾーン周りの実装のミスを無くすべく行ったテスト駆動開発について、品質担保のためだけでなく、実装効率を上げるためにも重要であることを痛感しました。
複雑なドメインの実装はミスも起きがちだと思います。そういったときにテスト駆動開発を行うことで、手戻りを少なくでき、実装効率が上がると感じました。また、実装ミスの箇所を即座に特定するためにも、適切な粒度で関数やフックを定義することが大切だと思いました。
2. コミュニケーションについて
2週間のオンラインでのインターンを通し、Slack を中心としたテキストコミュニケーションの経験を深めることができました。
特に印象的だったのが、ハドルの活用方法です。これまでは実装に行き詰まった際に使う程度でしたが、朝会や勉強会などでも積極的に活用していました。
テキストでの非同期なやり取りと、ハドルのような同期的な対話を目的によって使い分けることで、チーム全体の開発スピードが向上することを実感しました。今後のチーム開発でもより意識していきたいです。
3. 働き方について
オンラインでのインターンは、リモートワークという働き方をリアルに体験する貴重な機会でした。
通勤時間がないメリットは大きいものの、プライベートと仕事の物理的な境界が曖昧になるため、意識的なオン・オフの切り替えがパフォーマンスに直結すると痛感しました。リモート環境で十分なパフォーマンスを発揮するため、自己管理能力をしっかり身につけたいと思います。
4. モブプログラミングについて
正直なところ、これまでモブプログラミングのメリットをあまり実感できずにいたのですが、今回のインターンでその考えが大きく変わりました。
大規模なコードベースでは、機能の背景や仕様を知っているかどうかで、実装速度に大きな差が生まれます。知識を持っている人にサポートしてもらいながら実装を行うことで、実装を速くできるだけでなく、レビューでの手戻りも少なくなるということを感じました。
5. AI 活用について
今回の開発で私は AI ツールを使いませんでしたが、Claude を活用したモブプロを見学できたのは大きな収穫でした。
ドキュメントをどう活用するかであったり、AI と一緒にどのようにしてタスクを進めていくかの一例を知れてとても良かったです。大規模なコードベースで AI をどのように用いているのかの一例を知ることができ、とても勉強になりました。
6. アクセシビリティについて
インターン期間中の勉強会で、アクセシビリティへの理解を深めることができました。
ウェブアクセシビリティとは、障害者のためだけの特別対応ではなく、すべての人の「ウェブにアクセスできない」問題を解決するための品質なのです。
今まで、アクセシビリティは何らかの障がいを抱えた方に対するものだと思っていたのですが、様々な理由で一時的に困難が生じている人など、世の中の多種多様なすべての人に向けたものであるという点が、自分にとって全く新しい視点でした。
さいごに
2週間、実際の開発チームの一員として開発に参加させていただき、多くのことを学ぶことができました。
特にアクセシビリティについての意識が大きく変わったので、UXも意識しつつ、よりよいプロダクト開発ができるように取り組んでいきたいなと思います!
メンターやチームの方々をはじめ、関わってくださった社員の方々、本当にありがとうございました!
最後に完走証を頂きました!ありがとうございます!!
