mongolyyのブログ

開発(Javascript, Typescript, React, Next.js)や開発手法(スクラム, アジャイル)、勉強したことについて色々書ければと。

チームに新規参画のソフトウェア開発者を受け入れる時にやると良いこと 5つ

はじめに

メーカーのコーポレート部門でソフトウェアエンジニアとして働いているモンゴルです。
新人を受け入れるときにやるといいと思ったことがいくつかあったので紹介したいと思います。

アクティビティ

個性によって効果は異なりますが、万人におすすめできるアクティビティを紹介したいと思います。

ペアプロ

言わずもがなですね。
レビューだけでは伝えられない、開発のテクニック、ツールの使い方、開発時の考え方も自然と伝えることできるので非常に効果は高いです。
新規参画者のキャラクターによって、「最初の方にやるか」「ちょっと慣れてきてからやるか」は判断すると良いと思います。新規参画者、チームメンバーと相談して決めると良いでしょう。

一方、ペアプロに抵抗がある人もいます。後述のバディプログラミングから始めるのもおすすめです。

わかったことをメモしてもらう

「わからないことあったら聞いてねー」と受け入れる側はよく言いますが、新規参画者側は「何がわかっていないかわからない」状態であったり、見栄を張ってしまい「わからないことが共有できない」状態であることがよくあります。
わかったことを書いてもらうことで、新規参画者側はわかっている/わかっていないことの意思表示、受け入れ側は何が伝えられていないかの情報収集ができて双方にとって良い活動となります。

メモの方法はSlackでスレッドを作るなり、社内wikiにそういうページを作るなり、何でもいいと思います。新規参画者、チームメンバーと相談して決めると良いでしょう。

視点は異なりますがこちらのブログも参考になります。

note.com

また、新規参画者側も受け入れ側も、学ぶときの姿勢について考え直せるとより良いと思っています。

mm.hyuki.net

バディプログラミング

「レガシーコードからの脱却」という本で紹介されているアクティビティになります。
やり方ですが、書籍の中では次のように紹介されています。

バディプログラミングではほとんどの時間は1人で仕事をする。 1日の最後のたとえば1時間だけ、バディと一緒に今日それぞれが完成させたコードをレビューする。

このアクティビティにより、ペアプロに抵抗がある新規参画者、忙しいチームメンバーという環境であっても、ペアプロや知の移転を推進するきっかけづくりができるようになります。

mongolyy.hatenablog.com

受け入れる側の準備

準備も色々ありますが、次のものはしっかりやると、その分効果があると感じています。

プロジェクト、プロダクトの全体像、チームを知るためのリンク集を作る

リンク集を渡してもしっかり理解できないケースが多いですが、新規参画者側から求められることも多いので用意しておくといいでしょう。
受け入れる側の知識の整理になるので、受け入れ側のメリットが大きい活動だと感じています。

割当予定の課題を整理する

時間がなくてあまり深く考えずに決めてしまうことがありましたが、ここはある程度準備していたほうが、新規参画者にとっても受け入れる側にとっても互いにうまくいくと思っています。
次の順番で徐々に難しい課題を割当していくといいと思っています。

  1. 【開発のフローに慣れる】ドメイン知識が不要で、やり方も確立されていて、1時間以内で対応できる課題。
  2. 【コードの構造に慣れる・テストの書き方に慣れる】ドメイン知識が不要で、やり方も確立されているもの、特定の数ファイルだけ修正するだけで対応できる課題。できれば、フロント、サーバーサイドをそれぞれ、1,2個ずつできると良い。
  3. ドメイン知識に慣れる】ドメイン知識が少し入ってくる課題。ビジネスロジックの修正等が良い。
  4. 【コードの全体を把握する】1~2日で対応が完了する、1機能を追加する課題。案外時間がかかる場合もあるので、緊急度が低いものであると良い。

エンジニアのレベルによっては、飛ばしてもいいステップもあると思います。
大事なのは、目的意識を持って段階的に課題をアサインしていくことで、これにより、双方でストレスを抱えずに、ステップアップできると考えています。

おわりに

みなさんも、「こういうのやるとよかったよ!」とかあれば教えていただけると嬉しいです!

Next.js + TypeScript + NextAuth + AzureAD B2Cの組み合わせを試す

はじめに

認証基盤といえば手軽に使えるAuth0が好きですが、会社の状況によっては使えないことがあると思います。

NextAuthを使いつつ、色々なIdPを試してみようと思いますが、今回はナレッジが少なそうなAzureAD B2Cを試してみようと思います。

まずはいつもの

yarn create next-app --typescript

をします。

プロジェクトのディレクトリに移動し、

yarn add -D next-auth

します。

Azure AD B2Cの設定

docs.microsoft.com

docs.microsoft.com

docs.microsoft.com

をもとに設定します。設定するときに次の設定はどこかにコピペしておくようにします。

  • テナント(場所によってはディレクトリと表現)作成時に入力する、テナント名(場所によっては組織名と表現)
  • 登録したアプリのアプリケーション名(Azureによって採番された、a90abcd...のようなuuid形式のようなID)
  • 登録したアプリに対するクライアントシークレットの値
  • ユーザーフローの名前

アプリのリダイレクトURIは次の値を設定します。

  • https://jwt.ms
  • http://localhost:3000/api/auth/callback/azure-ad-b2c
  • https://<本番環境のドメイン>/api/auth/callback/azure-ad-b2c

ユーザーフローの「ユーザー属性とトークン要求」では次のように設定します。

.env.localの設定

AZURE_AD_B2C_TENANT_NAME=<テナント名>
AZURE_AD_B2C_CLIENT_ID=<アプリケーション名>
AZURE_AD_B2C_CLIENT_SECRET=<クライアントシークレットの値>
AZURE_AD_B2C_PRIMARY_USER_FLOW=<ユーザーフローの名前>

NEXTAUTH_SECRET=<任意のランダム文字列>

公式ドキュメントで紹介されていますが、NEXTAUTH_SECRETopenssl rand -base64 32 コマンドで作ると良さそうです。 Options | NextAuth.js

Providerの設定

ドキュメントをもとに次のようなファイルを作成しました。

import AzureADB2CProvider from "next-auth/providers/azure-ad-b2c"
import NextAuth from 'next-auth'

export default NextAuth({
  providers: [
    AzureADB2CProvider({
      tenantId: process.env.AZURE_AD_B2C_TENANT_NAME,
      clientId: process.env.AZURE_AD_B2C_CLIENT_ID,
      clientSecret: process.env.AZURE_AD_B2C_CLIENT_SECRET,
      primaryUserFlow: process.env.AZURE_AD_B2C_PRIMARY_USER_FLOW,
      authorization: { params: { scope: "offline_access openid" } },
    }),
  ]
})

IDEで次のようなwarningが表示されました。

process.env.AZURE_AD_B2C_TENANT_NAMEstring | undefined であることにかかわらず、providerのオプションの tenantIdstring になっているせいで発生しています。
process.env.AZURE_AD_B2C_TENANT_NAME が設定されていないときにアプリは起動したくないので、起動時にチェックすることで、tenantId としては必ず string が渡されるようにします。

起動時のチェックは、次の記事を参考にしました。

zenn.dev

結果、次のような実装になります。

import AzureADB2CProvider from "next-auth/providers/azure-ad-b2c"
import NextAuth from 'next-auth'

if (!process.env.AZURE_AD_B2C_TENANT_NAME || !process.env.AZURE_AD_B2C_CLIENT_ID || !process.env.AZURE_AD_B2C_CLIENT_SECRET || !process.env.AZURE_AD_B2C_PRIMARY_USER_FLOW) {
  console.error('Azure AD B2Cの環境変数が設定されていません!')
  process.exit()
}

export default NextAuth({
  providers: [
    AzureADB2CProvider({
      tenantId: process.env.AZURE_AD_B2C_TENANT_NAME,
      clientId: process.env.AZURE_AD_B2C_CLIENT_ID,
      clientSecret: process.env.AZURE_AD_B2C_CLIENT_SECRET,
      primaryUserFlow: process.env.AZURE_AD_B2C_PRIMARY_USER_FLOW,
      authorization: { params: { scope: "offline_access openid" } },
    }),
  ]
})

認証をmiddlewareで実装する

Next.jsで最近追加されたmiddlewareで認証を実装します。 nextjs.org

export { default } from "next-auth/middleware"

これだけです!

トップページでユーザー名を表示できるようにする

_app.tsxSessionProvider コンポーネントを追加します。

import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { SessionProvider } from 'next-auth/react'

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <SessionProvider>
      <Component {...pageProps} />
    </SessionProvider>
  )
}

export default MyApp

トップページで表示名を表示するようにします。

import type { NextPage } from 'next'
import styles from '../styles/Home.module.css'
import { useSession } from 'next-auth/react'

const Home: NextPage = () => {
  const { data: session, status } = useSession()

  if (status === 'loading') {
    return (
      <div className={styles.container}>
        <main className={styles.main}>
          <h1 className={styles.title}>
            読み込み中
          </h1>
        </main>
      </div>
    )
  }

  if (status === 'unauthenticated') {
    return (
      <div className={styles.container}>
        <main className={styles.main}>
          認証に失敗しました
        </main>
      </div>
    )
  }

  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <h1 className={styles.title}>
          Welcome {session?.user?.name}!!
        </h1>
      </main>
    </div>
  )
}

export default Home

動作確認

next dev で起動し、 http://localhost:3000 にアクセスしてみると、、

サインイン用の画面が出ました!
(Providerが一つしかないのは、もの寂しいですね、、)

ボタンをクリックするとサインイン画面が表示されます

Sign up now」からユーザーを作ってサインインします。 (うまくいかないときは他のログインが残っていることがあるので、シークレットブラウザで試すといいかも)

サインインできました!!

おわりに

今回、デフォルトの設定に従って、プロバイダの選択画面とAzure AD B2Cサインイン画面を表示していましたが、next-auth/reactsignIn 関数を呼び出すことによって、この画面(プロバイダの選択画面)をスキップするという技もあります。

github.com

普通に使えますが、標準でデフォルトのプロバイダが選べるようになるといいなと、思います。

github.com

あと、個人的にはAzureの独特の日本語に苦しめられました。。笑

今回のコードのリポジトリはこちらです。 github.com

「プロを目指す人のためのTypeScript入門」を読んだ

はじめに

こんにちは。mongolyyです。
近頃TypeScriptを触っているのですが、先月、次の本が出版されたので読んでみました。
感想を書いていこうと思います。

感想

TypeScriptの型システムがちょっとわかった

今までも触っていてなんとなくでやっていてしまった部分が、よく理解できました。
特に、

  • ランタイムの挙動が型情報に依存しないこと
  • 他のオブジェクト指向の言語と異なり、名前的部分型ではなく、構造的部分型というアプローチを取っていること

という点については、色々な観点から繰り返し語られており、よく理解できました。

本書を読む前までは、TypeScriptの型をなんとなく過信してしまったり、構造的部分型の部分に違和感を抱いていましたが、本書を通じてTypeScriptの仕組みや思想が理解でき、今後特徴を理解しながらうまく使っていけるように感じました。

コラムが興味深かった

こっちのほうがいいといった話が非常にためになる話が多かったです。
特に、「変数名の名前空間と型名の名前空間」や「privateと#の差異」の話は実用的だったり、視野を広げる話で良かったです。
TypeScript中級者の方は気になる章やコラムだけ読むという読み方でも十分学べるように感じました。

おわりに

以前読んだ

では、言語仕様の説明に重きが置かれていましたが、本書ではTypeScriptの型システムの特徴や、実プロジェクトでどう使うかというところが書かれており、違った視点で学びがあり、良かったです。

また、本書では、「力試し」という節があり、それをやることで読書にメリハリができて良かったです。

「良いコード/悪いコードで学ぶ設計入門-保守しやすい 成長し続けるコードの書き方」を読んだら、次の日からその知識が役に立った

はじめに

「良いコード/悪いコードで学ぶ設計入門-保守しやすい 成長し続けるコードの書き方」が先日出版されたので、GWに読みました。 その感想を書いていこうと思います。

感想

サンプルがあってわかりやすい

悪い例、良い例が両方とも書かれており、かつ、それらの例に対しての著者の経験を基にした考えが書いてあり、非常にわかりやすく、読みやすかったです。

本書では、今までClean Architectureやリファクタリング本で紹介されてきた設計原則を取り扱いつつも、一歩踏み込んで、実プロジェクトで発生してきたことベースで語られており、あるある度やわかりやすさは高く、現在の業務にすぐ活かせるように感じました。
特に、「5.5 多すぎる引数」や「8.2.1 継承に絡む密結合」、「8.2.5 高凝集の誤解から来る密結合」の章は自分も今まで何度かやってきてしまっていたり、見かけても放置してしまったことがあるなーと、ドキッとしました。

「8.2.1 継承に絡む密結合」については、他の方からも「継承より委譲を」と、言われたばっかりであったこともあり、改めて大事さを感じました。

今後の学習の指針となる

参考書籍や、勉強するときの心構えなどが書いてあって、初級者から一歩進んだ方から、設計に取り組み始める若手におすすめしたいと感じ、また、中堅以上の方も抜けている知識を補完するために役立つと感じました。

おわりに

繰り返しになりますが、著者の熱い想いが詰まっていて非常に読み応えがありました。
自分も心あたりがあるところがあったので、読んだ翌日から現場での得た知見を活かして業務をしていました。(今まで継承で実装していたであろう箇所を委譲を使用して実装していました)

基礎ができているエンジニアの方で、もう一歩成長していきたいという方におすすめの一冊でした。

「入門!論理学」を読んだら、論理学の考え方が少しわかった

はじめに

きしださんのこちらの記事を参考に、型理論を理解したいと考え、まずは「入門!論理学」を読んでみました。
感想を書いていこうと思います。

nowokay.hatenablog.com

読んでみてどうだったか?

論理学の考え方や、用語を理解できた

論理学での話の組み立て方、また、排中律、連言、選言、導入、除去、全称、存在と言った論理学の言葉について理解できました。
概念としてはもともと知っているものもありましたが、本書では、論理学としてどう捉えられているかというのが、わかり易い言葉で、深く説明されていて非常に読み応えがありました。

その中でも、「排中律」を認めるかどうかが論理学の中で議論されることの一つという話が興味深かったです。
排中律は、"Aである"が正の場合は"Aではない"は偽になり、逆に"Aである"が偽の場合は、"Aではない"は正である、という意味なのですが、プログラムを書いている上では当たり前なのですが、実生活では、証拠不十分でどちらかと断定するのは難しい場合があるんですよね。
本書では「排中律」が成り立たない例をいくつか紹介されていて非常にわかりやすかったんですが、同時に、普段自分たちが当たり前として捉えている考え方は、案外脆いものでもある、ということに気付かされました。

また、軽くしか紹介されていませんでしたが、「ゲーデル不完全性定理」についても興味深かったです。
今まで数学はいくつかの公理の上で、すべての命題について証明可能だと思っていましたが、そうではない(≒不完全性がある)ということを知り、「ほえー」と思いました。(これも正確な理解ではないかもしれませんが汗)

おわりに

本書で論理学を知って、今までの自分の考えはある枠組みの中で定義されたことであったと知りつつ、考えを広げてみると、「そもそも〇〇とは?」みたいな哲学的な方向性に考えにいきついたり、一方、数学やプログラミングとの結びつきも深く、論理学は領域横断的な基礎分野だなーと感じました。

本書は丁寧であるものの、論理学自体始めてだったこともあり、途中で何がわかっていて、何がわかっていないか、よくわからなくなる時がありました。 ただ、そういうタイミングに、本書では今までの理解を確かめたり、今までの理解を発展させた練習問題が出てきていて、それにより迷子にならずに読み進めることができました。
論理学難しそう、、という、初心者の方におすすめの本でした。

テストも書かずにリファクタリングとは何事か

はじめに

知人と話していて、「レガシーコードをメンテナンスしており、リファクタリングをしているが、テストは書いていない」という話を聞いて、それは違うのではないか?と思ったので、ポエムを書こうと思います

書いていることは、大体「リファクタリング」本や「レガシーソフトウェア改善ガイド」「レガシーコード改善ガイド」に書いてあることなので、まずはこれらを読みましょう。

リファクタリングとはなにか?

外から見たときの振る舞いを変えずに、内部の構造を変えることです。

外から見たときの振る舞いを変えずに、というのを検証するためにテストが必要になってきます。

テストを書かなかった場合に、どんな問題があるか?

テストを書かなかったときの問題点①

壊していても気づかない。気づけない。

テストを書かなかったときの問題点②

良い設計になっているか検証できない。 悪い設計になっている特徴として、テスタビリティが低いというのがあると思っています。 リファクタリングしたと思ったけれど、逆リファクタリングデグレさせている可能性さえあります。

レガシーコード(テストがない)の場合の対処法

個人的には以下の選択肢があると思っています

終わりに

テストが書けないと言っている場合も、よくよく見てみるとテストをかける場合が多いと思っています。 また、こんな面倒なことにしないためにも、最初からテストを書いておきましょう。

React系のライブラリにおいて、ts/tsxをトランスパイラーとして、何が使用されているのか調査してみた

はじめに

「Reactを使っている場合はjsxをトランスフォームするためにbabelを使用するのはわかるが、React + TypeScriptの組み合わせを使っている場合、tscでトランスパイルすれば、tsxのトランスフォームもtscがしくてれて、babel使わなくていいんじゃないの?」と知人から聞かれて、たしかにそうだなーと思いつつ、プロダクトでは babel や最近は esbuildswc を使っていることが多くて、tsc を使うことは少ない気がする(というか見たことない)と思ったので調べてみました。

まずReactの環境をどう構築するのか問題

次期公式ドキュメントになるであろう React Docs beta の中では、次の方法が紹介されています。

  • Create React App
  • Vite
  • parcel
  • snowpack
  • Next.js
  • Gatsby
  • Razzle

beta.reactjs.org

それぞれどういったトランスパイラーを使用しているか

感想

やはり babel を使用していることがそこそこ多く、 tsc は存在しなかったですね。tsx→jsだけでなく、jsx→jsの変換もしようとすると、 babel を採用するのは納得できるなーといった感じです。

多いですね。一方、最近出てきた esbuildswc はバンドルが可能であったり、トランスパイル自体早いものの、babelのプラグインが必要だったライブラリは移行しづらく、 swc のメンテナーをvercelが採用したのも、このbabel依存を剥がすためにはそのくらい本気で取り組まないと進まないんだなーと感じました。

今後、 esbuildswc 、あと、今回は出てきていませんが all-in-oneな rome のどれがディファクトスタンダードになるか、見守っていきたいと思います