本番データを使った検証を手軽にできる仕組みの構築

ロジクラでエンジニアをしている高梨です!

前回のstagingDev環境構築に引き続き、DevOps周りの改善を紹介します! 普段開発を進めていると、本番のデータを利用したいと思うことがよくあったりしますよね?

例えばロジクラでは

  • 顧客からの不具合問い合わせの検証
  • 新機能の仕様検証
  • 新機能のパフォーマンス検証
  • ...etc

などなど、色々なタイミングで本番データを利用したいと思うタイミングがあります。

ただし手動でやろうとすると、本番環境のデータベース周りを触ることになるのでセキュリティ上のリスクや誤操作のリスクがかなり高く、なかなか気軽にできません。

ロジクラではこういった課題をクリアし、誰でも本番データを利用できるような仕組みを作ったので今回はそちらを紹介します!

仕組みの概要

冒頭にいったような、セキュリティ上のリスクや誤操作のリスクを回避し、手軽に本番データが利用できるようにするため、開発者が簡単なアクションをするだけで本番データをマスキングしたデータが入ったデータベース ( 社内ではcloneDB と呼んでいます) を立ち上げ、stagingDev環境からそれを確認できるようにすることをソリューションとしました。

処理の実行には、いつものように github actoinsを利用しています。 github actionsでは以下のようなスクリプトを叩いています。

DBの複製

#!/bin/sh
export AWS_PAGER=""

usage () { echo "Usage : $0 -c <CLONE_DB_CLUSTER_IDENTIFIER> -i <CLONE_DB_INSTANCE_IDENTIFIER> -P <MASTER_USER_PASSWORD>"; }
while getopts c:i:p: OPT
do
  case $OPT in
    c) CLONE_DB_CLUSTER_IDENTIFIER=$OPTARG
      ;;
    i) CLONE_DB_INSTANCE_IDENTIFIER=$OPTARG
      ;;
    p) MASTER_USER_PASSWORD=$OPTARG
      ;;
  esac
done

if [ ! "$CLONE_DB_CLUSTER_IDENTIFIER" ] || [ ! "$CLONE_DB_INSTANCE_IDENTIFIER" ] || [ ! "$MASTER_USER_PASSWORD" ]
then
  usage
  exit 1
fi

DB_SUBNET_GROUP_NAME=logikura-xxx
VPS_SECURITY_GROUP_ID=sg-xxx
SOURCE_DB_CLUSTER_IDENTIFIER=logikura-xxx

# DBClusterのclone
echo "cloning database..."
aws rds restore-db-cluster-to-point-in-time \
  --source-db-cluster-identifier $SOURCE_DB_CLUSTER_IDENTIFIER \
  --db-cluster-identifier $CLONE_DB_CLUSTER_IDENTIFIER \
  --restore-type copy-on-write \
  --use-latest-restorable-time \
  --db-subnet-group-name $DB_SUBNET_GROUP_NAME \
  --vpc-security-group-ids $VPS_SECURITY_GROUP_ID

## DBClusterにDBInstanceを作成
echo "creating database instance..."
aws rds create-db-instance \
  --db-instance-identifier $CLONE_DB_INSTANCE_IDENTIFIER \
  --db-cluster-identifier $CLONE_DB_CLUSTER_IDENTIFIER \
  --db-instance-class db.t3.medium \
  --engine aurora-postgresql
aws rds wait db-instance-available --db-instance-identifier $CLONE_DB_INSTANCE_IDENTIFIER
aws rds modify-db-cluster \
  --db-cluster-identifier $CLONE_DB_CLUSTER_IDENTIFIER \
  --master-user-password "${MASTER_USER_PASSWORD}" \
  --apply-immediately

すでにあるDBをリストアしています。コマンドの詳細は公式のドキュメント をご覧ください!

ただしこのままでは本番のデータがそのまま利用できてしまうのでセキュアではありません。問題に対応するため、隠しておきたいデータをマスキングする処理を実行しています。

マスキング

#!/usr/bin/env ruby
require 'optparse'
require 'securerandom'

clone_db_host = nil
opt = OptionParser.new
OptionParser.new do |opt|
  opt.on('--clone-db-host VALUE', 'clone db host name') { |v| clone_db_host = v  }
  opt.parse(ARGV)
end
raise "required clone_db_host" if clone_db_host.blank?

settings = YAML.load_file("config/settings/masking.yml")

raise "saftiy" if Rails.env.production?
raise "saftiy" unless clone_db_host.match(/clone/)

ActiveRecord::Base.establish_connection(
  ActiveRecord::Base.connection_config.merge(host: clone_db_host, database: "logikura_production"),
)
settings["tables"].each do |table_name, column_names|
  sql = "UPDATE #{table_name} SET"
  update_terms = column_names.map do |column_name|
    "#{column_name} = uuid_generate_v4()"
  end
  ActiveRecord::Base.connection.execute("UPDATE #{table_name} SET #{update_terms.join(', ')}")
end

ymlにtableとcolumnの定義を買いてuuidで埋めてるシンプルな実装です。

以上を実行するとこで、本番相当のデータを安全に利用することができます!

最後にgithub actionでdbのエンドポイントをコメントするようにしているので、そのエンドポイントを利用して検証などを進めています 🎉

f:id:logikura:20211229133344p:plain

エンジニア以外での利用

前回の記事 で検証環境( 通称stagingDev環境 )をbranchごとに手軽に作る仕組みを紹介させて頂きましたが、staginDevの立ち上げ処理には環境変数を設定できるフックポイントがあります。

test -f staging_dev.env && export $(cat staging_dev.env)
if [ -e "./deploy/staging_dev_env/${STAGING_DEV_BRANCH}.env" ]; then
  export $(cat ./deploy/staging_dev_env/${STAGING_DEV_BRANCH}.env | grep -v ^# | xargs);
fi

これを利用して、 branch_name.env

DB_HOST=xxx

のように書いておくと、立ち上げた環境が接続するDBホストの値をoverrideして変更することができます。 検証環境で手軽に本番データを扱うことができるので、開発者だけではなくカスタマーサクセスのメンバーやセールスのメンバーも、マスキングされた安全なデータを問い合わせの対応や機能検証の際に気楽に使うことができます!

まとめ

本番とほぼ同じデータをいつでも利用できるようにしたことで、より正確な検証を行うことができ、顧客への対応や機能リリーススピードが改善しました 🙌 ローカルやstagingだとレコード数が少ないので常に高速に動いてる感じになりますが、実際にお客さんの環境を再現することでボトルネックに気づけることがあります。

また、ロジクラの開発チームでは週に1度パフォーマンス改善の取り組みをチームで行っているのですが、その際の検証環境としても本番環境のデータをcloneしたデータベースが施策の検証のために役立っています!

スタートアップのフェーズでは機能開発に追われがちですが、このような基盤の改善を進めることでさらに開発スピードをあげていき、より良いサービスの提供を進めていっています 👍

最後に

ロジクラでは一緒に開発してくれるメンバーを募集しています!

マスキングスクリプト実行に時間がかかるので、もっと良いソリューションある方 & ロジクラに興味ある方はぜひ こちら をご覧ください!

検証環境をbranch毎に作ってリリーススピードを改善した話

自己紹介

ロジクラでエンジニアをしている高梨です!

前回ロジクラのインフラ構成を紹介 したのに続き、今回もロジクラの開発を支えている環境周りに関して、リリーススピードを数倍にした例を紹介していきます!

以前ロジクラではチーム開発を進めていく中で、機能検証がスタックすることによって開発のスピードが停滞するという課題が発生していました。

具体的な問題としては、検証環境がstagingしか存在しておらず、複数の機能開発が同時に進んでいる場合に、PMなどに仕様を満たしているか確認してもらう順番待ちが発生したり、手直しがあった際に巻き戻しコストがかかりリリースが遅れるということがあります。

結果として、大きめの機能が入ってくるとリリース頻度が週に1度ほどになってしまうことがよくありました。

仕組みの概要

上記の問題を解消するため、変更した機能ごとに開発者以外が簡単に検証することができる stagingDev という環境を用意することをソリューションとしました。

branchごとにサブドメインの割り振りとECSのタスクを立ち上げ、今まで通りstagingのDBにアクセスできるようにして社内メンバーなら誰でも検証できるというものです。

処理の実行には github actoinsを利用しています。

以下に実際の設定を貼ります。

name: StagingDev作成君

on:
  pull_request:
    types: [opened, synchronize]
env: ...

jobs:
  build:
    if: contains(github.event.pull_request.labels.*.name, 'StagingDev')
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: kayac/ecspresso@v1
      with:
        version: latest
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with: ...
    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1
    - name: Setup Environment
      run: ... # 必要な環境変数の準備

    - name: Build Image
      run: |
        ./deploy/docker_build.sh staging ${{ secrets.IMAGE_REPOSITORY_URI }} $BRANCH_NAME ${{ secrets.SIDEKIQ_CREDENTIAL }} $BRANCH_NAME
        docker push ${{ secrets.IMAGE_REPOSITORY_URI }}:$BRANCH_NAME

    - name: Setup
      if: env.SETUP_COMPLETED == 'false'
      run: |
        # priorityが重複するとエラーになるので最大値を取得して重複しないようにする
        PRIORITY=$(aws elbv2 describe-rules --listener-arn ${arn} | jq -r '.Rules | map(select(.Priority == "default" | not) | .Priority | tonumber) | max + 1')
        # cloudformationでターゲットグループ, リスナールール, レコードセットの作成
        aws cloudformation create-stack \
          --stack-name $STACK_NAME \
          --template-body file://$(pwd)/deploy/cloudformation/staging_dev.yml \
          --parameters ParameterKey=BranchName,ParameterValue=$BRANCH_NAME ParameterKey=ListenerPriority,ParameterValue=$PRIORITY
        # 完了するまで待つ
        aws cloudformation wait stack-create-complete --stack-name $STACK_NAME

        TG_NAME=$STACK_NAME
        export TARGET_GROUP_ARN=$(aws elbv2 describe-target-groups --query "TargetGroups[?TargetGroupName == '$TG_NAME'] | [0]" | jq -r .TargetGroupArn)
        export BRANCH_NAME=$BRANCH_NAME
        export IMAGE_TAG=$BRANCH_NAME
        export ENTRY_POINT='"./deploy/init.sh"'
        # ECS Serviceの作成
        ecspresso create --config ./deploy/ecs/logikura-web-staging-dev/logikura-web-staging-dev.yml
        ecspresso create --config ./deploy/ecs/logikura-worker-staging-dev/logikura-worker-staging-dev.yml

    - name: Deploy
      if: env.SETUP_COMPLETED == 'true'
      run: |
        TG_NAME=$STACK_NAME
        export TARGET_GROUP_ARN=$(aws elbv2 describe-target-groups --query "TargetGroups[?TargetGroupName == '$TG_NAME'] | [0]" | jq -r .TargetGroupArn)
        export BRANCH_NAME=$BRANCH_NAME
        export IMAGE_TAG=$BRANCH_NAME
        export ENTRY_POINT='"./deploy/init.sh"'
        ecspresso deploy --config ./deploy/ecs/logikura-web-staging-dev/logikura-web-staging-dev.yml
        ecspresso deploy --config ./deploy/ecs/logikura-worker-staging-dev/logikura-worker-staging-dev.yml

    - ... # issueへのコメントやslack通知処理

上記の処理の流れを簡単に説明します!

  1. PRに StagingDev ラベルを貼り、そのPRに変更をプッシュすることによってActionがトリガ
  2. 該当ブランチで利用する環境変数をセット
  3. 該当ブランチのイメージを生成
  4. 用意しているcloudformationの設定を利用し、リソースを構築
    • Route53
    • LB (target groupの設定など)
  5. タスクのデプロイ
  6. 完了したらurlをPRにコメント

f:id:logikura:20211129120805p:plain

最後にslack通知を行います🚀

f:id:logikura:20211129120831p:plain

ちなみに設定は紹介しませんが、PRをクローズすると環境が消されるactionも用意しており、環境が作られっぱなしになることが内容になっています 👌

リソースの構築について

ざっくりとした環境構築までの流れは理解いただけたかなと思うので、ここからさらにstagingDev環境を具体的にどう構築しているかを記載します。

前回の記事でも紹介したようにロジクラはAWS上でECSを利用して運用されています。

実際に検証できる環境を作るためには、branchごとの変更がdeployされたECSの新しいタスクに対して独自のurlからアクセスできるようにリソースを作らないといけません。

CFでTGとRecordSetの作成

まず設定から記載します。

AWSTemplateFormatVersion: "2010-09-09"
Description: ""
Parameters:
  BranchName:
    Type: String
  VpcId:
    Type: String
    Default: 
  AlbArn:
    Type: String
    Default:
  Listener443Arn:
    Type: String
    Default: 
  ListenerPriority:
    Type: Number
Resources:
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 10
      HealthCheckPath: "/"
      Port: 80
      Protocol: "HTTP"
      HealthCheckPort: "traffic-port"
      HealthCheckProtocol: "HTTP"
      HealthCheckTimeoutSeconds: 5
      UnhealthyThresholdCount: 2
      TargetType: "ip"
      Matcher:
        HttpCode: "200"
      HealthyThresholdCount: 5
      VpcId:
        Fn::ImportValue:
          !Sub "${VPCStack}-VPC"
      Name: !Sub "logikura-tg-ecs-${Environment}"
      HealthCheckEnabled: true
      Name: !Sub "staging-dev-${BranchName}"
      Port: 443
      Protocol: HTTP
      TargetType: ip
      VpcId: !Ref VpcId
  ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup
      Conditions:
        - Field: host-header
          HostHeaderConfig:
            Values:
              - !Sub "dev-${BranchName}.com"
      ListenerArn: !Ref Listener443Arn
      Priority: !Ref ListenerPriority
  RecordSet:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      HostedZoneName: logikura.com.
      RecordSets:
      - Name: !Sub "dev-${BranchName}.com"
        Type: CNAME
        TTL: '60'
        ResourceRecords:
        - ***.elb.amazonaws.com

awscliで作っても良いのですが、削除が簡単にできるようにCFを採用しています。 terraformを利用している会社ではterraformで書き換えてもらってもよいかと思います!

最終的にbranch毎に割り振られたurlにアクセスすると、以下のようにbranch毎の変更が反映されたリソースにアクセスできます!

f:id:logikura:20211129120900p:plain

リソースの削除について

削除はCFで作ってるので簡単です。

githubactionsでPRが閉じた際にECSとELB等をまとめて消してます。

ecspresso delete --config ./deploy/ecs/logikura-web-staging-dev/logikura-web-staging-dev.yml --force
ecspresso delete --config ./deploy/ecs/logikura-worker-staging-dev/logikura-worker-staging-dev.yml --force

aws cloudformation delete-stack --stack-name $STACK_NAME
aws cloudformation wait stack-delete-complete --stack-name $STACK_NAME

一つ注意としてはPRの削除のたびに実行するとエラーになるので、stackが存在するかチェックする必要があります。

aws cloudformation describe-stacks --stack-name $STACK_NAME

注意事項

cloudformationのstackNameの制約で、 [a-zA-Z][-a-zA-Z0-9] にbranch名を限定しないとリソースの作成が失敗してしまうという問題があります。

branch名のルールが決まっていれば問題ないのであえて解決していませんが、もし命名に異なるルールがあるチームの場合は注意してください!

まとめ

ブランチごとに開発者以外が動作検証できる環境を作ったことで、それぞれの環境で仕様確認が同時並行で行うことができ、リリースがスタックすることがなくなりました 🙌

結果的に開発からユーザーに利用してもらうまでのスピードが数倍早くなり、顧客への提供スピードが上がっただけではなく、誰でも自由に検証できる環境があることで事前の社内周知やガイド作成など会社全体とし業務スピードをあげることにも成功しました!

今後も開発がスケールする仕組みを作っていき、さらに顧客へ価値を届けることができるようにしていきたいです 👍

最後に

強引にシェル芸で解決してる部分もあるのですが、もっとスマートにしていきたいので、 ロジクラでは一緒に開発してくれるメンバーを募集しています!

興味がある方はぜひ こちら をご覧ください!

現状のインフラ構成とワーカーのオートスケール

現状のインフラ構成とワーカーのオートスケール

ロジクラでテックリードをしている高梨です! サービスが公式に公開される前から技術選定だったり、実際にコード書いたり、インフラやSRE的なことまで色々やってます。 最近は愛犬と遊ぶのにはまってます。

f:id:logikura:20211124171041j:plain

概要

ロジクラは今年、AzureからAWSへとインフラの移行を行いました 🎉

当初ロジクラはAzureを利用していました。利用していたAppServiceは十分要件を満たすことができ、Microsoftさんからのサポートも手厚かったことが主な理由で利用していたのですが、会社のフェーズが進み、今後さらに事業拡大し開発組織を大きくしようと考えたとき、リファレンスが充実しており、経験者が多いAWSに移行して採用につなげることを主な目的にインフラ移行を決定しました。 ここでは現状のロジクラのインフラ構成と、移行時に工夫した点などを紹介していきます!

今回移行したものはメインサービスである在庫管理のSaaSのロジクラです。

必要な仕組みとして大まかに説明すると、

  • メインのサービスを乗せているサーバー・DB
  • 非同期処理を行うためのサーバー
  • 非同期処理を行うためキューを貯めるRedis

というシンプルな構成になっています。

管理やスケールの容易さから今回メインのサービスを載せるサーバーについては、ECS・Fargateを利用することにしました。

構成紹介

載せきれない部分もあるのですが、大まかな構成としては以下のようなシンプルな構成になっています。

f:id:logikura:20211110165801p:plain

次にこの構成を作っていった中で、特に工夫していった点を紹介していきます。

デプロイについて

デプロイに関してはgithub actionをトリガーにしています。stagingとproductionでトリガーは異なるのですが、deploy処理に関しては以下のgithub actionの設定ファイル(不要な部分はカットしています)のように、buildしたimageを一度ECRに置き、そのimageを利用してdbのmigrationを行った後にdeployする流れとなります。

...
jobs:
  ...  
  build_image:
    runs-on: ubuntu-latest
    steps:
    - uses: nelonoel/branch-name@v1.0.1
    - name: Check out code
      id: checkout
      uses: actions/checkout@v2

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ secrets.AWS_REGION }}
    - name: Set environment
      id: set_environment
      run: {{環境変数を設定する処理}}

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1
    - name: Build Image
      run: {{deployするimageをbuild}}

  deploy:
    needs: [build_image]
    runs-on: ubuntu-latest
    env:
      IMAGE_TAG: ${{ needs.build_image.outputs.image_tag }}
    steps:
    - uses: kayac/ecspresso@v1
      with:
        version: latest
    - name: Check out code
      id: checkout
      uses: actions/checkout@v2
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ secrets.AWS_REGION }}

    - name: Database Migration
      run: {{DBのmigrate処理}}

    - name: Quiet Sidekiq Process
      run: {{Sidekiqプロセスの停止}}

    - name: deploy
      run: |
        ./deploy/ecs_deploy.sh -t web -e staging -i $IMAGE_TAG
        ./deploy/ecs_deploy.sh -t worker -e staging -i $IMAGE_TAG

実際のdpeloyに何しては、カヤック製のecspressoを利用しており、以下コマンドで $SERVICE_NAMEごとの設定(productionやstagingなどを入れています)を読み込んでいます。

ecspresso deploy --config ./deploy/ecs/${SERVICE_NAME}/${SERVICE_NAME}.yml --rollback-events DEPLOYMENT_FAILURE
ecspresso wait --config ./deploy/ecs/${SERVICE_NAME}/${SERVICE_NAME}.yml

詳しくはecspressoのレポジトリをご覧ください!

タスクに関してもgithub actionから実行したいコマンドと環境を指定して実行するよう設定しています。

以下がecspressoでの実行コマンドになります。

ecspresso --config ./deploy/ecs/${SERVICE_NAME}/${SERVICE_NAME}.yml run --overrides="{\"containerOverrides\":[{\"name\":\"logikura-ecs-container-web-${APP_ENV}\", \"command\":[\"./deploy/run_command.sh ${COMMAND}\"]}]}"

最後にdeployとタスク実行ともに、完了するとslack通知が流れてきます。

f:id:logikura:20211110171022p:plain

以上が基本的なdeploy周りの設定となります!

オートスケールについて

構成の中で工夫した点としては、workerのオートスケールの仕組みを導入したことです。

ロジクラは、利用者の性質上、例えば商品登録や出荷データの登録など、大量のデータを一度に処理したいと言う要望が多く、非同期処理を行うことが必要になっています。

ただ、処理が集中した場合jobが詰まってしまうと言うことが発生し得ます。顧客も増えている ⇒ 安定的に全てのお客さんにシステムを使ってもらうために、job数に応じてオートスケールする仕組みを取り入れています。

credentials = Aws::Credentials.new(ENV["AWS_ACCESS_KEY_ID"], ENV["AWS_SECRET_KEY"])
client = Aws::CloudWatch::Client.new(region: EMV["AWS_REGION"], credentials: credentials)
client.put_metric_data({
    namespace: "SidekiqJobCount",
  metric_data: [
    {
       metric_name: "job_count",
       dimensions: [
          {
            name: "app_env",
            value: ENV["RAILS_ENV"],
          },
        ],
        value: Sidekiq::Stats.new.enqueued,
        unit: "Count",
    },
  ],
})

落ち着いたらスケールインしたくなりますが、処理の途中で落としてしまうと設計によっては問題が生じる場合があるかと思います。

https://github.com/mperham/sidekiq/wiki/Signals#tstp

SidekiqはTSTPシグナルを送ると新しいジョブの取得を停止し、処理が終わると停止します。

この仕組を利用して、TERMをtrapしてSidekiqを安全に停止するようにしました。

function trap_term() {
  SIDEKIQ_PID=`ps -ef  | grep -v grep | grep sidekiq | awk '{ print $2 }'`
  kill -TSTP $SIDEKIQ_PID
  while :
  do
    SIDEKIQ_STATUS=`ps axu  | grep -v grep | grep sidekiq`
    echo $SIDEKIQ_STATUS
    if [[ $SIDEKIQ_STATUS =~ stopping ]]; then
      echo "stopped sidekiq"
      exit
    else
      sleep 1
    fi
  done
}

trap trap_term TERM

これで解決したように思えたのですが、処理に時間のかかるjobの場合stopTimeout(最大120秒)を超えるとKILLされてしまう問題が起こりました。

stopTimeoutはFargate環境では現状これ以上伸ばせないので、結局スケールインはできていません。

何か良い方法あれば教えて下さい 🙏

参考

https://aws.amazon.com/jp/blogs/news/graceful-shutdowns-with-ecs/

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html

まとめ

toBのサービスだと同じような課題を抱えている会社は多いと思います。ぜひ参考にしてみてください!

ロジクラではこの他にもインフラ面で工夫している点がいくつもあるので、また別の記事でも紹介していきます!

最後に

ロジクラでは一緒に開発してくれるメンバーを募集しています!

興味がある方はぜひ こちら をご覧ください!

開発チームのマネジメント層を置かないことに決めた話

こんにちは!ロジクラでプロダクトチームの統括をしている榊間です。
初記事なのでまずは会社紹介から、、

僕が所属している株式会社ロジクラはSaasの在庫管理アプリ「ロジクラ」を提供しており、モノを扱う全ての企業が持つ在庫問題の解決を通して、お客様の事業の基盤・インフラとなる存在になるために事業を展開しています!

 

会社組織としては拡大中で、僕が入った当初の数人しかいなかった時期から仲間も増え、会社らしくなってきたなというふうに感じてます笑

そんなロジクラですが、外部で手伝っていただいている方を含めると開発チームは現在7名で、主にロジクラのiOSアプリとWEBアプリを開発しています(各メンバーの紹介はこちら)

 

通常このくらいの規模になるとマネージャー層を作って組織マネジメントの準備を考える会社が多いと思いますが、ロジクラの開発チームではあえてマネジメント層を置かないという判断をしました。

この記事ではその背景と運用に関して紹介します!

 

背景

まずそもそもマネジメントがなぜ必要か考えた時、理由の一部を挙げると以下になります

  • チームの目標と方向性決め、全社目標とのすり合わせ
  • メンバーの管理
  • メンバーの評価

...などなど(他にもたくさんある)

 

マネジメント職が担う役割は多岐に渡り、その機能は会社を動かしていく上でどれも必要です。

ただ、機能は必要だとしてもそれを個人が担う必要はあるでしょうか。

 

会社の成長のボトルネックになる

マネジメント層をつくるデメリットとして、意思決定がマネージャーに集中します。もちろんメンバーに裁量持たせてチームをうまく回せるマネージャーであれば問題ないですが、個人のスキルに依存するので、構造的に意思決定の集中を誘発しやすいです。

全ての意思決定のたびに許可が必要になると、多数の意思決定を行わなければならないスタートアップではボトルネックになることがあります。

 

主体性の抑制

意思決定の集中により、

  • マネージャー個人で方針が合わないと却下され、多様な意見が取り入れにくくなる
  • メンバーが意思決定に関わる場が設けられない

といった現象も起こります。

その結果、メンバーそれぞれが意思決定か関わるアイデアを考えたり、行動をそもそも起こさず、マネージャーから与えられた役割をこなすことに収束し、主体性の抑制が起きてしまいます。

 

業務環境の変化によりマネジメントがさらに難しくなった

コロナの影響でロジクラも全社員フルリモートになりました。

同じ悩みを持っている会社も多いと思いますが、それぞれのメンバーとコミュニケーションをとったり、パフォーマンスを管理するということ自体が以前より難しくなったの感じています。

このような状況下において、あえて難易度の高いマネジメントをするよりは、メンバーそれぞれがある種セルフマネジメントができるような環境を作っていくことが重要だと考えています。

 

組織の方針を決めれたきっかけ

実際このような方針に転換できたのは、もともといる開発メンバーがセルフマネジメントを行えていたという部分が大きいです。

会社としても、ロジクラでは全社の数値や方針が公開・説明されているので、全員が共通認識を持ちやすく、会社の目標達成のために個人、チームでどのような意思決定を行うべきか考える機会が多い文化がありました。

採用活動においてもセルフマネジメントの部分は強調しており、実際以前の会社でマネジメント職を行っていた方が共感して入社を決断してくださるなど、同様の課題感を抱えている開発者は多いのを感じています。

 

運用上の問題点とその解決策

マネージャーが担うはずの機能は誰がやるの?

まず評価制度構築、組織事務管理、技術支援など、チームで必要だが本来マネジャーが担うような機能を洗い出し、それぞれの機能に担当者を設定しました。

こうすることで意思決定のスピードを担保しつつ、意思決定の機能が個人に集中するのを防ぐことができます。

ただ、各機能が本当に必要か、うまくワークしてるかなどは確認が必要で、チームとしてガバナンスミーティングというものを設定し、役割交代も含め定期的に見直しをはかっています。

ガバナンスミーティングとは

役割を新たにつくったり、修正したり、なくしたりする必要があると感じている人(「提案者」と呼ばれる)は、だれでも議題に自分の案を加えることができる。このようなチームのガバナンスに関わる問題が順に一つずつ取り上げられ、次のプロセスに従って採決に至る。
1提案が発表される
2問題点の明確化
3反応ラウンド
4修正と明確化
5異議申し立てラウンド
6統合ラウンド

*1

みんな平等ということ?

違います。各メンバーが担う機能の重みや量などはバラバラなので、評価もそれに合わせて変えています。

あくまで主体性の抑制をしないことが目的なので、全員同等の評価をするということではありません。

 

意思決定が遅くなるのでは? 

この取り組みをメンバーの権限を完全に平等にすることだと捉えると意思決定のたびに全員の承認が必要なのではないかという発想になり、意思決定のスピードが下がると思われる方もいると思います。

ただ、あくまで意思決定は各機能の担当者が行い、必要なのは関係者に対する事前の共有と相談のみです。

現状は人数も少なく、開発チームに関する決定はデイリースクラムなどで全体に共有できるのですが、規模が大きくなった場合はティール組織にある助言プロセスを導入しようと計画中です。(助言プロセスについては詳しく説明しませんが、ティール組織ぜひ読んでみてください!)

 

今後も自己成長を継続

以上が今ロジクラの開発チームで行っている取り組みです。

チームの規模によって問題も変わってくると思いますが、今後うまくいった・いかなかったことも随時公開していければと思ってます!

 

最後に、、

ロジクラでは一緒に開発、組織づくり手伝ってくれる人を募集してます!

ぜひカジュアルに組織・技術のことを話しましょう!

=> 応募はこちら 

*1:引用: フレデリック・ラルー ティール組織 - マネジメントの常識を覆す次世代型組織の出現