【話題沸騰中】軽量でお洒落なコマンドプロンプト拡張ライブラリ「Starship」を導入した話

こんにちは。 分からないことに出会ったら、ワクワクする inteeの 中野 です。

会社から新型MacBook Proを支給して貰ったので、 ターミナルのプロンプトをカスタマイズした話をしようと思います!

Starshipとは

f:id:channaka0531:20200825141702p:plain

Starshipとは、ターミナルのプロンプトをカスタマイズするプラグインです。 日本語翻訳が充実しており、可愛いデザインに惚れて、導入を決めました!

Starshipの特徴
  • Rust言語で開発されており、動作が高速
  • 設定ファイルで細かくカスタマイズ可能
  • bash / Zsh / Fish で使用可能
  • Git管理のプロジェクトであれば、ブランチ名や言語バージョン等が表示可能
  • ポップなカラースキーム・絵文字がカワイイ(超重要)

個人的に辛い開発時にエモい気持ちになりながら、開発できる体験を重要視しております🙇‍♀️

https://raw.githubusercontent.com/starship/starship/master/media/demo.gif

インストール

今回はMacで導入した為、Homebrew(パッケージマネージャー)経由でインストールしました。 他の導入の仕方に関しては、日本語翻訳された公式サイト を見た方が良いです!

brew install starship

次に初期化のためのスクリプトをシェルの設定ファイルに追加します。

Bashの場合、 ~/.bashrc に

# ~/.bashrc
eval "$(starship init bash)"

Zshの場合、 ~/.zshrc に

# ~/.zshrc
eval "$(starship init zsh)"

Fishの場合、 ~/.config/fish/config.fish に

# ~/.config/fish/config.fish
starship init fish | source

上記の設定を反映後、ターミナルが下記画像になっていたら、インストール完了です!

f:id:channaka0531:20200825112852p:plain

カスタマイズ

各項目の表示を設定したいので、~/.config/starship.toml ファイルを作成します。

$ touch ~/.config/starship.toml

各項目の設定内容については、 日本語翻訳された公式サイト を確認するのが手っ取り早いです💪

個人設定

f:id:channaka0531:20200825140624p:plain

まだまだカスタマイズ途中ではありますが、設定ファイルの内容をアップロードしておきます! 皆さんもStarshipを導入して、カワイイ開発体験を試してみてください^^

自然言語処理を使って弊社エンジニアメンバーの特徴を言語化してみた

こんにちは! Hajimariの新卒2年目の栗岡です!

普段は受託開発を行いながら、採用担当をしています! 開発と採用の2足草鞋は内定者インターンから含めるとかれこれ2年になります。

今回は、プログラミングの力を使って、エンジニア採用でちょっと課題と感じていることを少しでも解消してみようと思います! (結論、そんなに簡単じゃなかったです、、、)

感じている課題

弊社のエンジニア組織/メンバーの特徴を言語化できていない故に、3年後・5年後にエンジニア組織の強みが分からなくなりそう、、、、

今は、会社自体が若く、小規模であるため、業務の幅の広さや裁量権の大きさを打ち出せるけれど、もし数年後従業員数が100人を超えたときに、どんな風に候補者さんに弊社のエンジニア組織を魅力的に思ってもらえる のか結構悩んでいます。

やること

組織は人の集まりなので、とりあえず、エンジニア組織のメンバーの特徴を改めて理解し、言語化したいと思います。 ざっくり言うと、「弊社のエンジニア組織の特徴としては、〜な人と・・・な人にカテゴライズできて〜」ってことを言えるようになりたい。

具体的な方法

wantedlyの入社ブログから、それぞれメンバーの特徴を抽出・分類する。 ちゃんと考えて書いた言葉は、人の特徴を表すので、とりあえずやってみるにはちょうど良いかなと思いました。

実装方法としては、自然言語処理でおなじみtf-idfでブログからメンバーの特徴を抽出しました。

www.sejuku.net

いろんな人が書いた文章を比較した際に、その人っぽい単語・言葉を見つけるって感じですかね。

自然言語処理や統計分析は大学の頃にほんの少しだけ触った程度ですので、初心者中の初心者です

やってみた

普段データ分析で遊ぶときは、jupyter notebookを使うのですが、今回、色々と探していると、Streamlitと言うデータ分析の結果を凄くwebっぽく表示してくれるフレームワーク があったので使ってみました。 なので、言語もpythonです。 www.streamlit.io

形態素解析 ブログの内容を単語ごとに区切る

前段階として、アナログにwantedlyのブログをコピペし、メンバーごとのテキストファイルを作りました。

 # nameにはメンバーの名前がloopで入ります
 def sprit_sentence_to_word(name):
  # 辞書登録(mecab-ipadic-neologd
  option = "-d /usr/local/lib/mecab/dic/mecab-ipadic-neologd"
  tagger = MeCab.Tagger("-Ochasen " + option)
  # アナログに作ったテキストデータリンク
  open_link = "/text_data/wantedly/" + name + ".txt"
  f = open(open_link)
  text = f.read()
  f.close()
  # パースする 
  res = tagger.parseToNode(text)
  #  ストップワードリスト取得
  path = "stop_words.txt"
  #  日本語のストップワードを取得し、リスト化します
  stop_words = create_stopwords(path)
  words = []
  while res:
        # ストップワード除去
         if res.surface not in stop_words:
              word = res.surface
              part_of_speech = res.feature.split(",")[0]
              sub_part_of_speech = res.feature.split(",")[1]
              if part_of_speech in ['名詞', '動詞', '形容詞']:
                  if sub_part_of_speech not in ['空白', '*']:
                      words.append(word)
           res = res.next
      return words
形態素解析した結果をファイル保存
  data = sprit_sentence_to_word(name)
     open_link = "/output/wantedly/" + name + ".txt"
      with open(open_link, 'w', encoding='utf-8') as f:
         f.write(' '.join(data))


 # こんな感じ単語区切りになり保存されます
  石川県 生まれ 札幌 住み 現在 千葉県 住ん 5歳 高校 卒業 サッカー 漬け 日々 大好き サッカー 辞め 
  休日 1 ミリ 出 多い ん インドア ん 笑 大学 青山学院大学 進学
TF-IDFの計算
 def analysis(name):
  contents = []
  eng_names = []
  open_link = "/output/wantedly/" + name + ".txt"
  
  # ファイルをオープンする
  test_data = open(open_link, "r")
  # データを書き込む
  contents.append(test_data.read())
  # ファイルクローズ
  test_data.close()
  # エンジニアの名前も詰める
  eng_names.append(name)

  # データフレームにする
  df = pd.DataFrame({'name': eng_names,
                    'text': contents})
   
  # TF-IDFの計算
  # TF-IDFの上位200単語・単語頻出度10%~90%を取得
  tfidf_vectorizer = TfidfVectorizer(use_idf=True, min_df=0.1, max_df=0.90, max_features=200)
 
  # Tfidf値を取得
  tfidf_matrix = tfidf_vectorizer.fit_transform(df['text'])
  
  # index 順の単語リスト
  terms = tfidf_vectorizer.get_feature_names()
  tfidfs = tfidf_matrix.toarray()

  # TF-IDF表示
  show_tfidf(terms, tfidfs, eng_names)
 
 def show_tfidf(terms, tfidfs, eng_names):
  df = pd.DataFrame(
    tfidfs,
    columns=terms,
    index=eng_names)
 #表で出力
 st.write(df)

こんな感じに出力されました。 数値が1に近いほど特徴的な単語になります。200単語あるので全てお見せすることは難しいですが、、 f:id:marron-web-engineer:20200811091345p:plain

ちょっと考察ができそうな単語をいくつかみてみます。

f:id:marron-web-engineer:20200811234346p:plain

事業という単語からは、エンジニアとして事業を作っていきたいと普段から発信している中野が高い数値となっています。

仲間という単語では、CTOの柳澤と新卒1年目の保坂に高い数値が出てます。 仲間(一緒に働く人)が軸に入っている候補者の方との面談にアサインしたいです。

f:id:marron-web-engineer:20200811234401p:plain 成長・技術という単語では、板橋に高い数値が出ています。 ブログを読んでもらってから面接を行い、入社からの成長を技術周りの事を交えて話してもらえると候補者体験として効果的かもしれません。

それぞれの単語をみていくだけでもたくさんの考察や気づきがあるのですが、やりたいことはエンジニアメンバーを近い特徴同士でグルーピングすることなので、次元圧縮を行いメンバーそれぞれの特徴をまとめて数値にします。 今回は、次元圧縮をちょっと話題になっているらしいのでt-SNEを使ってみます。 詳しくはこちらをご覧ください。

qiita.com

次元圧縮
 # tsne次元圧縮 
 # tfidf_matrix:上部で表示したtfidfデータ
 # df.name:エンジニアメンバー名前データ
 do_tsne(tfidf_matrix, df.name)

 def do_tsne(tfidf_matrix, name):
  # 2次元に変換 回転数1200
  tsne = TSNE(n_components=2, perplexity=50, n_iter=1200)
  tsne_tfidf = tsne.fit_transform(tfidf_matrix)

  # データフレームにセット
  df_tsne = pd.DataFrame(tsne.embedding_[:, 0],columns = ["x"])
  df_tsne["y"] = pd.DataFrame(tsne.embedding_[:, 1])
  # プロットする際に名前で表示させる
  df_tsne["name"] = df.name
  # テーブルで表示 
  st.write(df_tsne)

  # プロットグラフで表示
  c = alt.Chart(df_tsne).mark_point().encode(
    x='x',
    y='y',
   ).mark_text(
    align='left',
    baseline='middle',
    dx=10
   ).encode(
    text='name',
   )
  st.altair_chart(c, use_container_width=True)

結果

f:id:marron-web-engineer:20200812002537p:plain

微妙。。。散らばっているので、特徴ごとにグルーピングもできず、、、、 一箇所くらいまとまりあれば面白かったのですが、、、、 そんなに簡単にはいかないそうです。リベンジします。

最後に、ちょっと流行ってるword2vecで〜に〜を聞いてみたシリーズに乗っかり、

*word2vecとは、文章中の単語や単語間の意味を数値化(ベクトル化)する、googleの偉い方が考えたニューラルネットワークモデルです。

Hajimariのエンジニア組織にビジョンである「自立」を聞いてみました。 tf-idf同様wantedlyの入社ブログが元データです。

参考にさせて頂きました。

note.com

ソースコードのメインは以下の通り

 def filler_word2vec():
  # sample.txtには、ブログデータが単語区切りで入っています。
  sentences = word2vec.LineSentence('/output/sample.txt')
  # ブログデータベクトル化
  # 出現5単語未満切り捨て
  model = word2vec.Word2Vec(
   sentences,
   sg=1,
   size=100
   min_count=5,
   window=8,
   hs=1,
   iter=5
  )
  
  #学習モデル作成
  model.save('/model/sample.model')
 
 def analysis():
  load_model_path = '/model/sample.model'
  #学習モデル読み込み
  model = word2vec.Word2Vec.load(load_model_path)
  
  #自立に近い意味合いの単語を出力
  results = model.wv.most_similar(positive=['自立'])
  return results
 
 model = filler_word2vec()
 results = analysis()

f:id:marron-web-engineer:20200812011225p:plain

*1に近いほど類似しています

データ量が少ない関係で、数値が固まってしまいましたが、

「夢のために、新しいことに挑戦し、働く」

といった弊社らしい「自立」を解釈できるアウトプットになりました。 (少し無理やり感もありますが、、笑)

まとめ

  • 元となるデータがwantedlyでよかったのか?

  • データ数少なすぎじゃないか?

  • 分析の方法が本当に適切なのか?

などなど突っ込みどころ&反省もある内容であったと思いますが、採用という定性的で感覚が大きいテーマにおいて、言葉を数値化することで分かることも一定ありそうだなと思いました。 ちょっと大学で自然言語っぽいこと齧った程度では歯が立たないことは実感させられましたが、せっかくエンジニアと他の職務も兼務できる環境なので、プログラミングをいろんな分野に使っていけたらなと思います!

夢のために、新しいことに挑戦し、働く エンジニア組織ですが、まだまだ仲間がたりません!事業や組織作りに興味がある・モチベーション高い仲間と働きたいエンジニアさんがいらっしゃいましたら、是非お話しましょう!

www.wantedly.com

www.wantedly.com

speakerdeck.com

【Laravel】画像の直アクセスを禁止して、特定の条件を突破した場合のみ画像を表示する方法

こんにちは!Hajimariの新卒エンジニアの稲葉です。
2020年4月1日に新卒エンジニア2期生として入社しました!

普段は、自社プロダクトであるスタートアップ向けマッチングサイト構築パッケージPIECE(https://crowd.itpropartners.com/piece/)の開発や受託開発を行っています!

今回はログインしていない場合に画像の直アクセスを禁止する方法について書いていきます。
htaccessで直アクセスを制限する方法も考えられますが、ログインしている場合は直アクセスの許可するため、Laravel、Nginxで実装していきます。

直アクセス

storage/files配下に設置した画像が、 /storage/files/画像名でアクセスした際に画像が表示されます。
特定の条件を突破した場合のみ表示させたい画像がある場合は、直アクセスを禁止してみてください。
万が一直アクセスをされた際に、画像が表示されるの防ぐことができます。

実装

まずはstorage配下にimagesディレクトリを作成。
今回直リンクを禁止する画像をstorage/images配下に設置します。

画像の設置後、Nginxでlocationの設定をします。 /imagesにアクセスした際、内部リダイレクトされます。

location /images {
    try_files /index.php?$uri /index.php?$query_string;
}


次にルーティングの定義です。
whereメソッドはパラメーターのフォーマットを制約します。
下記ではパラメーター(path)を0文字以上の任意の文字列に制約。

Route::get('/images/{path?}', 'FileAccessController@index')->where(['path' => '.*']);


ルーティングの定義後、traitの作成です。
traitの作成後は必要なメソッドを定義していきます。
作成したtraitは任意のクラスで継承すれば、継承したtraitに定義されているメソッドをそのクラスが利用することができます。

use Illuminate\Support\Facades\Storage;

Trait ImageTrait
{
  public function getDiskInstance()
   {
       return Storage::disk('local');
   }

  public function storageExist($fileName)
   {
       return $this->getDiskInstance()->exists($fileName);
   }
}

getDiskInstance()メソッドでは、Storageファサードのdiskメソッドを使用してディスクインスタンスの取得。
storageExist()メソッドでは、existsメソッドを使用してファイルが存在しているか判定します。
存在する場合はtrueを返します。


trait作成後、filesystems.php で local のベースディレクトリがどこになるかを指定します。
今回はstorage/images配下に画像を設置したため、imagesディレクトリを指定。
デフォルトではappディレクトリが指定されています。

'disks' => [

        'local' => [
            'driver' => 'local',
            // 変更前
            // 'root' => storage_path('app'),
            'root' => storage_path('images'),
        ],


最後にコントローラの作成、indexメソッドを定義をします。
先ほど作成したtraitを下記で継承することが可能です。

use トレイト名;

ログインしている場合のみ直リンクを許可します。

class FileAccessController extends Controller
{
    use ImageTrait;

    public function index($path=null, Request $request)
    {
        $exist = $this->storageExist($path);

        if (!$exist) {
            abort(404);
        }

        if(Auth::check()){
            return $this->getDiskInstance()->response($path);
        }else {
            abort(404);
        }
        
    }
}

実装は以上です。


現在は家族の事情もあり、リモートワークを行っています。
内定者インターンから数えると約10ヶ月リモートワークを継続中です。
今後は長期間のリモートワークについても書いていこうと思います。


最後に

Hajimariでは、Laravel、vue.js、Nuxt.jsで開発に挑戦したいエンジニア・デザイナーを絶賛募集中です!

そして、22卒新卒エンジニアのエントリーも心よりお待ちしております!

www.wantedly.com

www.wantedly.com

GAS と Slack App でデータ集計用のボットを作りました

こんにちは!株式会社Hajimariの新卒エンジニアの濵田です。

今年の4月に新卒として入社致しました。 普段はGraspyの開発業務を行う傍ら

最近は会社のHPの管理を行ったりしています。 今回はGASとSlack Appで作った「360度レビューくん」がどう動いているのかを紹介します。

※このbotはエンジニアチームの中で走っている施策「360˚ソースコードレビュー」で使うために作成しました。 上記の施策に関しては責任者をされているエンジニアの先輩が解説してくださったこちらの記事でかなり詳しく解説されているのでぜひご一読ください。

bot の概要

slack の特定のチャンネルに配置しておき、メンションをつけてGitHubのプルリクのURLを送ると プルリクについた会話(conversation)を数えてシートに記録します。 また、メンションつけて「データをみたい」とメッセージを送信すると集計された内容が チャンネルに投稿されます。

f:id:hajimari_hamada:20200715092206j:plain 上記の写真ではプルリクのURLをbotにメンションつけて送る事で集計してもらっているシーンです。

今回はこのbotがどのようにして集計して、シートに記録・チャンネルに返信しているのか、ついて書いていきます。

全体的なbotの構成

Botが動く流れとしては以下の通りです。

① Slack でbotにメンションつけてイベント発生 => GASのAPI叩く ② GAS側では届いたURLを元にGitHub API を叩いて会話(今後コメントと表記)を取得。処理してシートに書き出し、レスポンスを返す。 ③ 戻ってきたレスポンスにあるメッセージをbotがチャンネルに投稿する

こちらのbotはGASプログラム(スプレッドシート)、Slack App(bot)を使って動いています。 それぞれ具体的にどのようになっているのか見ていきます。

GAS (スプレッドシート)

GASのプログラムは主に以下のような項目のコードで動いています。

  1. slack との最初の連携をする部分
  2. GitHub API を叩く
  3. 計算処理
  4. シートに書き込む
  5. Slack チャンネルにメッセージを送信

以下で順番に見ていきます。

1. slack との最初の連携をする部分

f:id:hajimari_hamada:20200714155903p:plain
GAS に来たデータを取得する部分です

上記写真の①では、このGASのプログラムに来たデータを取得しています。 後述するSlack 側の設定をしておくと、postData.event.text でメンションつけて送信したメッセージの内容が来ています。 今回は別箇所にプルリクURLだけ切り出す関数を用意してURLのみ使っていますが、 受け取ったメッセージはお好きなようにご利用ください。

そして②では、Slack側から来たデータが、認証用のリクエストだった場合に返してあげる内容を書いています。 このコードでSlack 側の期待したレスポンスが返ってくるかのチェックを通ることができます。 この記事を参考に(というかそのまま)用意しました。

Slack App の設定の部分で改めて説明します。

2. GitHub API を叩く

f:id:hajimari_hamada:20200714155214p:plain
GitHubAPI を叩いてレスポンスを返すメソッドです

このメソッドはGitHubAPIを叩くメソッドで、書いてる通りではあるのですが、 引数に来た GitHub API の url を叩いてレスポンスを返してくれるメソッドです。

今回はGitHubのプルリクについた会話を集計したいので、 引数に入ってくる apiUrl には

https://api.github.com/repos/ { レポジトリ名 }/pulls/{ プルリクの数値(#XXXXみたいに表示されてるやつ) }/comments が入ってきます。

また、今回は会社のレポジトリのプルリク情報を取得しているのでトークンをheaders に指定しています。

PropertiesService.getScriptProperties().getProperty('GITHUB_TOKEN')

上記に関して少し触れておくと、GASには今回のようなトークンなど、ベタ書きは避けたい情報を設定する時 別に置いておける場所があり、それをプロパティストアといいます。

そしてそこに置いておいた情報にアクセスしたりするGASの機能の事をプロパティサービス(ProperiiesService)といい、 上記のコードでは、それを使って予め保管しておいたGitHubトークンを呼び出しています。

今回は飛んできたプルリクURLをこのメソッドで使えるAPIURLに変換する部分の解説は割愛します。

3. 計算処理

f:id:hajimari_hamada:20200714162009p:plain
そのプルリクにどのメンバーがどれだけコメントしたかを計算するメソッド

上記のメソッドは、そのプルリクについたコメント数をカウントするいくつかのメソッドの中の一つです。 ここではコメントの通り、そのプルリクについたコメントを自分以外の誰が何回したかを算出しています。

引数について解説すると、このGASのプログラムではそもそもエンジニアチームメンバー全員の GitHubの名前とSlack のメンバーID を50音順で配列にして管理しています。 ここではGitHubの名前の配列を受け取っています。

また reviews は上記のGitHub API を叩いた戻りを受け取っています。 reviews にはそのプルリクについた全てのコメントが入っており、それぞれのコメントオブジェクトのuser.loginに入っています。 そして第3引数のuserGithubNameには、このプルリクをチャンネルで共有したメンバーのGitHub 上の名前を受け取っています。

上記のメソッドはそのプルリクに自分以外の人がどれだけコメントしているのかを集計しようとしていますが これらのGitHub の名前を使ってそれを実現しています。

ちなみに reviewCounts は配列で(名前どうにかするべきかも)、後々シートにデータを入れる際の事を考慮して用意しています。 それ専用のメソッドを読んで先にメンバー分の中身が入った配列を用意しています。

4. シートに書き込む

f:id:hajimari_hamada:20200714164605p:plain
今回書き込むシートを取得しています

f:id:hajimari_hamada:20200714164408p:plain
上記のメソッドを使って他のメンバーからもらったコメント数を使ってシートに書いています

1枚目の写真のように SpreadsheetAppクラスのopenByIdメソッドを使って操作したいシートを取得します。 openByIdメソッドではその名の通り、スプレッドシートのIDを渡してやる必要があるのですが、 今回も、先ほど出てきたようにプロパティサービスで、プロパティストアで管理してあるシートIDを取得して渡しています。

2枚目の写真では、 先ほど取得したシートの中で操作の対象にしたい範囲をgetRangeメソッドで指定したいます。(変数 pullRequestInfoRange)

また、シート上の書き込みたいセルを取得するために getCell メソッドを使ってそれぞれ具体的に書き込むセルの絞り込みまでしています。(変数 ~~Cell)

実際にこのプルリクで他のメンバーからもらったコメントの合計を取得するために 先ほどgiveCommentCount関数で集計して戻ってきた各メンバーのコメント数が入った配列をgiveCommentCountSum関数に渡しています。 こうして用意したもらったコメントの合計をothersCommentCellにsetValueメソッドで書き込んでいます。

5. Slack チャンネルにメッセージを送信

f:id:hajimari_hamada:20200714165751p:plain
メッセージ送信用関数の一部

f:id:hajimari_hamada:20200714170029p:plain
処理の結果で返すメッセージを切り替えている部分

最後に処理の結果を知らせるメッセージを対象のSlackチャンネルに返します。 とりあえず、sendMessageという受け取ったメッセージを返す関数を用意し、 処理の結果毎に異なったメッセージを返すようそれぞれのパターンに対してsendMessageを使う関数を用意しています。 2枚目の写真は実際にtry ~ catch でどのメッセージを返す関数を使うか切り分けている部分です。

Slack にメッセージを送るために必要な設定は後ほど説明しますが、 送信したいチャンネルにメッセージを送ることができるURLをまたプロパティサービスで取得しています。

ここまでがGAS で行われている処理の一連の流れです。

Slack App

1. slack app を作成

このページの画面上部のCreate New Appを押す。 名前と入れるworkspace を選ぶダイアログが表示されるので、それぞれ入力し次に進むとひとまずは作成できます。

アイコンや名前等の基本的は情報の設定はお好きにどうぞ。

2. bot の設定
  1. Incoming Webhook を設定

GASプログラムからbotを通じてチャンネルにメッセージを送るためにはIncoming Webhook を設定する必要があります。 Features/Incoming Webhook を選択し、Activate Incoming Webhooks を On にします。

f:id:hajimari_hamada:20200714175356p:plain
Features/Incoming Webhook の選択画面下部

f:id:hajimari_hamada:20200714175842p:plain
Add New Webhook to Workspace 押下後この画面に

そして、画面下部(上記の1枚目の写真)のAdd New Webhook to Workspace を押すと2枚目の写真の画面に遷移します。 追加したい チャンネルを選択し進むと、画面が戻りURLが発行されている事がわかります。

f:id:hajimari_hamada:20200714175903p:plain
追加された専用URL

このURLをGASのプロパティストアに設定して、上記のsendMessage 部分でプロパティサービスを使って取得して使っています。

  1. Event Subscriptions の設定

f:id:hajimari_hamada:20200714180027p:plain
Features/Event Subscriptions をOn にしています

Incoming Webhook と同じように Event Subscriptions の設定も On にします。 Request URL の部分にAPI公開されているGASのプログラムのURLを入力してテストします。 上で用意した通りにしていれば問題なく設定されます。

f:id:hajimari_hamada:20200714180129p:plain
ここでbotに関するイベントを設定することができます

そしてこの写真の部分で、bot に関係するイベントの設定ができます。 今回はbotにメンションをつけるイベントが発生すると、上で設定したURL(GAS)にデータを飛ばしてやりたいので app_mension を選択します。

以上で、今回botを用意したチャンネルでbotにメンションをつけた状態でプルリクのURLをメッセージとして送信すると、 GAS側で飛んできたURLを受け取り・集計しシートに反映・返信までできる部分をそれぞれ解説しました。

具体的にどういう計算をしたりや、どう言った文言(URL等)が来たら処理を行うのかはお好みでカスタマイズしてみてください。

ボットに関しては以上です。

また、僕の開発している Graspy は若手で活躍されている優秀な方々がキャリアアップできるようなプラットフォームを目指して日々成長しておりますので、ぜひ一度ご覧になってみてください(求人も沢山あります!)

graspy.jp

株式会社Hajimariでは、自社開発・受託開発を行っています。
一緒にLaravelやVue.jsを使って開発してくれるエンジニア・デザイナーを絶賛募集しています!

新卒・中途どちらも募集しておりますので、興味のある方は以下の記事をぜひ御覧ください!
みなさまとお会いできるのを心からお待ちしております。

www.wantedly.com

www.wantedly.com

新卒エンジニアがNoCode触って感動した話

自己紹介

はじめまして!株式会社Hajimariでエンジニアを担当している保坂(@michael_progs)と申します。
今年の4月に新卒として入社しました。
普段は大きく分けて次の3つの業務を行っています。

  1. inteeという学生のファーストキャリアをサポートするサービスの開発
  2. ソースコードリファクタリングを行うプロジェクトのリーダー
  3. リアルカレッジというプログラミングスクールの企画・運用・講師

今回はプログラミングなしで、サービスを作ることが出来るNoCodeについて書いていきます。
(NoCodeはエンジニアから見てもかなり感動するツールでした)

NoCodeとは

読んで字の如く、コードを書かずにサービスを開発できるツールのことです。

例えば何かサービスを作るときに、エンジニアがプログラミングをする必要があると思います。
しかしNoCodeを使えば、プログラミングをせずにサービスを作ることが出来ます!
今回僕も初めてNoCodeを使ってみたのですが、本当に感動しました。こんなにも短時間でクオリティの高いサービスが出来てしまうのかと。。。

ただ現状のNoCodeのツールでは、やはりエンジニアリングの知識が合ったほうがスムーズに開発できるように感じました。
なので、非エンジニアの方がNoCodeを使ってサービスを作るのには、現段階では少しだけハードルが高い気がしました。

しかし本当に革新的なツールなので、今後はNoCodeの需要が伸びていきそうです。NoCodeのこれからが楽しみです。

僕は今回bubbleというサービスを使いました。 bubble を選択した理由は以下の2つです。(気軽に選びました)

  • リアルカレッジ受講生がbubbleを使って、サービスを作ろうとしていたため
  • ネットで検索したときに、bubbleをおすすめしているサイトが多かったため

bubble.io

なぜNoCodeを触ってみようと思ったか

リアルカレッジ受講生が以下のNoCodeハッカソンに出場することになり、僕もその子達を応援したいと思ったからです。 ただ今までNoCodeを一度も触ったことがなかったので、この機会に触ってみようと思い挑戦してみました。

ncc01.nocodecamp.co.jp

NoCode触ってみた

実際にNoCodeを使って、ツイートを投稿出来るサービスを作ってみました。開発にかかった時間は60分くらいで、画面を見ながら直感的にサービスを作ることが出来ました。NoCode本当にすごいです!僕が60分で作ったサービスはこちらになります。

f:id:hosaka555:20200620190217p:plain
NoCodeで作ったツイッター

ツイートを投稿するだけの簡単なサービスですが、サイトのレスポンスも非常に速く、作っていてとても楽しかったです。 慣れてしまえば10分くらいで、同じようなものが出来てしまいそうです。

今回作ったツイートを投稿できるサービスの作り方の手順を簡単に載せておきます。
まずbubbleを開き、NEW APPよりアプリを新規で作成します。

f:id:hosaka555:20200622171320p:plain
NEW APPをクリックしてアプリを作成

次にアプリ名を設定しますが、このアプリ名がサブドメインになるので、他で使われていない名前にする必要があります。

f:id:hosaka555:20200622171346p:plain
アプリネームを設定

早速投稿フォームを作っていきます。(もともとあったエレメント(要素)やコンテナ(ブロック)などは削除しておきました)
左のメニューからInput forms > Inputを選択して、入力フォームを配置します。

f:id:hosaka555:20200622174540p:plain
投稿フォームを配置する

次にボタンを配します。先ほどと同様に左のメニューからVisual elements > Button を選択してボタンを配置します。

f:id:hosaka555:20200622174910p:plain
ボタンを配置する

ボタンの中のedit meをクリックして、投稿に書き換えます。

f:id:hosaka555:20200623093706p:plain
edit meを投稿に書き換え

次にDBにTweetテーブルを作成します。左のメニューから、Data を選択し、New TypeのところにTweetと入れてCreateをクリックします。

f:id:hosaka555:20200623094243p:plain
Tweetテーブルの作成

Tweetテーブルが作成されるので、続いてmessageというツイートを保存するカラムを追加していきます。 Create a new fieldをクリックして、以下画像のように設定します。

f:id:hosaka555:20200623094549p:plain
messageカラムを追加

これでTweetテーブルの作成は完了です!

次に投稿ボタンをクリックしたときにツイートをTweetテーブルに保存するようにしていきます。 左のメニューからWorkflowを選択し、以下画像のようにElements > An element is clickedを選択します。

f:id:hosaka555:20200623094825p:plain
ボタンをクリックしたときのイベントを追加

選択後は以下の画像のような感じになります。

f:id:hosaka555:20200623141849p:plain
選択後の状態

ここで上記画像のWhenをクリックして、出てきたポップアップウィンドウのElementのところに先程追加したボタンを選択します。

f:id:hosaka555:20200623104834p:plain
ElementにButton 投稿を選択

これで投稿ボタンをクリックしたときに何かしらのイベントを実行できるようになります。早速イベントを登録していきます。
Click here to add actionをクリックして、Data > Create a new thingを選択してください。

その後出てきたポップアップウィンドウに以下のように設定してください。

f:id:hosaka555:20200623110416p:plain
ボタンクリック時に登録するデータを設定する

これでツイートを投稿ボタンをクリックしたときに、ツイートをDBに登録できるようになりました!
左のメニューのData > App data > All Tweetsからデータが登録できているか確認できます。

f:id:hosaka555:20200623110723p:plain
ツイートを投稿できているか確認

いよいよ投稿したツイートを表示していきましょう! (実は投稿したツイートを画面に表示出来ずに40分くらい悩みました。。。)

まず投稿したツイートを表示するボックスを容易します。
左のメニューからContainer > Repeating Groupをクリックして以下画像のように設定してください。

f:id:hosaka555:20200623135532p:plain
ツイートを表示するためのボックスを用意する

次にRepeating Group の上に Text というエレメントを配置して次のように設定します。

f:id:hosaka555:20200623140518p:plain
ツイートを表示するためにTextエレメントを配置

これで右上のPreviewをクリックするとツイートが表示されていると思います!

f:id:hosaka555:20200623141534p:plain
投稿したツイートが表示される

めでたしめでたし

最後に

株式会社Hajimariでは、自社開発・受託開発を行っています。
一緒にLaravelやVue.jsを使って開発してくれるエンジニア・デザイナーを絶賛募集しています!

新卒・中途どちらも募集しておりますので、興味のある方は以下の記事をぜひ御覧ください!
みなさまとお会いできるのを心からお待ちしております。

www.wantedly.com

www.wantedly.com

躓いたところ共有しておきます

f:id:hosaka555:20200620190350p:plain
躓いたところ

その原因は次の2つでした。

  1. データを表示するエレメント(要素)を配置していなかったこと
  2. データ型を間違えていたこと

まず1つ目についてですが、データベースに存在する値を表示するときは、Repeating Group というエレメント(以下画像の赤色部分)を配置するだけで表示できると思いこんでしまっていました。
実際にはRepeating Group の上に Text というエレメント(以下画像の青色部分)を配置する必要がありました。 ここに気づくまでにかなり時間がかかってしまいました。。。

f:id:hosaka555:20200620191250p:plain
データを表示するエレメントを配置していなかった

2つ目がデータ型を間違えていたことです。
最初僕はTweetオブジェクトに存在するmessageというプロパティを表示したかったので、以下画像のようにData sourceを設定してしまっていました。。。

f:id:hosaka555:20200620192312p:plain
データ型を間違えていた

正しくは以下画像のようにData sourceに設定する値の型をType of contentに合わせて、Textエレメント上でTweetオブジェクトのmessageプロパティを表示するように設定することで上手く表示することができました。

f:id:hosaka555:20200620192520p:plain
Data sourceに設定する値の型をType of contentに合わせる

f:id:hosaka555:20200620192822p:plain
TextエレメントにTweetオブジェクトのmessageプロパティを表示するように設定する

でめたしでめたし

WordPressでディスク容量がMAXになりカテゴリが表示されなくなった話

wordpress

こんにちは!Hajimariの新卒エンジニアの市川(@shu_chikanne)です。

2020年4月1日に新卒エンジニア2期生としてジョインしました!

普段は、自社プロダクトであるスタートアップ向けマッチングサイト構築パッケージPIECE(https://crowd.itpropartners.com/piece/)の開発や受託開発をしたり、新卒採用関係の業務を行っています!


今回はタイトルにもある通り、WordPressでディスク容量がMAXになったことでカテゴリが表示されなくなった話をしていきたいと思います。

業務の関係上、スクショ等は掲載できないのでご了承ください(><)

今考えても恐ろしい出来事でした・・・

 

 

経緯

発端は6月10日の17時頃。

クライアントから恐ろしい連絡が飛んできました。内容は以下の2つ。

  • ワードプレスのカテゴリーとタグが全てリセットされてしまったこと

  • それに伴いURLが変わってしまったこと このWordPressのサイトは広告の配信先として利用しており、URLが変わることで広告元のURLがデッドリンクになってしまいます。


つまり、「大量の広告のリンク先が表示されず、広告経由の収益が出ない状態」となっていたのです。


同時接続数が100前後のサイトのため、常時100人近くのユーザーがサイトを閲覧していることになります。

そんなサイトのURLがデッドリンクになったと聞いて、本気で冷や汗を書きました。

もういっそのこと、全てを忘れて眠りにつきたい。。。


嘆いていても、原因を見つけて修正しないことにはこの状態は解消されません。


原因調査

ここからはなぜその状態になったのか、原因調査の段階に入ります。

まずはメモリの確認をします。

$ free -m
             total       used       free     shared    buffers     cached
Mem:          7986       4550       3436         37        142        902
-/+ buffers/cache:       3505       4481
Swap:         2047         14       2033

ふむ、問題なし。

先輩エンジニアからディスク容量はどうなの?と聞かれたので、確認してみると、、、

$ df -h
 ファイルシス   サイズ  使用  残り 使用% マウント位置
devtmpfs         3.9G   60K  3.9G    1% /dev
tmpfs            3.9G     0  3.9G    0% /dev/shm
/dev/xvda1        30G   30G   0G   100% /
[ichikawa@ip-172-31-16-13 ~]$

100%!!! はじめてみた!!!


そう、原因はディスク容量が100%になっていたことでした。

ひとまずAWSコンソール上からディスク容量を増やします。(ちなみに一回増やすと減らせません)

そしてターミナル上で以下のコマンドを叩きます。

$ sudo growpart /dev/xvda1

$ sudo resize2fs /dev/xvda1


確認してみます。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        3.9G   60K  3.9G   1% /dev
tmpfs           3.9G     0  3.9G   0% /dev/shm
/dev/xvda1       99G   30G   69G  30% /

しっかり増えてますね。
今回は30G→100Gまでディスク容量を増やしました。

WordPressの管理サイトを確認しに行った所、カテゴリとタグが正常に表示されるようになっていました。
良かった!!!

なぜディスク容量が100%になっていたのか

duコマンドでどのディレクトリの容量が大きいのか確認してみます。

$ du -sh /*
7.0M    /bin
50M /boot
4.0K    /cgroup
60K /dev
11M /etc
408K    /home
93M /lib
21M /lib64
4.0K    /local
16K /lost+found
4.0K    /media
4.0K    /mnt
43M /opt
107M    /root
8.0K    /run
12M /sbin
4.0K    /selinux
4.0K    /srv
2.1G    /swap
1.1G    /swapfile1
0   /sys
8.0K    /tmp
1.3G    /usr
24.9G   /var


なにやらvar配下がとても大きくなっているようです。

var配下も確認してみます。

$ cd /var
$ du -sh ./*
4.0K    ./account
105M    ./cache
124K    ./db
8.0K    ./empty
4.0K    ./games
12K ./kerberos
2.4G    ./lib
4.0K    ./local
16K ./lock
14.8G   ./log
0   ./mail
4.0K    ./nis
4.0K    ./opt
4.0K    ./preserve
132K    ./run
1.8M    ./spool
0   ./swap
4.0K    ./tmp
6.7G    ./www
4.0K    ./yp

logディレクトリがとても大きいことが判明しました。

そしてlogディレクトリを調べていると、Apacheアクセスログのログローテーションを設定していないことが判明。

(そりゃあディスク容量の大きくなるわ。。。)


ログローテーションの設定をし後日確認してみた所、/var/logディレクトリのディスク容量が14.8G→696Mまで減っていました。

再発防止策として、AWSの構成の見直しやディスク容量・メモリ・CPU等の監視を行っていく予定です。(ここらへんも今後記事にしていきたいと思います!)

最後に

Hajimariでは、Laravel、vue.js、Nuxt.jsで開発に挑戦したいエンジニア・デザイナーを絶賛募集中です!

そして、22卒新卒エンジニアのエントリーも心よりお待ちしております!

www.wantedly.com

www.wantedly.com