これは ドリコム Advent Calendar 2020の15日目です。
14日目は shohei_ono さんによる、 WebフロントエンドエンジニアがBluetooth使うときに知っておきたいこと です。

はじめに

こんにちは、こんばんは、おはようございます。
情報システムグループの「なかはらつ」です。

簡単な自己紹介を。
2019年に新卒として入社し、サーバサイドエンジニアとして黒い画面と戯れたのち
2020年からは情報システムグループ(以下、情シス)としてヘルプデスク対応などの定常業務と並行して「ぽちぽち作業」を駆逐するお仕事をしています。

ぽちぽち作業とは

ここでは情シス内の「手作業で行われていた、人がこなさなくても問題ない単純作業」としておきます
例えば、権限を付与するためにログインしてチェックボックスにチェックを入れて保存する、などです。

このような作業の場合、
「権限付与のポリシー的に問題無いか」などを確認するのは人が行うべきですが、
「チェックボックスにチェックを入れて保存する」などの作業は人でなくても問題ありません。
後者のような、ただ単にマウスをぽちぽちするだけの作業をどうにか軽減できないか、と言うのが今回のお話です。

一つひとつは小さな作業ですが、全社から断続的に依頼が来るとなると結構な時間がかかります。
特に、コロナ禍で働く環境が変わった2020年では平年よりも依頼数が多かったのではないでしょうか。
(2020年から情シスにジョインしたので平年を知りませんが・・・)

ということで、マウスをぽちぽちする単純作業を自動化により駆逐している話について、いくつか書いていきます。

駆逐したぽちぽち作業

ぽちぽち1: アカウントの作成、停止

自動化前の状況

大きなところでは、社内で利用しているサービスのアカウント周りです。
入社された方へはアカウントの新規作成、退社された方へはログインできないようにアカウントを停止・削除する必要があります。

入社時、ユーザ管理システムにてアカウントが作成されると自動で各サービスにアカウントが作成される仕組みがありますが、一部対応していないサービスもあります。
これらのサービスへは、必要事項を手作業で入力してアカウントを作成する必要があります。

前任の方から作業を引き継ぎ、実際に手作業でやってみると大体一人当たり10分程度かかっていました。
筆者はあまり要領がいい方ではないので、それぞれ入力するたびに確認して次へ、と言う形だったので前任の方よりも時間がかかっているかもしれません。

また退社された方へは、残ったアカウントにログインできないようにアカウントを停止したり、削除する必要があります。
こちらも、ユーザ管理システム側でアカウントを無効化することで、紐づいた各サービスのアカウントを無効化する仕組みがありますが、対応していないサービスも一部あり、これは手作業で対応する必要があります。

こちらも実際にやってみると、こちらも一人当たり10分ほどかかりました。
アカウントを停止する作業の場合は、すでに動いているものを止めるため誤って別の方を止めないよう注意を払いながらの作業なので心臓に良くありません。

入場時、退社時どちらも一人当たりはそこまで大きな時間はかかりませんが、複数の方が重なると結構大きな時間がかかります。
例えば新卒の方が入社される時などですね。
なんとかしたい・・・。

問題点

手作業で行うにあたり、よく起こるのは以下のもの。
  • 付与すべき権限が付与されていない
  • 必要ない権限が付与されている
  • 誤字・脱字
どれも手作業によるミスです。
コピー&ペーストでやればいいじゃん、と言われるかもしれませんが
コピー元・ペースト先のミスなどもあるため手作業は辛いです。

自動化後

Rubyさんで各サービスのAPIを叩いたりSeleniumでブラウザ操作を自動化することで対応しました。
幸い作業手順はすでに情シス内でまとめられていたため、
これや実際に手作業で行ったときのメモを参考にスクリプトに落としました。

例として、以下にBoxアカウントをAPI経由で停止するスクリプトを載せておきます。
非公式ながらBoxとそのコミュニティによって管理されているboxrというGemを使い、さらっと書いています。
http:// https://github.com/cburnette/boxr

require "active_support/core_ext/object/blank"
require "boxr"
require "json"

class Box
  attr_reader :email

  def initialize(email: "")
    @email = email
  end

  def lock
    return user_not_found if user.blank?

    inactive!
  end

  private

    def client
      @client ||= Boxr::Client.new user_token(user_id: xxxxx)
    end

    def user
      return @user if defined? @user

      users = client.all_users(filter_term: email)
      @user ||= users.find { |_user| _user.login == email }
    end

    def inactive!
      client.update_user(user.id, status: "inactive")
    end

    def user_token(user_id:)
      conf = JSON.parse("/path/to/config.json", symbolize_names: true)
      app_auth = conf[:app_auth]
      params = {
        private_key: app_auth[:private_key],
        private_key_password: app_auth[:passphrase],
        public_key_id: app_auth[:public_key_id],
        client_id: conf[:client_id],
        client_secret: conf[:client_secret]
      }
      
      Boxr.get_user_token(user_id.to_s, **params).access_token
    end

    def user_not_found
      puts "対象となる'#{email}'ユーザが見つかりませんでした。"

      nil
    end
end

使用例は以下の通り。

box = Box.new(email: "xxxx")
box.lock

このような形で、メールアカウントをもとに対象ユーザのアカウントを無効化できます。
なお、基本的に他のサービスの停止処理と連続して動いているため、実際には単体でうごかすことはありません。

これだけでアカウント作成・停止関連の手作業がなくなり、人はスクリプトが実行した結果を確認するだけで良くなりました。
作業時間的には一人当たり1分程度で作業が終わるようになりました。単純計算で一人当たり9分ほど短縮できました。

さらに、手作業と違い、とても早い上に打ち間違いや操作のミスもありません
アカウント周りは、設定にちょっとしたミスがあるだけでも所属するチームや部門への影響は大きくなります。
特に退社した方のアカウント停止に関しては、アカウントの放置は情報漏洩にも繋がってしまうため、できる限り早急に対処すべき事項となります。
ここへ素早く正確に対処できるようになったのは大きな利点かと思います。

ぽちぽち2: 情シスへの依頼確認

自動化前の状況

情シスでは備品購入やアカウント払い出しなどの依頼をいくつかのサービスから受け付けています。
依頼が来たかどうかの確認は、各自サービスへログインし有無を確認していました。
後述しますが、これが意外と手間なんです。

問題点

1つ目は、依頼がきてから初動までにラグが生じやすいことです。
各自が任意のタイミングで確認するため、初動までにラグが生じる場合がどうしてもあります。
緊急の場合はこれでは困る・・・。

2つ目は、確認自体の手間です。
依頼を確認するために、依頼一覧画面へ切り替えて、念の為ページをリロードする。
確認自体は数秒のことですが、作業を中断されるのでなんとかしたいなぁと思っていました。
筆者の場合、当初は数分おきに確認しよう!と思っていたが気がつくと数時間経っていた、
なんてことも何度もあり、とてもよくない。

自動化後

対応としては、依頼が飛んできたらChatworkへ通知をするようにしました。以上!
やったこととしてはこれだけです。

Botが通知する内容としては大まかに、依頼内容の抜粋、依頼者、依頼サービスへのURLです。
これだけの情報があれば、最低限の内容を把握し動くことができます。
(抜粋に関しても、単純に文字数で切り捨てるとURL等が入るとリンク先へ飛べず悲しいことになるため、よしなに対応したんですがここでは省略します)
実際に飛んできた依頼の例
対応としてはこれだけですが、効果としては意外なところにもありました。
依頼内容を部門全員が見えるところへ通知してあげることで、チャット内で依頼への議論や確認ができるようになりました
対面環境ではちょっと声をかければ済む話ですが、リモートワークが多くなっている今日この頃ではありがたい変化でした。

ぽちぽち3: 実行環境構築の自動化

自動化前の状況

上記のような自動化を行っていますが、実行環境があるのは筆者のPCのみでした。
部門的にも実行環境は必須ではないため、構築されていない方が大半な状態でした。
構築手順を文章として残してありましたが、構築自体に時間がかかる上に
誰でもできるかと言うとそうでもなく、ハードルが高い部分があります。

また、筆者はMacで前述のようなスクリプトを作成し実行していました。
しかし、筆者以外はWin環境が主なので、そのままでは色々と困ったことが起こってしまいます。

問題点

一番大きな問題は、OS間の差異です。
Macの場合はHomebrewなどを使えばある程度手軽に実行環境を作ることができますが、
Winの場合はそうもいきません。
さらにパスの問題等もあり、それぞれの環境で同じように動くようにするのが面倒でした。

また、部内へ共有する時に「何もわからない場合でも手軽に使えると嬉しい」という要望もあり
環境構築の手順を共有するだけでは不十分な状態でした。
さらに言えば、環境構築は思わぬところで躓いたりと、割と辛い部分もありますよね。
(個人的には環境構築が一番楽しいと思っています)

自動化後

Win環境の方が多いのと、自動化スクリプトはRubyで作成していたので、WSL環境を使うことにしました。
MacとLinuxでの細かい差異はありますが「Rubyが動けばいい」と思って環境を作ることにしたので、
Win環境との差異に比べれば大した差はありません。
WSLについては、公式サイトを参照ください。
https://docs.microsoft.com/ja-jp/windows/wsl/

取り組んだこととしては、下記URLの手順を基に
実行すればWSL上でUbuntuが動くような環境を
PowerShellやbatファイルを実行すればよい形にしただけです。
https://docs.microsoft.com/ja-jp/windows/wsl/install-win10

以下に、WSLを有効化するPowerShellを載せておきます。
前述したURLの手順1に相当します。

# support.ps1
function isAdmin {
    $cur = [Security.Principal.WindowsIdentity]::GetCurrent()
    $currentPrincipal = New-Object Security.Principal.WindowsPrincipal($cur)

    $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

# wsl_enable.ps1
. .\support.ps1
if ( !(isAdmin) ) {
    Write-Output "管理者権限でPowerShellを実行してください"
    Remove-TempStoreRegistry
    Start-Sleep -s 5
    exit
}

# 処理の本体
Write-Output "windows Subsystem for Linuxの機能を有効化します"
dism.exe /Online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

公式サイトの手順を参考に、処理終了後に再起動・自動ログイン後に次のスクリプトを実行、という感じで流していくイメージです。

PowerShellに関しては今回初めて触れました。
数回再起動をかける必要があったため、再起動後もスクリプトを実行できるように設定したり、再起動後に自動でログインする方法を調べてなんとか対応しました。
(WSL上でSeleniumを動かすために戦った記録もありますが、ここでは省略します)

結果として、割と辛い環境構築が、何も知らずともbatファイルを実行だけで済むようになりました
WSLなので、不具合等が起きた場合の環境リセットも簡単です。
やったね。

駆逐による問題点

ここまで、自動化の内容や変化について書いてきましたが、
ここからは自動化した事により起こるであろう問題点を書いておきます。

まずは、スクリプト自体の保守コストがかかる点です。
今はまだそこまでコード数や利用者も少ないため大きな問題は起こっていないませんが、
数が増えると保守自体が手間になってしまいます。
実際、ここ最近使っているサービスのリプレースがあり、諸々の対応がありました。

次に、どこまで対応するか、という問題です。
スクリプトを自分で書いているため、やろうと思えばどこまででも対応できてしまいます。
手をかければかけるだけ自動化できるものも増えていきますが、
それだけ時間や保守のコストも増えていってしまいます。
その他、個人的には自動化できると楽しくなってしまうので、あれもこれもと手を広げてしまいがち。
自動化って難しいね。

まとめ

今回は、情シス内の単純作業をRubyやPowerShellなどを使って自動化した話をいくつか紹介しました。
自動化することで、一部の作業をスクリプトに丸投げできるようになり、他のことに時間を充てられるようになりました。
1件当たり数分程度の短縮ですが、積み重ねによって大きな時間になります。

また、手作業よりも正確に素早く作業をこなすことができるようになりました
自動化というと、作業負荷の軽減という話が多くなりがちですが、
正確性というところも大きく向上しています。
特にアカウント作成や停止などは設定にミスがある場合、チームや部門に大きな影響を与えてしまいます。
これをスクリプトに任せることで、素早く正確に対処できるようになった影響は作業負荷の軽減よりも大きいと思います。

一方で、スクリプトを手作業で作っているため、
保守管理のコストやどこまで対応するか問題など考えなければいけない点も多いです。
「作業時間が短くなるもの」「何度も行う作業」に関しては効果は大きいですが、
「自動化できるから」とあれこれ自動化すればいいものでもありません。
手を広げすぎると、自動化したものの誰も管理していない、という禍々しい世界になってしまいます。

自動化って楽しいけど、難しいね。

おわり


ドリコムでは一緒に働くメンバーを募集しています! 募集一覧はコチラを御覧ください!