細かい業務改善_2023

こんにちは、takeshi-p0601 - Qiita です。普段iOSアプリケーションの開発をメインに業務を行っています。本記事はブログの1日目で、それに相応しいような特大ネタでなくちょっと地味なんですが、よかったらお立ち寄りください~

この記事は去年もこちらで記載した内容の2023年版で、今年は二つほど紹介します。

(1) 運用タスクの時期を決めるためのフローの整備

背景

所属するモバイルチームのタスクは、プロジェクトに紐づくタスクについてはスケジュールが引かれる一方で、運用上発生するタスクについてはリソースの空き状況を踏まえ、その時々で対応の可否が決まっていました。

予定されたスケジュールを見直すほどのクリティカルな問題であれば、優先度の判断はつきます。 ただ中には緊急度の高くないような、優先度の判断に時間がかかるタスクもありそうで、あらかじめ検討していた優先度のそこまで高くないタスクが積み残されてしまうような、中途半端な状態になることも想像できました。

具体的に取り組んだこと

添付のようなフローを整備し、未来のタスクを選出するために1ヶ月単位でのスケジュール確認やステークホルダーとの確認を組み込みました。

  • 1ヶ月単位で翌月のタスク確認〜タスク選出〜チケット作成をし、決めたタスクを翌月行う
  • 月初から月末2週間前にかけてを、来月のタスクを確認する時期とする
    • 各プロジェクト状況を把握して、スケジュール的に翌月に予定されるタスクとして何がありそうか確認しておく
    • チーム内で確認している緊急度高いものや、直近必要なものなど確認する
    • 極端な例ですが、例えば再来月から新入社員の方の参画が決まっている場合、来月のタスクに「オンボーディングの資料など前もって準備する」といった作業にも意識が向くようなことを期待
  • 月末2週間前から月末1週間前くらいにかけて、タスクを選出し、ステークホルダーに確認
    • 実際には運用でない、通常のプロジェクト作業がメインとなることもある
  • その後チケット作成

結果

  • ある程度チーム内に共通認識を持たせ、タスク決めに関するフローが整備ができた
  • 個人的には未来のタスクへの意識がむき始めたことで、何となくその時々で対応するような感覚はなくなりつつある
  • ただし、計画にないタスクの発生は何度かあり、そうしたタスクの意識的なスコープ管理等の取り決めは必要そうだった

このフローはあくまで直近の問題に対してのアプローチで、その時の状況次第で変わるため、定期的に見直したいです。

(2) 議事録のテンプレート

背景

携わっているプロジェクトで、自身が会議を主体的に行う必要がありました。 あまり自らが主体となった会議をやったこともないのもあり、なんらか準備を工夫した方がいいかなと考えていました。

具体的に取り組んだこと

ひとまずテンプレートを作成し、参加者、日時、背景、ゴール、議事録メモなどの項目を用意して会議に臨む

## 参加者

{ 誰が参加したのか。誰と認識合わせをしたものか、誰と認識合わせてなさそうかを知るため。 }

@XXX @XXX @XXX 

## 日時

{いつ頃の、何分程度の情報なのか認識合わせるため}

XX/XX

## 背景

{  なぜその会議をするに至ったかの情報がわかる内容。googleカレンダーに詳細書いていたり、slackなどでメッセージ記載している場合は、それを引用するなど } 

## ゴール

{ この会議が何を満たしたら終了できそうかを認識合わせること。 }

 ## 本日考慮できてないこと

{ 話す内容で、まだ決められてないけど進みたい場合もあるため(あったため)、その情報を最低限展開するための場所 }

## 資料

{ゴールに向かうための必要な資料リンク or その内容自体}

## アジェンダ

{ どういう順序で話が進むのかの認識を共有しておくこと。参加者にあとどのくらい論点があるかを確認するためのもの }

## ネクストアクション

{ 次にどこに向かった方が良さそうか、そもそもそれがないかを把握できる情報を記載すること。会議開始時点で見込みで予想されることもあるかもしれないが、会議中に更新されることもあるかもしれない }

## 議事録メモ

{ ここに議事録をひたすら書く }

結果

  • 2回目以降は準備時間を短縮できた
  • 実際に使ってみて、ある程度会議をスムーズに進行できそうなことを実感。
    • 重要度高そうなものや、参加者が多いものなどしっかり準備しておく
  • ただし、特に重要でない会議ではあまり使用したいとも思えなかったのでケースバイケースで使用

感想

以上2点です。 こうした改善活動は一見地味ですが、コツコツやって2024年度も何か見つけてできることがあれば取り組みたいと思います!


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 photosynth.co.jp

Akerunにご興味のある方はこちらから akerun.com

Swift OpenAPI Generator を使って、モックサーバーアプリをローカルで起動する

こんにちは、takeshi-p0601 - Qiita です。普段iOSアプリケーションの開発をメインに業務を行っています。

Vision Pro の話が印象深い今年のWWDCでしたが、その他にもSwiftの言語仕様やXcodeの改善、UIフレームワークの機能向上など気になるものがたくさんありました。本記事ではその中の一つである Swift OpenAPI Generator と、それを利用して作成した簡易モックサーバーアプリをローカルで起動することについて書きます。

※ この記事で記載しているソースコードは、Swift OpenAPI GeneratorのWWDCセッション中に使用されたソースコードや、公式のサンプルコードなどを参考にしています

Swift OpenAPI Generator とは

OpenAPIの仕様に準拠したドキュメントファイルの内容から、Swiftソースコードを自動で生成してくれるツールで、ビルド時に実行されるSwift Package Pluginです。 こちらソースコードを確認することができます。※Swift Package PluginとはWWDC2022でも発表のあった比較的新しいツールで、この記事では深掘りしませんが、概要を掴むために下記のリンクが役立ちました。

既存でもOpenAPIドキュメントファイルからソースコードを自動生成するツールはありますが、AppleがSwiftを使用して公式的に開発しているツールであることや、Swift Package Pluginとして提供されていることから、Xcodeとの親和性も高く、将来的に期待できそうです。そのためiOSアプリやMacOSアプリなどを開発する場合に、Web API関連のソースコードを自動生成するツールとして、スタンダードなものになっていくことが予想されます。

ツールの簡単な紹介

詳細な手順は省きますが、ツールがどのようなものか軽く紹介します。

何らかのiOSアプリがAPIリクエストを送信してレスポンスを受け取りたいような、クライアントサイドの処理を実装するとして、 まず下記のようなOpenAPIドキュメントファイルを用意します。

openapi: "3.0.3"
info:
  title: CatService
  version: 1.0.0
servers:
  - url: http://localhost:8080/api
    description: "Localhost cats 🙀"
paths:
  /emoji:
    get:
      operationId: getEmoji
      parameters:
      - name: count
        required: false
        in: query
        description: "The number of cats to return. 😽😽😽"
        schema:
          type: integer
      responses:
        '200':
          description: "Returns a random emoji, of a cat, ofc! 😻"
          content:
            text/plain:
              schema:
                type: string

その後、Xcodeで上記のドキュメントファイルの組み込みやツールの設定ファイルの追加、そのほか必要な手順を済ませると、ビルド時にソースコードを自動生成するツールが実行され、

ソースコードが自動で生成されます。

それにより、iOSアプリのプロダクトコードに自動生成されたAPIリクエスト処理とそのレスポンスを処理できるプログラムを組み込めるようになります。

API通信処理を組み込んだ後でデバックビルドし、そのログを追ってみると

SwiftCompile normal arm64 /Users/takeshikomori/me/iOS/testSwiftOpenAPIGenerator/testSwiftOpenAPIGenerator/testSwiftOpenAPIGeneratorApp.swift (in target 'testSwiftOpenAPIGenerator' from project 'testSwiftOpenAPIGenerator')
    cd /Users/takeshikomori/me/iOS/testSwiftOpenAPIGenerator
    /Applications/Xcode15beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -c 
    .... /Users/takeshikomori/Library/Developer/Xcode/DerivedData/testSwiftOpenAPIGenerator-himwceovqvysargtcarobfkdexzk/SourcePackages/plugins/testSwiftOpenAPIGenerator.output/testSwiftOpenAPIGenerator/OpenAPIGenerator/GeneratedSources/Client.swift

DerivedData/.../SourcePackages/plugins/testSwiftOpenAPIGenerator.output/testSwiftOpenAPIGenerator/OpenAPIGenerator/GeneratedSources/Client.swift とあるように、 DerivedData/に自動生成されたソースコードが生成され、それを元にコンパイルするので、デフォルトでプロジェクトフォルダ直下に自動生成されることはなく、メインアプリターゲットのソースファイルとして管理することはないようです。

サーバーサイドのコードも自動生成ができる

Swift OpenAPI Generatorのセッション は、前のセクションで説明したようなクライアントサイドアプリで使えるSwiftソースコードを自動生成する話がメインですが、セッションの後半ラスト5分ほどでサーバーサイドアプリのソースコードにおいても、自動生成できる紹介がありました。

恥ずかしながら元々セッションの目次を見ていなかったため、それに辿り着くまでpythonを使った簡易サーバープログラムを起動し、クライアントサイドアプリの自動生成ソースコードの挙動確認を行なっていました。後半のセッションをもとにサーバーサイドの自動生成プログラムの内容も試してみると、Swiftを使って簡単に少ないコードでローカルモックサーバーアプリを起動することができました。

普段クライアントサイドアプリを中心にSwiftをプログラミングするエンジニアとしては、Swiftで簡単にサーバーアプリを起動できたことは良い体験でしたので、その辺りを紹介します。(サーバーサイドの実装には、 Vapor というSwiftで主に実装されたオープンソースのWebフレームワークを前提としています。)

公式のサンプルコードを使って、ローカルにサーバーアプリを起動する

実装方法を紹介する前に、公式にあるサンプルコードを使用してローカルにモックサーバーアプリを起動できるので、下記の手順を踏んで軽く確認をしてみます。 ※具体的な繋ぎ込みの手順はこの次のセクションに記載しています。

試した環境

手順

(1)ソースコードをcloneします

$ git clone https://github.com/apple/swift-openapi-generator.git

(2)clone後、下記のディレクトリに移動しておきます

$ cd swift-openapi-generator/Examples/GreetingService

(3) swift-openapi-generator/Examples/GreetingService/openapi.yamlファイルを開き、ベースURLを下記のようにlocalhostに書き換えます。

   title: GreetingService
   version: 1.0.0
 servers:
-  - url: https://example.com/api
+  - url: http://localhost:8080/api
     description: Example
 paths:
   /greet:

(4)Xcodeの指定を、Xcode14.3 に切り替えます

$ sudo xcode-select -s /Applications/{Xcode14.3}.app/Contents/Developer

(5)ソースコードをビルドし、アプリを起動させます。

$ swift run GreetingService
Building for debugging...
~~~
Build complete! (178.39s)
2023-06-28T05:03:32+0900 notice codes.vapor.application : [Vapor] Server starting on http://127.0.0.1:8080

※Exampleの例としてクライアントサイドアプリのターゲットもPackage.swiftに定義されているため、 run サブコマンドの引数にサーバーサイドアプリのターゲット( GreetingService )を指定してください。Exampleとしてクライアント/サーバー両方のアプリの実行ターゲットが準備されているようです。

(6)curlコマンドで疎通確認します。

下記のようにレスポンスが返されると思います。

$ curl localhost:8080/api/greet
{
  "message" : "Hello, Stranger!"
}

※レスポンス処理の実装参考: https://github.com/apple/swift-openapi-generator/blob/7b97c0e062411ec594fad8d670a25bac1449bc06/Examples/GreetingService/Sources/GreetingService/GreetingService.swift#L29

サーバーサイドアプリの実装方法

先の公式サンプルで示したモックサーバーアプリをlocalで立てるところまでの実装方法を紹介します。https://github.com/takeshi-p0601/TestMockServerApp にもソースコードを載せていますので、そちらもご参照ください。

試した環境

  • Xcode14.3 (Swift5.8)
  • Mac OS 13.4

手順

(1)適当にディレクトリを作成して、そのディレクトリに移動します。

$ mkdir TestMockServerApp && cd TestMockServerApp

(2) swift package initを実行してserverアプリを実装するための Swift Package を作成します。 その際、オプションの type(Package type)executable を指定してください。(デフォルトでは type=library となっています)

$ swift package init --type executable            
Creating executable package: TestMockServerApp
Creating Package.swift
Creating .gitignore
Creating Sources/
Creating Sources/main.swift

(3)Package.swift を下記のように編集します。

// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "TestMockServerApp",
    platforms: [
        .macOS(.v13)
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-openapi-generator", .upToNextMinor(from: "0.1.0")),
        .package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.1.0")),
        .package(url: "https://github.com/swift-server/swift-openapi-vapor", .upToNextMinor(from: "0.1.0")),
        .package(url: "https://github.com/vapor/vapor", from: "4.76.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package, defining a module or a test suite.
        // Targets can depend on other targets in this package and products from dependencies.
        .executableTarget(
            name: "TestMockServerApp",
            dependencies: [
                .product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
                .product(name: "OpenAPIVapor", package: "swift-openapi-vapor"),
                .product(name: "Vapor", package: "vapor"),
            ],
            path: "Sources",
            plugins: [
                .plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator")
            ]
        ),
    ]
)

(4) 下記の内容で、OpenAPIドキュメントファイル( openapi.yaml )をSourcesディレクトリに追加します。

openapi: '3.0.3'
info:
  title: TestMockServerApp
  version: 1.0.0
servers:
  - url: http://localhost:8080/api
    description: Example
paths:
  /greet:
    get:
      operationId: getGreeting
      parameters:
      - name: name
        required: false
        in: query
        description: A name used in the returned greeting.
        schema:
          type: string
      responses:
        '200':
          description: A success response with a greeting.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Greeting'
components:
  schemas:
    Greeting:
      type: object
      properties:
        message:
          type: string
      required:
        - message

(5) 下記の内容で openapi-generator-config.yaml を作成して、Sourcesディレクトリに追加します。

generate:
  - types
  - server

(6) API関連のソースコードを自動生成するためにビルドします。(Xcodeでビルドすることもできます。)

出力内容が一部異なるかもしれませんが、初回ビルド時に下記のようにOpenAPIGeneratorが実行されていることがわかります。

$ swift build
...Swift Package の Fetch など...
Swift OpenAPI Generator is running with the following configuration:
- OpenAPI document path: /Users/takeshikomori/TestMockServerApp/Sources/openapi.yaml
- Configuration path: /Users/takeshikomori/TestMockServerApp/Sources/openapi-generator-config.yaml
- Generator modes: types, server
- Output file names: Types.swift, Server.swift
- Output directory: /Users/takeshikomori/TestMockServerApp/.build/plugins/outputs/testmockserverapp/TestMockServerApp/OpenAPIGenerator/GeneratedSources
- Diagnostics output path: <none - logs to stderr>
- Current directory: /Users/takeshikomori/TestMockServerApp
- Is plugin invocation: true
- Additional imports: <none>
File Types.swift: changed
File Server.swift: changed
[1876/1876] Linking TestMockServerApp
Build complete! (208.55s)

// 再度ビルド
$ swift build 
Building for debugging...
[4/4] Compiling plugin OpenAPIGenerator
Build complete! (0.56s)

(7) Sources/main.swift を下記のように変更します。

import OpenAPIRuntime
import OpenAPIVapor
import Vapor

struct Handler: APIProtocol {
    func getGreeting(
        _ input: Operations.getGreeting.Input
    ) async throws -> Operations.getGreeting.Output {
        let name = input.query.name ?? "Stranger"
        return .ok(.init(body: .json(.init(message: "Hello, \(name)!"))))
    }
}

let app = Vapor.Application()
let transport = VaporTransport(routesBuilder: app)
let handler = Handler()
try handler.registerHandlers(on: transport, serverURL: Servers.server1())
try app.run()

(8)ビルドして、サーバーアプリを起動させます。(Xcodeでビルド+起動させることもできます。)

$ swift run
Building for debugging...
Build complete! (0.53s)
2023-06-30T08:14:50+0900 notice codes.vapor.application : [Vapor] Server starting on http://127.0.0.1:8080

(9)疎通できるか確認します。

下記のようなレスポンスが返されれば問題ないと思います。

$ curl localhost:8080/api/greet
{
  "message" : "Hello, Stranger!"
}

$ curl -G -d name=world localhost:8080/api/greet
{
  "message" : "Hello, world!"
}

APIの仕様の変更に対応する

APIの仕様が変わる場合も当然あると思います。その際の変更方法を紹介します。 先の手順で定義したOpenAPIの仕様から、imageバイナリデータがが一つ返される [GET] /image エンドポイントが追加される変更があると想定して、確認します。

(10) openapi.yaml ファイルの内容を変更します。

/image エンドポイントを追加してみます。

  /image:
    get:
      operationId: getImage
      responses:
        '200':
          description: "Return image"
          content:
            image/png:
              schema:
                type: string
                format: binary

(11) ビルドします。

ログを見ると、OpenAPIドキュメントファイルが変更されたため、Types.swiftServer.swiftに変更が入ってそうなことがわかります。

$ swift build
Building for debugging...
Swift OpenAPI Generator is running with the following configuration:
- OpenAPI document path: /Users/takeshikomori/TestMockServerApp/Sources/openapi.yaml
- Configuration path: /Users/takeshikomori/TestMockServerApp/Sources/openapi-generator-config.yaml
- Generator modes: types, server
- Output file names: Types.swift, Server.swift
- Output directory: /Users/takeshikomori/TestMockServerApp/.build/plugins/outputs/testmockserverapp/TestMockServerApp/OpenAPIGenerator/GeneratedSources
- Diagnostics output path: <none - logs to stderr>
- Current directory: /Users/takeshikomori/TestMockServerApp
- Is plugin invocation: true
- Additional imports: <none>
File Types.swift: changed
File Server.swift: changed
error: emit-module command failed with exit code 1 (use -v to see invocation)
/Users/takeshikomori/TestMockServerApp/Sources/main.swift:5:8: error: type 'Handler' does not conform to protocol 'APIProtocol'
struct Handler: APIProtocol {
       ^
/Users/takeshikomori/TestMockServerApp/.build/plugins/outputs/testmockserverapp/TestMockServerApp/OpenAPIGenerator/GeneratedSources/Types.swift:16:10: note: protocol requires function 'getImage' with type '(Operations.getImage.Input) async throws -> Operations.getImage.Output'
    func getImage(_ input: Operations.getImage.Input) async throws -> Operations.getImage.Output
         ^
/Users/takeshikomori/TestMockServerApp/Sources/main.swift:5:8: error: type 'Handler' does not conform to protocol 'APIProtocol'
struct Handler: APIProtocol {
       ^
/Users/takeshikomori/TestMockServerApp/.build/plugins/outputs/testmockserverapp/TestMockServerApp/OpenAPIGenerator/GeneratedSources/Types.swift:16:10: note: protocol requires function 'getImage' with type '(Operations.getImage.Input) async throws -> Operations.getImage.Output'
    func getImage(_ input: Operations.getImage.Input) async throws -> Operations.getImage.Output
         ^
[9/10] Compiling TestMockServerApp main.swift

下の方でエラーが出てしまっているのは、プロダクトコードの実装が新たに変更されたAPIProtocolに準拠してないためです。

上記はCLIでの確認ですが、Xcodeで確認すると添付のようにエラーメッセージが表示されるので、そのFixボタンを押してメソッドを自動で追加します。

(12) 先ほど追加したメソッドの中身の実装と、imageバイナリをレスポンスとして返すために少し修正を適用させます。

こちらの変更履歴参考にしてください。

(13) 再度ビルドしてアプリを起動し、疎通確認をします。

$ swift run
Building for debugging...
[5/5] Linking TestMockServerApp
Build complete! (2.75s)
2023-06-30T08:24:54+0900 notice codes.vapor.application : [Vapor] Server starting on http://127.0.0.1:8080

ブラウザで http://127.0.0.1:8080/api/image にアクセスすると添付のような画像が表示されます。

==

今示したように、APIの仕様変更に対応して挙動を確認するには下記の手順になります。

  1. OpenAPIドキュメントを更新する
  2. ビルドして、変更後のOpenAPIドキュメントファイルに則ったソースコードを生成する
  3. 新しく生成されたソースコードを使って、プロダクトコードに繋ぎ込む
  4. 再度ビルドして、アプリを起動する

良かった点

  • 普段使い慣れたエディタ + 言語でプログラミングできるため、特にChatGPTに頼ることなく実装できたこと。(pythonを使った簡易サーバープログラムは、簡単な文字列の操作から標準ライブラリのimportなどもすぐエラーになってしまうため、ややストレスに感じました。)
  • 書くべきソースコードはそこまで多くなかったこと。
  • APIProtocolインターフェースに定義された実装が強制されるので、実装もれが少なくなりそうなこと。

気になる点

一方でこのツールを使う際の気になる点として、個人的には下記がありました。

  • OpenAPIドキュメントファイルは準備する必要があるので、ない場合は準備が手間なこと。
  • 自動生成されたソースコードは、デフォルトで管理するような設計になってないためソースコードの変更を追従することがやや面倒です。APIの規格自体はそこまで頻繁な変更があるわけでもないように思いますが、最初のうちはバージョンごとでどういうソースコードが生成されるかや、どういった差分はあるかは確認したり、gitで管理するのもいいかもと思いました。

今後試したいこと/調べてみたいこと

今回試せなかったことで、今後下記のようなことを試したり調べてみたいです。

  • Swift OpenAPI Generator を使ってAPIの結合確認の際に、簡単なレスポンスを返すモックサーバーアプリの作成
    • サーバーアプリがデプロイされる前の、簡易的な動作確認用のレスポンス
    • 異常なケース(大量のデータなど)のレスポンス
  • Vaporの理解を深める
    • 今回のGeneratorツールを利用した手順でないと、Vaporを利用することができないため。

最後に

Swift Package のエコシステムを利用しながら、クライアントサイドにとどまらない改善を進めていることを知ることができて、今後Swiftで開発するモチベーションにつながりました。WWDCのセッションはまだ視聴できてないものもあるので、引き続き確認していけたらと思います。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com

GitHub Copilotでのより良いプロンプトの書き方

こんばんは Esperna - Qiita です。 今年の4月から業務で GitHub Copilot を使い始めて2ヶ月以上経ちます。ほんと便利ですね。 この2ヶ月ゴリゴリ単体テストやコードを書いたり、デバッグすることが多かったのですが、 コードを書くとどんどん補完されていくのが気持ちよくて、もう後戻りできないです。 補完機能だけでも、1ヶ月あたり数時間は入力時間が短縮されているのではないでしょうか。

一方で、捉え方次第でもっと GitHub Copilot を活用できるのではと思い、GitHub Copilot でのプロンプトの書き方について調べてみました。 想定読者は

  • Copilotを使っているけどイマイチ使いこなせてない感があり、もっと上手く活用したいと思っている人
  • Copilotを社内で導入したいと思っている人

で、そのような人たちの役に立てればと思っています。

より良いプロンプトの書き方について

次の3つがあると思います。

  1. コメントには create/generate/rewrite といったプロンプトによる指示ではなく関数の説明そのものを書く
  2. 宣言的プログラミングを行う
  3. 既知のアルゴリズムやデータ構造、デザインパターンに適用する

なお、本ブログで登場するプロンプトの例はVSCode環境で実行したもので、注意すべき点があります。

  • 出力例は内容の妥当性を保証したものではないのでご注意ください。
  • また実際のコメントには「//<=ここで Ctrl+Enter(※)」は含んでいません。

GitHub Copilotはプロンプトを記載した上でCtrl+Enterを押すと、複数の補完候補を表示してくれます

1. コメントには create/generate/rewrite などを使わずに関数の説明そのものを書く

GitHubのgenerating-code-suggestions-from-commentsに「You can describe something you want to do using natural language within a comment」と書かれており、 当たり前とは言えば当たり前な気もしますが、色々検討し1周回って元に戻ってきた例を1つ紹介します。

下記はjsonファイルの中身をjqでフィルタリングするGo言語のプログラムの出力を目指したプロンプトの例です。 自然言語の説明は少なく、主な条件をshellから推測してもらうことを期待していました。

/*
cat test.txt | jq -r  'select(.vulnerability.modules[0].packages[0].callstacks[0] !=null).vulnerability | {descrip
tion:.osv.details, "check_name":"govulncheck" ,  fingerprint:.osv.aliases[0] , "severity": "HIGH", location : { path : .modules[0].packages[0].callstacks[0].frames[0].position.filename , lines 
:{begin:.modules[0].packages[0].callstacks[0].frames[0].position.line } } } '| jq -s .
*/

// q: Please rewrite above shell by golang
// a: //<=ここでctrl+Enter

これは同僚に言われて気がついたのですが、Copilot はChatGPTと違って「指示する」系のプロンプトはなんとなく合わない印象があります。 なぜなら

  • 生成後に指示文を削除するなどの辻褄を合わせる作業が必要なくなる / コメントがそのままコメントとして機能するから
  • もともと コメント + ソースコード を学習に利用しているはずで、そこには copilot への指示文は含まれないはずだから

よって、コメントには create/generate/rewriteと書かず、関数の説明そのものを書いてあげると良さそうです。

// print out "govulncheck" results like following `jq` script
// cat test.txt | jq -r 'select(.vulnerability.modules[0].packages[0].callstacks[0] !=null).vulnerability | {description:.osv.details, "check_name":"govulncheck" ,  fingerprint:.osv.aliases[0] , "severity": "HIGH", location : { path : .modules[0].packages[0].callstacks[0].frames[0].position.filename , lines :{begin:.modules[0].packages[0].callstacks[0].frames[0].position.line } } }'
// shall not use ioutil because it is deprecated//<=ここでctrl+Enter

2. 宣言的プログラミングを行う

手続き的プログラミングはコードの実行手順を記述していくようなプログラミングを指すのに対して、 宣言的プログラミングとは得たい結果を記述するようなプログラミングを指します。

例としては前者が c言語で for 文や if 文でコンピュータにやってほしい手続き(例えばバブルソート等を考えてもらうとイメージしやすいと思います)を書くのに対して、 後者はSQLなどで「create table if not exists xxx」と書きます。

以下は単純なモータを駆動するプログラムを出力するプロンプトの一例で、 状態に応じた start の振る舞いをコメントで記述しています。

class Motor {
    constructor() {
        this.isActive = false;
    }
    //when motor state is not active, start calls motorDev.start()
    //when motor state is active, start does nothing
    start()//<=ここでctrl+Enter
}

出力例

start() {
        if (!this.isActive) {
            this.isActive = true;
            motorDev.start();
        }
    }

上記の記載に stop の振る舞いの記載も追加すると

class Motor {
    constructor() {
        this.isActive = false;
    }
    //when motor state is not active, start calls motorDev.start()
    //when motor state is active, start does nothing
    start() {
        if (!this.isActive) {
            motorDev.start();
            this.isActive = true;
        }
    }

    //when motor state is active, stop calls motorDev.stop()
    //when motor state is not active, stop does nothing//<=ここでctrl+Enter

startstop の対称性も維持したコードを出力してくれます。

出力例

class Motor {
    constructor() {
        this.isActive = false;
    }
    //when motor state is not active, start calls motorDev.start()
    //when motor state is active, start does nothing
    start() {
        if (!this.isActive) {
            motorDev.start();
            this.isActive = true;
        }
    }

    //when motor state is active, stop calls motorDev.stop()
    //when motor state is not active, stop does nothing
    stop() {
        if (this.isActive) {
            motorDev.stop();
            this.isActive = false;
        }
    }

個人的に宣言的プログラミングで書くときは割とテスト駆動・テストファーストで書くときの感覚に近いと思っています。 宣言的にコメントを書くとCopilotが行間を読んで、コードを出力してくれますし、 暗黙のうちに対称性や規則性を考慮してコードを出力してくれるので、 Copilotはテスト駆動・テストファーストでコードを書く際の効率を上げてくれると思っています。

また、関数・メソッドに関する入出力の説明を増やしたり、 データの型に関する情報を増やすとより精度の高い出力が得られると思います。 これは「.d.ts をピン止めするとOpenFiles としてプロンプトの一部になって補完精度あがるよ」というmizchiさんという方のtwitter投稿と 同じことではないかと思っていて、型のような静的な情報が増えるほど、出力が一意に定まりやすいのではないかと思います。

3.既知のアルゴリズムやデータ構造、デザインパターンに適用する

例えばquick sortのようなアルゴリズムをバグを埋め込まずに実装するには時間がかかります。 既知のアルゴリズムを実装するといった車輪の再発明をする時間を減らして、 ドメインに特化した設計(データ構造・アルゴリズムの選択、クラスの責務分担、状態設計、非機能とのトレードオフの選択など)に 時間をかけられると効率が良いのではと思っています。 大抵の設計・実装課題というのは過去に先人が通ってきた道であり、 特定のアルゴリズムやデータ構造、あるいはデザインパターンで解ける内容である場合は 前述の宣言的プログラミングを駆使して精度の高い出力を得られるのではと思っています。 ただし、前提として出力されるコードが正しいかどうかを理解できる、 つまり、入出力コードをチェックするテストコードが書けることが前提になります。

//use quickSort algorithm
//input: Number array
//output: Number array
function quickSort(array) //<=ここでctrl+Enter

出力例

function quickSort(array){

    //if array is empty or has 1 element, return it
    if(array.length <= 1){
        return array;
    }

    //choose pivot, take first element
    var pivot = array[0];

    //create left and right arrays
    var left = [];
    var right = [];

    //iterate through array, put elements bigger than pivot in right array, smaller in left array
    for(var i = 1; i < array.length; i++){
        if(array[i] < pivot){
            left.push(array[i]);
        }else{
            right.push(array[i]);
        }
    }

    //recursively call quickSort on left and right arrays
    return quickSort(left).concat(pivot, quickSort(right));

}

注意点

Copilotはとても便利ですが注意点があります。

  • 前提としてGitHub Copilotで下記が設定されていること
    • Suggestions matching public codeがBlockになっていること
    • Allow GitHub to use my code snippets for product improvementsにチェックが入ってないこと
  • Copilotから出力されるコードが妥当かセルフチェック、テスト、レビューを必ず行うこと
    • そのまま使えることもあるが、大抵は加筆・修正が必要
    • 上述の設定をしていてもCopilotが提案するコードにライセンス違反のコードが含まれる可能性があるのでチェックすること

まとめと所感(Copilotをチーム全体で使う意義について)

次の3つを意識すると精度の高い出力を得やすく、車輪の再発明を防げると考えます。

  1. コメントには create/generate/rewrite といったプロンプトによる指示ではなく関数の説明そのものを書く
  2. 宣言的プログラミングを行う(なるべく静的な情報を増やす)
  3. 既知のアルゴリズムやデータ構造、デザインパターンに適用する

Copilotをチーム全体で使う意義については、単にコードの入力時間の短縮に止まらず、 前述のような宣言的なコードのコメントを増やすことで、 テストファースト・テスト駆動的な開発がチームでできるとGoDocやJSDoc的にAPI仕様(設計仕様)を残すことにも繋がり、 チーム内に一定の規律や共通見解を育み易く、属人性を下げることにもつながるのではないかと思いました。

参考

docs.github.com www.educative.io


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proの購入はこちらから akerun.com

受託開発とか自社開発とか言うけれど、会社のカルチャー違いや個人差の方が大きい。

この記事は Calendar for Akerun | Advent Calendar 2022 - Qiita の 19日目の記事です。 こんにちはyuyakmです。今回はEM目線での記事を投稿します。

弊社は自社サービス開発がやりたい!という動機で入社する方が多いです。新卒/中途どちらにおいても受託開発と自社開発でどちらが良いかと迷う方が多い印象ですので触れてみたいと思います。

前提

私のスタンス

  • 自社にサービスを開発・運営する組織があることを理想としている
  • 手放しで受託より自社開発が良いと聞くとそれは違うと言いたい
  • 部分的に開発を委託している立場でもある。委託領域もチームの一部

どのような組織を目指しているか

  • PMとエンジニアが1つのプロダクトチームとして日々コミュニケーションを取りながらプロダクトの成功のために協力している
  • 世の中にないものをつくることができる
  • 中長期目線を持ち継続的にサービスを育てる

参考 ユニコーン企業のひみつ www.oreilly.co.jp

参考 プロダクトマネジメントクライテリア - プロダクトをつくるチームのチェックリスト productmanagement-criteria.com

就職先としての受託開発 vs 自社開発

就職活動において、受託開発と自社開発は何かと比較されがちです。 例えば「受託開発はいろんな案件が経験できて良いけど仕様に口出しできないからつまらない」という話はよく聞きます。

就活目線での、自社サービス開発に対してよくある期待とズレ

仕様に対して口出しできる

こうした方が良いのではないかという提案ができるというのはYes。顧客も含めて不要だと思っているが仕様書に記載しているから検収のためだけに用意するというような請負特有の悲しい話も回避可能です。

口出しできる=全て自分の好きなようにできるという期待であればNo。全部好きにできるのは全ての責任を負う社長だけです。自分で起業して自分で資金調達するのが一番確実です。 社内でのキャリアパスとしては、プロダクトビジョンの実現と収益に責任を負うプロダクトマネージャーになるという選択肢もあります。

提案は、開発しているサービスが誰のどのような課題を解決するものなのかを理解した上で、技術的な背景を理解した立場として目的を達成できる方法を提案する流れだとうまくいくことが多いです。開発コストパフォーマンスや既存システムとの依存関係等を考慮することも求められます。 このような提案は受託でも求められていると思います。

自社プロダクトは納期を守らなくて良い

No。自社だからスケジュールの概念がないということはありません。 見込み顧客の要求スケジュールやアライアンスのスケジュール、製造委託先等の外部要因もありますし、完全に自社に閉じていたとしてもスケジュールの目標がないプロジェクトはありません。 受託よりも厳しい状況、例えば仕様を追加しても納期は変えられないという状況もあり得ます。例えば、会社のフェーズによってはPMFするための要求が判明したがバーンレートを考慮すると納期は変えられないという状況もあります。この場合はやるか解散するかの二択です。弊社も創業初期はそういうこともありました。

一方で、社内だからこそ関係者と方針を協議しやすいというのはあるかもしれません。開発プロジェクトは様々な不確実性があるので都度プロダクトマネージャーや事業責任者とリスクについて情報交換し、例えば開発スコープやスケジュールを変更することは理由次第で可能です。

自社サービスだからやりがいがある

Yesです。 自社サービスならではのやりがいの例

  • ローンチした後にユーザーからのFBや利用実態を見ることができる
  • CSやセールス等の他部門と会話することができる
  • プロダクトビジョンや事業成長を考慮して中長期のロードマップを描くことができる

一方で、チームや個人の状態によってNoとなってしまう可能性もあります。 Jiraに割り振られたチケットをリモートワークで処理するだけの毎日というようなことになると自社プロダクトであってもやりがいは感じにくくなります。

また、受託であっても社会的に意義があったり顧客が喜ぶ姿が見えるようなやりがいがあるプロジェクトも多くあるはずです。受託/自社云々よりも会社のカルチャーや自分の関わり方の方が影響が大きいと思います。

採用目線で考えを改めたこと

自社サービスの経験がないと自社サービス開発は難しいというのは誤りだった

自社サービスを開発するにあたって、中途採用においてはこれまでのバックグラウンドにおいて自社サービスの経験がないと難しいのではないかと考えていた時期がありました。しかし、様々なバックグラウンドを持つ方が入社して活躍するのを見た結果考えを改めました。むしろ、受託開発バックグラウンドしかなかったエンジニアも多数リーダーシップを発揮して活躍しています。 結局のところ個人差の方が大きいと感じたポイントです。

例えばこのようなマインドがあるかどうかは前職の業態は関係ないのでは

  • 技術が好き。技術を主体的に学んで何ができるか提案する
  • 専門外の技術があったとしても領域横断で課題を解決しにいく
  • プロダクトビジョン観点での課題を提起して中長期的な設計に取り入れる
  • 属人化しないように設計や手順をドキュメント化する
  • プロダクトやチームの課題を見つけて解決しようとする

「受託やってたから言われたことしかやらない」というのはステレオタイプなイメージです。むしろ受託をやっている会社の方が、クライアントから次の案件をもらうために課題提起や解決策の提案を行っており課題を見つけて提案する姿勢が強いというパターンもあります。

さいごに

受託開発と自社開発の違いについて考えることを書きました。結論としては、受託開発か自社開発かどうかではなく会社と各個人のカルチャーフィットの方が差が大きいのではないかと考えています。 就職先の候補を見つけた際は、カジュアル面談等で相互理解するための時間を十分に取ると良いと思います。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 photosynth.co.jp

オフィス運営やシェアスペース運営、賃貸住宅の物件管理をお考えの際はAkerunにお気軽にご相談ください。 akerun.com

2022年度版 設計書に最適なドローツールは何なのかベストプラクティスを探す終わらない旅

はじめに

この記事は Akerun Advent Calendar 2022 - Qiita の18日目の記事です。

設計書に最適なドローツールは何なのかベストプラクティスを探す

終わらない旅です。

  • ドキュメントとしての管理・公開スキーム
  • シームレスなドキュメント作成と図の編集
  • バージョン・変更管理

にフォーカスしたベスプラを今年も探してきました。

結論だけ知りたい人むけ

Markdown + Honkit + plantuml + VSCode + draw.ioプラグイン が結果最高でした 🎉

Honkitについて

以前、gitbookで設計書を書くお話をブログにしましたが、OSSとしての提供は終了してしまいました。

Gitbook Legacy

As the efforts of the GitBook team are focused on the GitBook.com platform, the CLI is no longer under active development.
All content supported by the CLI are mostly supported by our GitBook.com / GitHub integration.
Content hosted on the legacy.gitbook.com will continue working until further notice. For differences with the new vesion, check out our documentation.

ですが、非常にありがたいことにフォークしたHonkitというツールがメンテされ続けています。

移行も簡単なので弊社も光の速さで移行しました

ドローツール

よく見かけるドローツール

パッケージソフトウェア・Webサービスそれぞれ特徴があります(お値段も) 描画するツールとしてはどれも良いのですが、

画像の編集とドキュメントへの埋めこみをシームレスにできるツールは残念ながら公式ではほぼありませんでした。

MS WordとVisioの組み合わせならできそうですが、ドキュメントが大きくなった際のWordの重さがボトルネックです(閲覧者にとってドキュメントを開くまでの時間は重要な体験)。

その中で、draw.io については以前のブログでも紹介しましたが、更に進化を遂げていました。

  • 比較的軽量
  • 構成図を書くためのアセットが準備されている(アイコンやクラウドサービスのシンボルなど)
  • 操作が直感的
  • VSCodeプラグインが最&高 ← 主にココ

このプラグイン(非公式ながら)が、前述の「画像の編集とドキュメントへの埋めこみをシームレスに」を実現してくれます。

また、draw.io のもう一つ進化したポイントが、Webで使用した場合、同時編集が可能になりホワイトボードのような使い方ができるようになりました。これで他のツールに比べて弱点がほぼなくなったと思います。(ステマではありません)

公式ブログより

Draw.io integration プラグイン

図を保存するディレクトリに、 [ファイル名].drawio.[画像ファイル拡張子] の形式でファイルを作成します。例えば overview.drawio.png とか。

そうすると、あら不思議。VSCode上でdrawioを操作して作図できるようになります。

これで、VSCode上で

  • Draw.ioインテグレーションで図を作成
  • Markdownでドキュメント作成

が可能になりました。個人的にとても気持ちいい。

コードベースUML

システム構成やクラス図など配置に気を遣う・おしゃれに書きたい場合はドローツールをつかいたいですが、シーケンス図・アクティビティ図はコードベースで書くのがおすすめです。 理由は主に経験則ですが、ちょい変で構成全体に手が入るような場合、コードベースで書いておいた方がメンテしやすいです。好みもあると思います。

現在主流は以下の2つ。

  • plantuml
  • mermaid

この中では plantuml に軍配です。mermaidは表現が狭い。やたら図がでかくなるなど、まだまだ課題ありです。GithubのREADMEページがmermaid記法をサポートしたので、ちょっとした図を仕込むにはいいかもしれません。plantumlもサポートしてくれ。

Honkitはumlプラグインを導入することで、plantuml形式で書けます。また、Markdown Preview Enhancedを追加すれば、Markdownプレビューで一緒に表示してくれます。便利です。

ドキュメントの公開

Honkitでビルドした静的ファイルをホスティングすれば、Webブラウザで閲覧できる設計書のできあがりです。

簡単にやるなら GithubActionsでビルドしてGitHubPagesで公開するのが最もお手軽です。

ただし、GithubPagesはユーザー認証できない(たぶん)ので、情報漏えいにご注意ください。 さすがに設計書を一般公開するわけにはいかないので、弊社では AWSを活用し、S3にデプロイ・Cloud FrontとLambda@Edgeで認証+HTTPSでのアクセスになるよう設定しています。

今回このブログもHonkit形式にしてGithubで公開してみました。

完成形がイメージできてるのもありますが、とても簡単に公開までできました。

終わらない旅

ツールは日々進化するし、使い慣れたツールが突然使えなくなることもある。ベスプラ探しの旅は来年も続きます。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com

エンジニア採用担当者のこころえ

こんにちは。 フォトシンスでエンジニア採用をやっております@YUKI_0405と申します。

フォトシンスのエンジニア採用担当者として今回、こちらにブログを書かせていただくことになりました。

このブログでは、私個人としての 「エンジニア採用担当者のこころえ」 を綴りたいと思います。

【目次】

1. 初めに

前提として、お役にたてる情報は特にないと思いますので、目次からご興味が湧かない方は、ここでご拝読を終了していただくことをお勧めいたしますm( )m

まず最初に、私の自己紹介を簡単にさせていただきます。

結論から申し上げますと、人事のキャリアは約10年ほどあるものの、 採用担当としての経験はまだまだひよっこ🐥レベルです・・ 。 なので、これから書き連ねることに対しても、温かい目で読んでいただけますと幸いです。

私の人事としてのキャリアは、前職からスタートしました。
前職は人材派遣/営業代行の会社で、そこで未経験から労務を始めて約4年間、フォトシンス 入社2年目まで通算約6年間、労務領域にいました。
今から3年前に、キャリア採用担当としてエンジニア職を含む全職種の採用をした後、 現在は主にエンジニア採用をミッションに日々奮闘をしています。

何をやっているか


  • 採用戦略策定
    ・採用手法の計画立案

具体的には・・

「このポジョションはエージェントさんの方がターゲット見つけやすいよね」や、 「ダイレクトリクルーティング媒体はこれよりあっちの方がターゲットいそうだよね」 など 部門からのバックオーダーに基づいて効果性が高そうな手法のバランスの道筋を概ね立てます。 (とはいえ、現実は全ての手法を全網羅的にやらないと難しいですが..)

  • 部門と求人の擦り合わせ
    ・ターゲットのペルソナヒアリング ・スカウトの基準設定

  • スカウト文の作成&エージェントさんとの打ち合わせ
    ・ダイレクトリクルーティング: ポジションごとにテンプレートを作成
    ・エージェントさん: 部門とすり合わせをした求人内容やペルソナについて、ターゲット目線と乖離が出ないよう具体的にすり合わせをして、よりマッチ度が高い候補者を見つけていただく準備をする

  • スカウト&候補者進捗

  • カジュアル面談or面接(※面接はエンジニアの方が担当)

  • クロージング


細かいところはまだまだありますが、大枠は上記のようなフローで採用活動をしています。

2. エンジニア採用担当になってまずやったこと

採用担当になって3年経ち、今でこそ基本の知識はわかるものの(まだまだ勉強することは沢山ありますが)、エンジニア採用を始めた頃は「コードって何?」のレベルからのスタートで、本当にダメダメでした。

そんなレベルの奴が、「最低限の知識だけは身につけたい、開発についてもっと知りたい」といった単なる私の探究心と興味と担当者としての責務の想いから、【エンジニア採用担当者のこころえ】として、まずは3つのことを実施しました。

・エンジニア採用の本を読みまくる
・つてを使ってエンジニア採用をやっている人事の方に、やっていること、成功事例などの話を聞きまくる
・エンジニア採用に特化したエージェントさんに市況感やターゲットデータベースなどを聞きまくる

実施してよかったこと

・「勉強」の観点でやっていなかったため、すぐに実務に落とし込めるイメージが湧き、その分、吸収力が抜群によかったこと

・同職種の方々の苦戦していること、実体験のお話で、これから来るであろう波に対してある程度の心の準備ができたこと(これめっちゃ大事でした)

・成功事例を真似してみて、自社や自分のやり方と合っているかの検証ができた

・プロであるエージェントさんのお話しや提案などを聞いたりある意味、壁打ち相手ができたこと

非エンジニアの担当者が、「コードについて詳しく話して!」と言われた場合、Google先生に味方をしてもらったとしても、技術本を読んだとしてもきっとちんぷんかんぷんです。 ですが、わからないなりにもエンジニア採用担当者としての基礎知識は覚えていた方が、面談時にエンジニアの方とのお話もスムーズになると思いますし、スカウト作業や採用実務できっと役に立つと思います。もし、これから1人体制でエンジニア採用を始められる方がいらっしゃいましたら、まずはこちらを実践いただくと知識だけでなく気持ちも楽になるかもしれません。

私がエンジニア採用のスタートとして読んだ本の一部をご紹介します。有名な本なので読んだことがあるエンジニア採用担当者は多いと思いますが、技術や基本的な開発環境に対して優しく説明されていて読みやすいです。

参考本

https://www.amazon.co.jp/%E4%BD%9C%E3%82%8B%E3%82%82%E3%81%AE%E3%83%BB%E4%BD%9C%E3%82%8B%E4%BA%BA%E3%83%BB%E4%BD%9C%E3%82%8A%E6%96%B9%E3%81%8B%E3%82%89%E5%AD%A6%E3%81%B6-%E6%8E%A1%E7%94%A8%E3%83%BB%E4%BA%BA%E4%BA%8B%E6%8B%85%E5%BD%93%E8%80%85%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AEIT%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%AE%E5%9F%BA%E6%9C%AC%E3%81%8C%E3%82%8F%E3%81%8B%E3%82%8B%E6%9C%AC-%E4%B8%AD%E5%B3%B6-%E4%BD%91%E6%82%9F/dp/479816531X/ref=asc_df_479816531X/?tag=jpgo-22&linkCode=df0&hvadid=342595526565&hvpos=&hvnetw=g&hvrand=14978878202848301864&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009343&hvtargid=pla-901708087633&psc=1&th=1&psc=1www.amazon.co.jp

https://www.amazon.co.jp/%E9%9D%9E%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E4%BA%BA%E4%BA%8B%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E6%8E%A1%E7%94%A8%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%EF%BD%9E%E3%83%80%E3%82%A4%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%82%AF%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%AE%E5%A7%8B%E3%82%81%E6%96%B9%EF%BD%9E-%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BEJELLYFISH/dp/4814925298/ref=asc_df_4814925298/?tag=jpgo-22&linkCode=df0&hvadid=588980016217&hvpos=&hvnetw=g&hvrand=836347945083156382&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1028853&hvtargid=pla-1648058463088&psc=1&th=1&psc=1www.amazon.co.jp

3. エンジニア採用への想い

現在の市場感として、エンジニア採用は高難度と言われていて、私自身も本当にそう感じます。
採用がうまくいっている企業さまのお話を聞いても、同じようなことを網羅的にやっている気がしてならず、「あとは何をやったら良いのか」、「何をやるべきなのか」、「やれることってあるの?(ないわけないじゃん。と自分でツッコミ入れてますが)」などなど、採用戦略的なところで悩んでいる事は、本音としてあります。

でも、私はエンジニア採用が楽しくて仕方がないのです。エンジニア採用のご縁をいただけて有り難いと思いますし、これからもやっていきたいと思っています。

なぜ?とよく言われますし、周りから見たら苦悩しかないと思われているかもしれません。ですが、人からどう思われていようとも、私はエンジニア採用が楽しくて仕方ないです。(2回言った!)

理由は沢山あるのですが、大きくは2つあります。


理由① 現場と協業して採用活動ができること

理由② 難易度が高い分のやりがいと達成感があること

▼理由① 現場と協業して採用活動ができる

企業さまによって様々だとは思いますが、フォトシンスは採用と現場の距離が近くそれぞれの役割を分担して採用活動をしています。

私は、採用において最も大事なことが、これだと思っています。「点と点がつながり線になっていく」一点だけでは線にならないので、個々の協力があってこそ採用成功ができるものだと考えています。

開発採用に関してでいうと、例えば組み込みエンジニアの方のクロージング面談などにWEBエンジニアに参加していただいたり、逆も然りのようなことが当社では常にあり、人事⇆募集職種のエンジニアだけでなく、全職種のエンジニアが一体となり領域を超え協力し合いながら採用活動をしています。

非エンジニアの担当者が技術のことを話すことは難しいと前述させていただきましたが、 採用担当としての役割は他にもたくさんあるので、個々の役割を最大限に出しながら同じ目的に向かって一緒に活動する。 企業カルチャーにも起因することなので、これが正解!はないですが、私個人の“こころえ“としては、

「エンジニアにはなれないけれど、自社の開発環境についてできる限りのインプットをして、 採用に対して最大限のアウトプットをしていく。」 エンジニア採用担当としての出来うる範囲以上のことを常に考え実行していくこと。を大切にしています。

▼理由②難易度が高い分のやりがいと達成感がある

“達成感“をどこに置くかは人それぞれだと思いますが、わかりやすいところでいうと、入社の意思決定(内定承諾)をいただけた時でしょうか。

まず、当社のエンジニア採用手法としては大きくは下記の2つです。

・ダイレクトリクルーティング
・人材紹介会社経由

一般的にエンジニア採用は、ダイレクトリクルーティングの比重が高くなるかと思います。 当社でも同じ感覚です。
ダイレクトリクルーティングでは、一般的なフローと同じく主に下記の流れと気持ちで進めています。


  • 1.ターゲットにスカウト送信

→1人のエンジニアに対して数十社の企業から受信されている想定でいる

  • 2.スカウトの返信がくる

→送信数に対して返信数は数%のレベルなので、とっても嬉しい!
(けれど、当社だけではないでしょう・・)

  • 3.カジュアル面談

→興味を持っていただくために自社のアピール頑張る時間

  • 4.選考意思をいただく

→ちょうど転職の時期だったこと、興味を持っていただけたことのタイミングが重なりここで初めて選考進捗となる
(だけど、当社だけではないでしょう・・)

  • 5.選考フェーズ(当社は選考2回~3回)

→他社との選考スケジュールも鑑みながら候補者様と接点を持ち意欲を保っていただきながら進捗を進めていく。また、技術だけではなくカルチャーマッチも必要になってくるので、双方のマッチ度が高くないと双方またはどちらかが選考継続しないこともあります。

  • 6.内定フェーズ

→オファー!!と喜ぶのも束の間、オファーを出す企業は当社だけではないので、意思決定をいただくための最終クロージングに尽力する


私のこころえとしては、入社の意思決定をいただくことが採用のゴールではないので、入社後のミスマッチが出ないように、アピールだけでなく課題や現状もちゃんと話すことを念頭に置いています。

どのタイミングでも、沢山のライバル企業が常に隣にいる状況なのでその分、意思決定をいただく可能性も低くなってきます。

もちろんこれはエンジニア採用だけに限ったことではないですが、1人のエンジニアに対して数十社のライバルがいるこの現実で、当社に入社を決めていただく事は簡単ではないです。

ですが、意思決定いただけた時の嬉しさは壁が高い分に大きいものだと思います。

それが、私がエンジニア採用をやっているモチベーションの一つになっているのです。

(では、どうやったら採用成功まで辿り着くのか・・の議論はまたの機会にしたいと思います。)

4. 最後に

ここまで読んでいただきありがとうございました。

エンジニア採用は結果が中々出ない分、苦しいことも多い。とよく聞きますが、自社で働くエンジニアの方々のために。と思えば、その苦しさも糧になるのではないでしょうか。

締めが精神論みたいになってしまいましたが、 自分のこころえを決めて実行してみると、意外と楽しいものです。

採用のプロだね!と言われるようにこれからも精進したいと思います。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com

皆どのようにしてコードを書いてるのか?

この記事は Akerunのカレンダー | Advent Calendar 2022 - Qiita の 24日目の記事です。 こんにちは Esperna - Qiitaです。ファームウェアの開発を担当してますが、最近nodeJSとGoを触ることが多いです。

背景

コードを書くときって皆どんなプロセスで書いてるのか気になりませんか。自分は気になってます。 個人的にはこれまで複合機、電子黒板、車載カメラ、SSD、スマートロック等の組み込みソフト寄りの開発をしてきましたが、 製品、業界、開発のフェーズ(研究・要素開発よりから製品開発、運用・保守までのどこか)等によって、 ソフトウェアのコンストラクション*1の仕方が異なります。 そこで、まずは改めて自分がどのようにしてソースコードを書いているのか整理してみました。

内容

仕様と既存の設計(というかソースコード)を読んで、要求を整理した後、(可能であれば)クラス図を書いて、どのクラスに何をさせるか整理します。 その後、ソースコードを書くより前に単体テストを書いてソースコードを書いてます。 ソースコードを書くまでに下記の設計の成果物までは書きたい派です。 実際に書くかどうかは開発期間、プロジェクトの状況、会社の文化だったりその時々によります。 以下はソースコードを書いていく過程でアウトプットとして意識する成果物のフォーマットの一例です。

成果物フォーマットの一例

背景
目的
スコープ(どの機種・プロジェクトに適用されるのか)
要求分析
テスト設計
  • テスト仕様書
分析
  • クラス図(責務分担)
設計
  • 設計指針
  • クラス図
  • シーケンス図
  • 状態遷移図
実装
テスト
  • テスト結果報告書

下記は上記の成果物に対して私が思うところです。

成果物 内容 何故必要か
要求分析 やることリスト プログラミングをすることで実現する振る舞いのリストを書く。 ソフトウェアを書くことでどんな振る舞いを実現するのか明確にするため
テスト仕様 主に実機テスト仕様を書く(なるべくテストファーストで(ソースコードを書く前に)書く)。可能なら他の人が見て同じ手順を実行できるレベルで書くのが理想。 評価の視点を明確にするため。評価項目に漏れがないことを確認するため。評価手順を明確にするため。
ユースケース図(ユースケース記述) システムに関わるステークホルダを明確にする。ユースケースに関わるシナリオを明確にする。 ユーザの使い方や運用を含めたシステム全体のシナリオを意識するため
分析 クラス図(責務分担) 各クラスの責務を整理する 特定のクラスに責務が集中してコードが複雑になったり、密結合になったり、ソースコードの可読性が下がるのを避けるため
設計 クラス図 データ構造やデータの有効範囲、スコープ、責務の整理を行う ソースコードが複雑になったり、ソースコードの可読性が下がるのを避けるため
状態遷移図 各状態に応じたイベントの有無、イベントに対する振る舞いを明確にする 状態に応じた複雑な振る舞いをバグらずに書くため
シーケンス図 ソフトウェアの動的な振る舞いを記述する インスタンスの処理の流れを明確にするため
実装 ソースコード 関数やメソッドの詳細を実装する ないとソフトウェアは動かないため
静的解析結果 lintやQACを実施する バグを回避するため。Warningが多いとより危険なWarningを見落とすことがあるため。
テスト 単体テスト報告書 単体テストカバレッジレポート どのパスがテストされていてどのパスがテストされていないかを明確にするため。カバレッジ(%)は参考値。
結合テスト報告書 実機で動作確認した結果を書く。エビデンスのログを残す。 評価のエビデンスを残すため。テストチームへの参考資料として共有するため。

所感

こうして書いてみると全部やるのはなかなか大変ですね。でも、

  • 自分たちが作っているのは製品ではなくサービスなので、ユーザシナリオや運用、セキュリティ含めてサービスやシステム全体のシナリオをもっと意識して要求分析の成果物を残しつつコードを書きたい
  • 責務を明確にして設計が複雑にならないようにするためにクラス図を書くことを大事にしていきたい
  • コマンドを打ってクラスやメソッドの説明が出てくると調査に便利なのでGoDocのようなものを残していきたい

と思いました。他のエンジニアがどのようにしてコードを書いてるかぜひ知りたいです。

参考文献

https://www.amazon.co.jp/CODE-COMPLETE-%E7%AC%AC2%E7%89%88-%E4%B8%8A-%E5%AE%8C%E5%85%A8%E3%81%AA%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%97%E3%81%A6/dp/489100455X/ref=sr_1_1?adgrpid=56168912107&gclid=Cj0KCQiA-oqdBhDfARIsAO0TrGF0h9tz-imW_eJlUIdfw6zZzWP54_Lq8ZJJaiIdTuRQc9gYhbN7b9AaAtbbEALw_wcB&hvadid=611408443601&hvdev=c&hvlocphy=1028853&hvnetw=g&hvqmt=e&hvrand=12532948818991730462&hvtargid=kwd-27623266&hydadcr=27488_14587134&jp-ad-ap=0&keywords=code+complete&qid=1671665661&sr=8-1


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com

*1:CODE COMPLETE 第2版上に「ソフトウェアを作るプロセスを意味する用語で、詳細設計、コーディング、統合、単体テスト、統合テストが主なアクティビティである」旨が記載されている