Technote

by sizuhiko

フロントエンド・PHPカンファレンス北海道2026に参加しました

久しぶりの札幌カンファレンス参加。2024は参加できなかったので、PHPカンファレンス北海道 2019で「PHPを学ぶということ」について発表してきました 以来となりました。

ちゅんとそのときの登壇者Tシャツ着ていったけど、気づいてくれた人はいただろうか?

フロントエンド・PHPカンファレンス北海道2026に参加しました。

前日入り

プロジェクトのスクラムイベントが金曜日になっているのと、新しい案件の見積り直前であんまり休んでる場合ではなかったので、エクストリーム出社することにしました。

ちょうど昨年のPHPカンファレンス福岡のときも忙しくて、前日入りして働いてました。

そんなときも永和システムマネジメントでは東京支社のオフィスが WeWork 京橋内にあって、それ以外の拠点の利用もできるので、ほんと遠征のときは楽で良いです。今回は 6:55 の Air DO で羽田から新千歳 -> エアポート快速 で無事に10:00には仕事を始められました。

ランチどうしようかな?と調べていたら隣にビルにスープカレーの GARAKU があったので、まずの北海道メシとしては最適でした。

定時になったので、さてビール、札幌だからクラシックでは?!と思ってビールサーバーを見たらガッツポーズ出たのですが、すぐに現実に戻されました。

6月になって関東ではびっくりするぐらい暑い日があったりしたのですが、今週末は涼しかったですね。 札幌は涼しいと言うより寒いぐらいでした。事前に天気予報みて最低気温11度予報だったので、ちゃんと上着も持って。

一度ホテルへチェックインして、夜どうしようかな?と思っていたら前日入りしていた人が、こちらに参加していて面白そうだったので合流。

なんかプチ前夜祭みたいな感じになってました。

#スナックとみお 楽しかったですね。

そのあとは、その場の流れでクラフトビールを飲みにいって(僕は右斜上です。thx: @takahashiyuya

ラーメン食べて(僕は右斜上です。thx: @WP_Daisuke

なぜかそのあと、すすきのの知り合いがバイトしてる店で2:30ぐらいまで飲んでました….

カンファレンス当日

ちゃんと起きて会場入り(ギリギリだったけど….

電車で @takahashiyuya に偶然会って昨晩のラーメン後の話でアイスブレークできた感じになりましたw

午前中

オープニングセッション以降で参加したセッションは以下のとおり

PR TIMESルーム

本当はSignals の話も聞きたかったけど、ちょうど 12:30 から懇親会チケット当日販売だったので、そちらを優先してしまいました。

ランチ

少しスポンサーブースでスタンプラリーしてからランチマッチングに参加しました。

社会人PHPer3人と学生5名がマッチングされて、 PHPer x 2 & 学生 x 3、 PHPer & 学生 x 2 で移動。 ちょうど雨が降り始めていたので、会場1Fのレストランに行きましたが、すでにそこにはたくさんの同胞がw

みんな考えることは一緒ですね。ただ会場ではイベント客が来ることが想定されていなかったのか、大変そうでした。ラーサラは美味しかったです。

午後

PR TIMESルーム

その後は LT 、クロージングでした。

各セッションの感想とかはツイートしてるので、気になる方は僕のタイムラインを見てください。

そのあとは懇親会、2次会(そーだいさん取りまとめありがとうございました)と流れて、日曜日もお昼前には飛行機に乗らないといけなかったので、3次会には行かずにホテルに戻りました(なぜ 6/7 日曜日に予定を入れてしまっていたのか、半年前の自分に問いたい…)。

後日

アフターハックにも観光にも行かず、空港へ。お土産を買って五十七番で寿司食べて帰ろうと思ったら、みたことない行列ができていたので、諦めて保安所内にある早い時間からやっているお寿司屋さんへ。

食べ終わってまもなく搭乗して無事帰宅。

最後に

そして、愛車のロド号の18ヶ月検診のため、マツダのディーラーに来て作業待ち時間を使ってブログを書いてます。

セッションの感想については X にポストしているので、全体を振り返って

  • 会場がとても素晴らしかった。昔手前の産業館でPHPカンファレンスが開催されていた記憶が(参加したと思う
  • フロントエンド x PHP という、自分は仕事上はフルスタックで全部やってるけど、こういうコラボカンファレンスとても良いと思った。自分の領域と違うところを知れる機会にもなるし
  • 1分間フィードバック(ぺちおだインスパイア)が採用されていて良かった
  • 会場 Wi-Fi があって良かった
  • 懇親会のジンギスカンが楽しかった
  • とにかく北海道が最高すぎた

ということで最後に今回の北海道メシをふりかえり

  • スープカレー
  • 味噌ラーメン
  • ラーメンサラダ
  • ジンギスカン
  • 寿司
  • たくさんのビール

ということで満遍なく堪能できました。

たくさんの刺激をもらったので、明日からも仕事頑張るぞー。

また北海道のカンファレンスに参加したいです。すべての現地にいた人に感謝です。

React 共通パッケージで SVG を賢く管理する —— SVGR を活用したコンポーネント化戦略

デザインシステムの共通化などで React コンポーネントをプロジェクト横断で使うことはよくあると思います。 もしくはモノレポ構成で複数のWebアプリがあったとき、その間で利用する共通コンポーネントだったりするかもしれません。

そんなとき SVG 画像をどうやって管理したら 気持ちいいか を考えてみたので、記事にしました。

SVG のままインポートすれば良いのでは?

いや、まぁそうなんです。

Vite React (TypeScript) vite-plugin-svgr で SVG をコンポーネントとして扱う のようにプラグインを使ったり、直接 .svg をインポートできるように tsconfig を設定したりすればできなくはないです。

アプリケーション側のアセット管理であれば、それで良いと思っています。

でも共通コンポーネントパッケージとしたとき、どうやって import するかという話になってきます。 もちろん package.json の import で拡張子が .svg だったとき public フォルダを参照させるとか方法はいくらでもあります。

今回の記事では、共通コンポーネント側で JavaScript ファイルにバンドルしたときに含まれてくれることをゴールにしたいと思います。 なので、アセット参照で良いや、という方はゴメンなさい。

SVG をどうやってコンポーネント化するか

SVGR というツールを使います。これがとても便利です。

モノレポだと以下のようなディレクトリ構成になっているとします。

└── packages/
    └── components/
        ├── icons/    <-- ここにFigmaなどから取得したsvgファイルを保存
        │     └── warning.svg
        └── src/
              ├── Button/    <-- ボタンコンポーネント
              └── Icons/    <-- ここに React コンポーネント化された svg が生成される

package.json の scriptsgen:icons を設定します。

  "scripts": {
    "gen:icons": "npx @svgr/cli -d src/Icons icons"
  },

icons ディレクトリにある svg 画像がすべて React コンポーネントになって src/Icons の下に変換されます。 warning.svgWarning.tsx に変換されます。

import * as React from 'react'
import type { SVGProps } from 'react'
const SvgWarning = (props: SVGProps<SVGSVGElement>) => (
    // 実際のSVGタグが入る
)
export default SvgWarning

あとは src/Icons/index.ts を作って export すれば良いだけです。簡単ですね

export { default as Warning } from './Warning'

アプリケーション側では、共通コンポーネントを npm i してから以下のように利用します。

// 使う側のイメージ
import { Warning } from '@common/components';

const App = () => <Warning color="red" />;

この方法の最大のメリットは、SVG がただの画像ではなく「コード」として扱えるようになることです。 これにより、Tree Shaking の恩恵を受けられたり、型定義によって props の補完が効くようになったりと、開発体験が劇的に向上します。

SVG コンポーネント化すると良いこと

Custom Templates が使える。これですね。CLIのパラメータでもある程度カスタマイズできますが、テンプレートを修正する方が見通しが良いです。

たとえばアプリケーションがテーマを変更できるようになっていたとき、SVGの色を変えたいことがあります。もちろん CSS で変更できる場合もありますが、SVG側でかなり考慮されていないと難しいです。 カスタムテンプレートを使えば fill の値を props にするよう定義することもできるので、そういった需要にも柔軟に対応できます。 これは 共通コンポーネント という共通化では重要になってくるのではないでしょうか?

さらに共通コンポーネント集を作る際、悩ましいのが「各プロジェクトで微妙に異なる命名規則や型定義」です。 Custom Template を使えば、例えば IconProps という独自の型を自動で付与したり、aria-label などのアクセシビリティ属性を必須にするような出力も自由自在です。

単なる変換ツールとしてではなく、「SVG の形をした React コンポーネントを量産する工場」を定義できるのが SVGR の真価だと言えます。

さいごに

今回はSVGR というツールの紹介でした。 実際使ってみてとても便利なので、みなさんも使ってみてくださいね。

モノレポ構成の Next.js を standalone ビルドして Docker で動かす(404エラー対策)

このブログは NPM workspaces を使ったモノレポ構成のリポジトリ内にある Next.js アプリを standalone するときに注意すべき点についてまとめた記事です。

NPM workspaces を使ったモノレポ構成

たとえば以下のようなディレクトリ階層を想定しています。

  • apps/webapp : Next.js の web アプリのワークスペース
  • infra : AWS CDK など IaC コードのワークスペース
  • packages/components : React コンポーネントのワークスペース
  • packages/functions/xxxxx : AWS Lambda 関数ごとのワークスペース

これ以外にも packages の下にいろいろなパッケージを入れるような構成はよくあると思います。

Next.js アプリを standalone ビルドする

next.config.ts が以下のような感じで standalone ビルドする想定です。

import type { NextConfig } from 'next'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'

const __dirname = dirname(fileURLToPath(import.meta.url))

const nextConfig: NextConfig = {
  reactStrictMode: true,
  transpilePackages: ['@packages/components'],
  images: { unoptimized: true },
  output: 'standalone',
  poweredByHeader: false,
  typescript: {
    ignoreBuildErrors: true,
  },
  experimental: {
    webpackMemoryOptimizations: true,
  },
}

一般的に Dockerfile は Next.js の公式サンプルからもってきます。

コンテナイメージをビルドしてみる

はい、いきなりビルドが通りません。 どうやら、モノレポの上位階層にある node_modules(依存パッケージ)を standalone ディレクトリにコピー対象として含めたいのですが、apps/webapp ディレクトリにないのが原因なようです。

これは next.config.ts が以下のような感じで outputFileTracingRoot を追加します。それによりルートディレクトリの node_modules を参照してくれます(これがないと、Next.js は自分のディレクトリ(apps/webapp)内しかトレースしてくれません)。

const nextConfig: NextConfig = {
  reactStrictMode: true,
  transpilePackages: ['@packages/components'],
  images: { unoptimized: true },
  outputFileTracingRoot: join(__dirname, '../../'),
  output: 'standalone',
  poweredByHeader: false,
  typescript: {
    ignoreBuildErrors: true,
  },
  experimental: {
    webpackMemoryOptimizations: true,
  },
}

これでビルドは成功するようになります。

動かしてみる

なんか全部のページが404エラーになります。

イメージビルド結果に public ディレクトリが入ってないことがまずわかりました。

ビルド方法を疑って調べてみてわかったこと

ここで Gemini とか生成AIを使って解決策を壁打ちしてたんですが、適切な回答はまったく得られませんでした。 で、それっぽいキーワードでネットを検索していると、良い記事を見つけました。モノレポ構成のNext.jsプロジェクトをDocker化する方法

大事なのは、記事の中でビルド結果のファイルをコピーしているとことです。

COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public

で、元の公式サンプルでは以下のようになっていました。

COPY --from=builder --chown=node:node /app/.next/standalone ./
COPY --from=builder --chown=node:node /app/.next/static ./.next/static
COPY --from=builder --chown=node:node /app/public ./public

差分がわかりやすいですね。つまりモノレポの場合は、モノレポのパスを含めた状態で .next/staticpublic のフォルダをコピーする必要があるということです。

今回は .next/standalone の中身をこうすることになります:

└── apps/
    └── webapp/
        ├── server.js  <-- これを起動する
        ├── public/    <-- ここにコピーが必要
        └── .next/
            └── static/ <-- ここにコピーが必要

これで解決

結果としてできあがった Dockerfile は以下のような感じです

# syntax=docker.io/docker/dockerfile:1

ARG NODE_VERSION=24.13.0-alpine
FROM node:${NODE_VERSION} AS base

FROM base AS deps
RUN apk update && \
  apk upgrade && \
  apk add --no-cache libc6-compat make gcc g++ python3
WORKDIR /app

COPY . .
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi

FROM base AS builder
WORKDIR /app
# モノレポのため、全階層の node_modules が必要。webapp から参照するワークスペースについてはコピーする
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/apps/webapp/node_modules* ./apps/webapp/node_modules/
COPY --from=deps /app/functions/command/node_modules* ./functions/command/node_modules/
COPY --from=deps /app/packages/components/node_modules* ./packages/components/node_modules/
COPY . .

RUN \
  if [ -f yarn.lock ]; then yarn run build; \
  elif [ -f package-lock.json ]; then npm run -w apps/webapp build; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
  else echo "Lockfile not found." && exit 1; \
  fi

FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# モノレポのディレクトリパスを含める
COPY --from=builder --chown=nextjs:nodejs /app/apps/webapp/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/apps/webapp/.next/static ./apps/webapp/.next/static
COPY --from=builder --chown=nextjs:nodejs /app/apps/webapp/public ./apps/webapp/public

USER nextjs

EXPOSE 3000

ENV PORT=3000

ENV HOSTNAME="0.0.0.0"
# モノレポのディレクトリパスを含める
CMD ["node",  "apps/webapp/server.js"]

COPY でモノレポの node_modules が必要になる理由

  • シンボリックリンクの解決: NPM workspaces は、packages/components などを node_modules 内にシンボリックリンクとして配置します。Docker の COPY プロセスでこのリンク関係が崩れたり、リンク先のパスが正しく参照できなかったりすることがあります。
  • 依存関係の分離: 一部のビルドツールや Next.js の outputFileTracing は、各ワークスペース直下の node_modules を探しに行く挙動をすることがあります。

server.js にモノレポのディレクトリパスを含める理由

Next.js の standalone モードは、デフォルトでは server.js をカレントディレクトリとして動作しようとしますが、モノレポだと outputFileTracingRoot の影響で apps/webapp/server.js のような深い階層に生成されるので、実行パスにも注意が必要です。

さいごに

意外とよくあるシーンだと思うのですが、意外と情報に辿り着くまでに時間がかかりました。 僕の記事も追加することで、同じ問題で困っている人の解決になればと思います。

AWS 環境の Next.js アプリから Lambda 呼び出しトレースを X-Rayで追跡できるようにする

Next.js アプリを AWS にデプロイしたとき、SSR などでサーバーサイドで実行した処理から Lambda など別の AWS サービスを呼び出すことがあると思います。 アプリケーションのオブザーバビリティを確保するため、AWS 上のアプリケーションでは X-RAY を使ったログ集積をやることが多いと思います。

ここでは Lambda など別のAWSサービスを呼び出したとき、トレースを追跡できるようにする方法について記録していきます。

また本記事での Next.js のバージョンは v15 を想定しています。それ以前のバージョンでは instrumentationexperimental になっていますのでご注意ください。

Next.js で X-RAY に出力できるように設定する

instrumentation.ts で以下のようにします。

export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    await require('pino')
    await require('next-logger')
    await import('./instrumentation.node')
  }
}

ログが JSON で保持されていると X-RAY と相性が良いので、ロガーを pino にしておくと吉でお勧めです。

重要なのは NEXT_RUNTIMEnodejs の場合に instrumentation.node というファイルをダイナミックインポートすることです。 つまりサーバーサイドの処理のときの計測コードを使うようにします。

instrumentation.node.ts の内容は以下のようになります。

import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'
import { AWSXRayIdGenerator } from '@opentelemetry/id-generator-aws-xray'
import { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk'
import { AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray'
import { defaultResource, resourceFromAttributes } from '@opentelemetry/resources'
import { NodeSDK } from '@opentelemetry/sdk-node'
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'

const sdk = new NodeSDK({
  idGenerator: new AWSXRayIdGenerator(),
  textMapPropagator: new AWSXRayPropagator(),
  resource: defaultResource().merge(resourceFromAttributes({ [ATTR_SERVICE_NAME]: 'your-app-service' })),
  instrumentations: [
    new AwsInstrumentation({ suppressInternalInstrumentation: true }),
  ],
  spanProcessors: [new BatchSpanProcessor(new OTLPTraceExporter())],
})

sdk.start()

OTEL 系のライブラリを使って計測の設定を行いますが、X-RAY を使うときは @opentelemetry/id-generator-aws-xray@opentelemetry/propagator-aws-xray が重要になります。 あと、aws-sdk を使った呼び出しを計測できるようにラッパーである @opentelemetry/instrumentation-aws-sdk を入れておくと楽になります。

この例では Next.js を App Runner(新規申込が終了してしまいました。残念ですね)にデプロイしているのでリソース定義も defaultResource().merge(resourceFromAttributes({ [ATTR_SERVICE_NAME]: 'your-app-service' })) のようにしています。ここは Next.js をデプロイしたリソースによって書き方が変わります。

あとはいい感じに AWS のサービスを SDK で呼び出すと、Next.js(App Runner)から DynamoDB へのリクエストとか、S3 へのアクセスとか全部 X-RAY 上で線がつながって表示されるので、システムトレースの追跡がしやすくなります。

なぜか Lambda だけ線がつながらない?

さて、DynamoDBとかS3などのマネージドサービスは線が接続されていて問題がなさそうに思うのですが、Lambdaの呼び出し(InvokeFunction)だけは、うまく線が接続されません。Lambdaから外部のAPIサーバーを実行していたり、Aurora DBを実行するトレースなどの情報が AppRunner とは結合されておらず、App Runner から Lambda の呼び出し、Lambda から HTTP(API) 呼び出しみたいな別の線が出来上がっていて、システムトレースの追跡ができません。

調べてみた

そうすると X-Amzn-Trace-Id がセグメントドキュメントの http.request に記録されておらず、Lambdaへ正しく伝播されてないことがわかりました。 X-Amzn-Trace-Id が X-RAY で線を結びつけるための値です。

OpenTelemetry の仕様を調べてみる

公式ドキュメント 手動コンテキスト伝搬 などが参考になります。

propagation.inject(context.active(), output);

上記のようにアクティブコンテキストに追加すれば良さそうです。 さらに AWS-SDK の Lambda クライアントでコマンドが送信されたときにフックするにはミドルウェアを使います。

公式ドキュメント ミドルウェアを使用してリクエストをログに記録する

上記サイトの例は DynamoDB クライアントですが、他のクライアントでも同様に実装できます。

メモ

通常、AwsInstrumentation は多くの AWS サービスをカバーしていますが、Lambda の Invoke においては、ペイロードや呼び出し形式の都合上、自動でのコンテキスト注入が期待通りに動かないケースがあります。 これを解決するために、AWS SDK v3 の Middleware Stack を利用して、リクエストが送出される直前に OpenTelemetry のアクティブコンテキストからトレース情報を抽出し、HTTP ヘッダーに明示的にねじ込む処理を追加します。

やってみた

手動伝搬するコードの追加

まず x-ray.ts を作ります。

import { FinalizeHandlerArguments, HttpRequest, MiddlewareStack } from '@aws-sdk/types'
import { context, propagation } from '@opentelemetry/api'

interface HasMiddlewareStack {
  middlewareStack: MiddlewareStack<any, any>
}

const headerSetter = {
  set: (carrier: Record<string, unknown>, key: string, value: string) => {
    carrier[key] = value
  },
}

export const addXRayInjector = <T extends HasMiddlewareStack>(client: T): void => {
  client.middlewareStack.add(
    (next) => async (args) => {
      const finalizeArgs = args as FinalizeHandlerArguments<object>
      const request = finalizeArgs.request as HttpRequest

      if (request?.headers) {
        const activeContext = context.active()
        const carrier = request.headers as Record<string, string>
        propagation.inject(activeContext, carrier, headerSetter)
      }

      return next(args)
    },
    {
      step: 'serialize',
      name: 'xRayContextInjector',
      override: true,
    }
  )
}

このコードでは AWS-SDK のクライアントから X-RAY のコンテキストにリクエストヘッダーを手動伝搬しています。

トレースコンテキスト $C$ は、スパン ID $S$ とトレース ID $T$、およびフラグ $F$ の集合として定義されます。

$$ C = \{T, S, F\} $$

この $C$ を X-Amzn-Trace-Id ヘッダーとして $C_{AppRunner} \rightarrow C_{Lambda}$ へ手動で注入(Inject)することが、今回のコードのキモです。

Lambda クライアントのインスタンスに設定する

そして LambdaClient インスタンスを生成したら、 addXRayInjector で手動伝搬するためのミドルウェアを設定するようにします。

  const client = new LambdaClient()
  addXRayInjector(client)

最後に

今回は Lambda クライアントについて手動伝搬できるような記事となっていますが、S3やDynamoDBのようにさらにその先がない場合は伝搬を気にしなくて良いのですが、Lambdaと同様に以下のサービスについても手動伝搬は必要になります。

  • StepFunctions
  • SQS

つまりリクエストが伝搬して、さらに別のサービスまでトレースを伝搬するようなサービスを利用するときは、リクエストを受け取ったサービス(今回の例でいうと Next.js)から、さきほどの addXRayInjector を設定して X-Amzn-Trace-Id を伝搬できるようにしましょう。

これで良きオブザーバビリティが実現できますように!

PHPカンファレンス福岡2025に参加した

PHPカンファレンス10周年おめでとうございます。

過去の参加ブログのリンクから:

ほとんど参加していると思っていたら、そうでもなかった。

前日入り

今回も前日入りしましたが、いきなり飛行機が遅延するというトラブルに。

こちらは昨年と同じ書き出しを1行コピペしてきましたが、今年も遅延から始まりました。 お昼ぐらいの来福者は時間どおりだったそうなので、朝だけだったようです。

福岡に到着したら WeWork 天神ブリッククロスへ。永和システムマネジメントでは東京支社がWeWork京橋内になったため、今回のように福岡に前日入りしてもWeWork拠点があれば作業できるのでとても便利。

こちらも昨年からのコピペに見えますが、WeWork の場所が変更となっています。昨年訪問した大名は新しい天神ブリッククロスに引越したようです。こちらは8月にオープンしたということで、まだ3ヶ月ぐらいの新しい拠点で、すごい新築の香りがしていました。

プロジェクトが多忙なこともあり、始発に近い時間に東京を出て、普通の勤務時間に仕事を開始してました。

お昼はWeWork近くにあった能古うどんへ。

夕方からは昨年と同じくWeWorkに知っている人たちが続々来て【非公式】PHPカンファレンス福岡2025・前日Meetup が行われました。昨年は袋詰めに参加していたのですが、今年はこちらに参加(偶然居合わせ?w)ていました。

そのあとは懇親会/2次会にも混ざって、そのあとは Rummy 行って美味しいラムをいただいて、締めにラーメンを食べて3時ちょいに寝ました。なんと気づくとほぼ昨年と同じパターン。

当日

ちゃんと朝起きれて今年は無事会場へ到着。

今回は多くの時間セッションに参加してました。PHP養分がたくさん補充されました。アンカンもなかったので、大量のインプットです。

技術面もエモさもたくさんあって、とても充実した1日となりました。来週からの仕事のモチベにもなります(PHP書いてないけど)。

AIというキーワードが多くあって、やっぱりそういう時流というか避けては通れない何かみたいなのは感じますね。とはいえ、その中で僕ら技術者がやるべきことというか、やることが変わっていく中での模索が続いているというのは、こういうリアルなコミュニティという現場で得られるなぁと強く感じました。

ちなみにお昼は、隣のウェストで。店中が同じようなイベントTシャツを着た人で溢れていて、お店の人も「何?」って後で話したりしてるんでしょうねぇw(そういえばランチの写真はFacebookにしかupしてなかった

そのあとはそのあとは懇親会 → 2次会 → 3次会 の流れで4時過ぎに解散となりました。 初めましての方、お久しぶりの方とたくさん話せました。楽しかった!(そして飲みすぎた!

※3次会の始まりのポストより

後日

今年はアフターハックがなかったので、ホテルの隣のエンジニアカフェにてこのブログを書いています。

2019年の記事の最後は

PHPカンファレンス福岡、来年も参加できると良いなー。

2024年の記事の最後は

そしてまた参加できるように願っています。

で終えていました。

PHPカンファレンス福岡は現体制での開催は今年で最後ということが事前に告知されております。 最後の赤瀬さんの挨拶を思い出して、ウルウルしながらこの1行を書いています。

福岡のコミュニティとのつながりでいうと、PHPMatsuri Fukuoka (ブログ記事: PHP Matsuri2012を終えて 〜 Retrospective of PHP Matsuri 2012 in Fukuoka)からで、最初にもリンクした過去の自分の記事を含めて見ながら懐かしいなぁというのと、少し寂しさも感じていました。

ところが懇親会で @kis さんがコミュニティの継続を熱く願って(少し無茶振り?)、fukuoka.php としての活動は新しい世代で始めるという流れを作ってくれました。

そうPHPカンファレンス福岡の始まりも、あのツイートからでしたからね

もちろん各地のPHPカンファレンスなどで福岡のコミュニティのみなさまと再開できることはあると思いますが、また福岡の地での再会があるかもしれません。

最後に Kenichiro トリオ写真を撮っていただいたので入れておきます。