下級エンジニアの綴

新しく発見したことを綴っていこうと思っています。夢はでっかく上級エンジニアになることです。

goのginを使ってjsonでパラメータを返すサーバーを立ててみた

やんてらです。今回はgoの話になります。 goのフレームワークは何が良いのか分からなかったのでネットで調べたところginが良さげだったので採用してみました。

本題

レストランの一覧を返すjson用のapiサーバを立てていきます。前回と変わらずdokcerで作っていきます(構成は少し変えてます

構成

今回はこんな感じです

|-docker
| |-go
|   |-Dockerfile
|-src
|  |-api
|    |-main.go
|    |-restaurant.json
|    |-Gopkg.toml
|-docker-compose.yml

Dockerfile

  • 今回はalpine使ってみました
FROM golang:1.10.3-alpine3.8

COPY src/api /go/src/api/

WORKDIR /go/src/api/

RUN apk update \
  && apk add --no-cache git \
  && go get -u github.com/codegangsta/gin \
  && go get -u github.com/golang/dep/cmd/dep \
  && dep ensure

EXPOSE 8080

CMD ["gin", "-i", "run"]

docker-compose.yml

version: '3'

services:
  api:
    build:
      context: .
      dockerfile: docker/go/Dockerfile
    volumes:
      - ./src/api:/go/src/api
      - vendor:/go/src/api/vendor
    ports:
      - 8080:8080
    tty:
      true

Gopkg.toml

[[constraint]]
  name = "github.com/gin-gonic/gin"
  version = "1.2.0"

[prune]
  go-tests = true
  unused-packages = true

main.go

  • 今回は自分でjsonを用意してjsonで表示する方法と外部からjsonを取得してjsonで返すという2種類のやり方で実装してみました。
package main

import (
    "github.com/gin-gonic/gin"
    "io/ioutil"
    "encoding/json"
    "log"
)

type Restaurant struct {
    Id   int    `json:"id"`
    Name string `json:"name"`
}

func main() {
    r := gin.Default()

    restaurant := Restaurant{
        Id: 3,
        Name: "サイゼリヤ",
    }

    r.GET("/restaurant", func(c *gin.Context) {
        c.JSON(200, restaurant)
    })

    bytes, err := ioutil.ReadFile("restaurants.json")
    if err != nil {
        log.Fatal(err)
    }

    var restaurants []Restaurant
    if err := json.Unmarshal(bytes, &restaurants); err != nil {
        log.Fatal(err)
    }

    r.GET("/restaurants", func(c *gin.Context) {
        c.JSON(200, restaurants)
    })

    r.Run(":8080")
}

restaurants.json

[
  {"id": 1, "name": "デニーズ"},
  {"id": 2, "name": "ジョナサン"}
]

実行結果

無事表示されましたね f:id:yanterakun:20180815201808p:plain f:id:yanterakun:20180815201803p:plain

まとめ

とりあえず、jsonで値を返すやり方がなんとなく分かったので次はフロント側でいい感じのレストランのマップを実装して行こうと思います。

参考URL

qiita.com

qiita.com

mysqlのクエリが詰まったので解消したメモ

どうもやんてらです。今回はmysqlでクエリが詰まりすぎて何もできなくなったのでそれを解消したメモになります。

クエリが詰まるとCPU使用率がどんどん高くなっていきました(99.8%ぐらいまで上がっていたのでほんと危なかったです笑

show processlist を使用するとmysqlで積み上がっているクエリが見れます

show processlist
+----+------+------------------+---------+---------+------+--------------+-------------------------------------------------------------------------------------------+
| Id | User | Host             | db      | Command | Time | State        | Info                                                                                      |
+----+------+------------------+---------+---------+------+--------------+-------------------------------------------------------------------------------------------+
|  1 | root | 172.18.0.5:35500 | example | Query   |    0 | Sending data | SELECT `sutudents`.* FROM `sutudents`  WHERE `students`.`id` = 94068                      |
|  2 | root | 172.18.0.1:47626 | example | Query   |    0 | NULL         | show processlist                                                                          |
+----+------+----------------------------+---------+------+--------------+-------------------------------------------------------------------------------------------+

上で表示されている詰まっているIDのプロセスをkillすれば残りのプロセスが実行されていくはずです。

kill Id

※もし本番で発生した場合は一人で対応ではなく複数人でダブルチェックしながら作業するのがおすすめです。(select 以外のプロセスをkillすると大惨事になるので気をつけて下さい

今回はこれで以上です。

rubyのbundleでgemfileのパスでハマったのでメモ

どうもやんてらです。bundleを行う時にGemfileが上手く読み込めなかったので、その時周りの方に教えて頂いたメモになります。

このような感じでGemfileを置いてて、

root@dda622750a80:/app# ls -al Gemfile
-rw-rw-r-- 1 1001 1001 3901 Nov 16 09:38 Gemfile

bundle installを叩くと

root@dda622750a80:/app# bundle install
~
Bundle complete! 75 Gemfile dependencies, 176 gems now installed.
Bundled gems are installed into `/usr/local/bundle`

と出てきて想定したgemがインストールされていなくて(予定では 75 Gemfile ではなく 76 Gemfile になるはずでした

bundle config

を叩くと、

root@7934b4f05fde:/app# bundle config
Settings are listed in order of priority. The top value will be used.

gemfile
Set via BUNDLE_GEMFILE: "/tmp/Gemfile"

と出てきてgemのパスが想定した場所と違っていました(想定は/tmp/Gemfile ではなく/app/Gemfile の予定でした

解決方法

以下のコマンドを叩けば解消できました。

$ bundle install --gemfile=Gemfile(Gemfileのパス)
~
Bundle complete! 76 Gemfile dependencies, 176 gems now installed.
Bundled gems are installed into `/usr/local/bundle`
root@7934b4f05fde:/app# bundle config
Settings are listed in order of priority. The top value will be used.

gemfile
Set via BUNDLE_GEMFILE: "/app/Gemfile"
root@7934b4f05fde:/app#

これで無事インストールすることが出来ました。

dockerを使ってgoの環境を立ち上げる流れを作ってみたのでそのメモ

お久しぶりです。久々の更新ですみません。 今回はgo作業する時、dockerを使って開発したいなーと思って作成したそのメモになります。

自分は docker fo mac を使用しています。

フォルダ構成

|- docker
|  |- go
|    |- Dockerfile
|- docker-compose.yml
|- main.go
|- templates
  |- chat.html
Dockerfile
ROM golang:latest

RUN apt-get update -qq && apt-get install vim -y

WORKDIR /go
ADD . /go

EXPOSE 8080

CMD ["go", "run", "main.go"]
docker-compose.yml
version: '3'
services:
  app:
    build:
      context: .
      dockerfile: docker/go/Dockerfile
    environment:
      TZ: Asia/Tokyo
    volumes:
      - ./:/go
    ports:
      - "8080:8080"
    tty: true
    stdin_open: true
main.go
package main

import (
  "log"
  "net/http"
  "path/filepath"
  "sync"
  "text/template"
)

type templateHandler struct {
  once     sync.Once
  filename string
  templ    *template.Template
}

func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  t.once.Do(func() {
  >-t.templ = template.Must(template.ParseFiles(filepath.Join("templates", t.filename)))
  })
  t.templ.Execute(w, nil)
}

func main() {
  http.Handle("/", &templateHandler{filename: "chat.html"})  
  if err := http.ListenAndServe(":8080", nil); err != nil {
    log.Fatal("ListenAndServe", err)
  }
}
chat.html
<div> test test test </div>

実行結果

↑ファイル構成で docker-compose up -d を実行すると f:id:yanterakun:20180803184852p:plain

こんな感じで表示されます。 今回はただ表示して動かしただけなので、次はホットリロードに対応した構成にしたい。

参考URL

qiita.com

モブプロを初めて1ヶ月立ったので感じた事のまとめ

どうもやんてらです。私が開発チームのリーダーになって2ヶ月くらいになりました。

以前書いた記事から1ヶ月くらいたったので、久々の更新です。

今回はチームでモブプログラミングを初めて大体1ヶ月ほどたって感じた事を書いていきます。

はじめはモブプロではなくペアプロもどきをやっていたのですが、 私の時間がレビューコストとリーダーの業務とメンテ等で全て奪われて行き、更に開発もしないといけない状況になりました。 流石にこれは無理だと思ってやり始めたのがモブプログラミングです。

※参考書籍はモブプロをする時、めっちゃ勉強になりました。

モブプロを導入しようと思ったのは以下の点です。

  • 相互レビューしながら開発するのでレビューのコストがなくなるのでは?
  • 案件の認識を合わせるMTGがなくなって常に同期されるのでは?
  • 自分も開発に参加出来るのでは?
  • 個人的に一度やってみたかった←ココ重要!!

モブプロを行う時のルールは以下のとおりです

モブプロのルール

  • 毎朝、1日の予定を決める
    • 各メンバーに会議が入っている等を洗い出す
    • 開発を行う時間を決める
      • 自分たちのチームは10:00-18:00でモブプロをしてます
      • 残りの1時間は各々やりたいことをやってます。
  • 休憩
    • 自己判断で休憩をとるのが難しくなるので、強制的に休憩を取るタイミングを決める(1、2時間単位ぐらい
    • 大体10~20分くらい休む
    • 全員で考えて10分詰まったら強制的に休憩する
    • 17時を過ぎているとそのまま振り返りをして自習(解散)ということもある
  • 1日の振り返りは絶対にする
    • これをやらないと最適化されないのでよりチームに合ったやり方と見つけるために振り返りの時間を30分ほど取ってます
    • google driveなどで今日やった事やKPTの写真を取って成果の管理する。
  • PCは各々によって環境が違うので、ドライバー交代時はブランチをpullする。
  • 案件の見積もりはメンバー全員でする
    • issueは機能単位で切り、出来るだけMinimumにする
      • ここで言うMinimumとは見積もりが出来る且つ、少し余裕があるくらいの見積もりの大きさです
    • 追加や漏れがあった場合、別issueで行う
    • 案件で発生するissueをまとめるissueを作成する
  • 2週間のスプリントで区切り、見積もり含めて順調に案件が進んでいるかを見直すようにした。

モブプロのルールは毎日の振り返りを行い、毎日振り返りをして最適化した結果こうなりました。 個人的に見解ですがルールが変わらなくなれば、見積もりを含めてほぼ完璧に成果が出せるようになっていると思います。

やってみた結果(メリット)

  • プルリクを投げるとすぐにマージできるようになった。
  • 細かくcommit&pushをするようになった。
  • 互いが何をやっているかの共有会がなくなった。
  • 私も開発に参加出来る時間が増えた。
  • メンバー間のコミュニケーションがよくなった。
  • 周りから見て楽しそうに開発しているように見えているらしい。
  • 教育コストが減った。
  • 雰囲気が良さげだと別のチームが真似をしてモブプロに近いことを始める。
  • いらない会議を減らせた

やってみた結果(デメリット)

  • 正直めちゃくちゃしんどい。
  • サボる事は不可能になった。
    • 自分のタイミングで気分転換するのが難しいので、そこはいい感じに解決しないと問題になる。

まとめ

自分のチームでは基本的にモブプロ+アジャイルというスタンスでやってます。

基本的にMAX6.5時間ほどモブプロをして、後の1時間は各々でやりたい業務をするという流れにした結果、良い雰囲気で開発出来るようになったかなと思っています。(残りの0.5時間は休憩です

あと、余裕がなくなると愚痴が多くなりパフォーマンスが下がるので、出来るだけ余裕を持って作業出来るようにするとチームは良いパフォーマンスを発揮するのでは無いかなと思いました。

参考書籍

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

アジャイルサムライ−達人開発者への道−

アジャイルサムライ−達人開発者への道−

カイゼン・ジャーニーを読みながらマネジメントっぽい事を始めて2週間ぐらいたったので感じた事をメモ

最近チームのリーダーの人が抜けて急遽自分が代わりにマネジメントっぽい事を始めたので気づいた事をメモ。

今までスクラムを意識してやっていたのですが、どうもチームで作業している感が無くて改めて今までの開発フローを見直しました。 (ほとんどカイゼン・ジャーニーを参考にして行いました)

やめた事

  • 開発チーム (4人)の代表とプロダクトオーナーだけで話し合って案件(githubのISSUEのチケット)の優先順位を決めていた事。
  • ↑の会議で話し合った案件をチームに割り振る事(優先度の理由は別途聞き直す理由があった)。
  • 1つの案件に対して1人で作業する事。

始めた事

  • 案件の優先度は開発チーム全員とプロダクトオーナーで話し合って優先順位を決める事。
  • 決めた優先順位の案件に対して2人以上で取り組む事。
    • スコープが小さすぎると1人でやる事もある
  • ISSUEのテンプレートを作成した。
    • issueは開発チーム以外から上がることが多いので案件について誰が見てもわかるようなテンプレートを作成。
  • トレードオフスライダー
  • 星取表(スキルマップ)

やった結果

  • 案件の優先度は開発チーム全員とプロダクトオーナーで話し合って優先順位を決める事。
    • 開発チームに危機感や一体感が出てきた。
  • 決めた優先順位の案件に対して2人以上で取り組む事。
    • これは相談できる相手がいるというのがあったりするのでチームの雰囲気は少し良くなったなと思います。
  • ISSUEのテンプレートを作成した。
    • これは作成したばかりなのでまだ結果はわかりません。
  • トレードオフスライダー
    • 開発チームのメンバーが何故このサービスにジョインしているのか知ることが出来た。
    • メンバーの優先度が互いに共有できた。
  • 星取表(スキルマップ)
    • メンバーが今の開発チームで不安に思っていることが知れた。
    • メンバーの苦手な部分を知れた。
    • メンバーのやりたいことが知れた。
    • これは各自の技術的なスキルマップだけでは無くサービスに関しての機能単位でもやることにより、どの機能を誰に聞けば良いかなども明確になった。
      • 逆に誰も知らない機能があるというのも明確になったのでより危機感を覚えました笑

最近始めようと思っていること

  • 朝の案件の共有をもう少し時間を取ること。
    • 具体的にはファイブフィンガーを取り入れようと思ってます。

まとめ

結果がすぐに出ている訳ではないですが、チームで見えていない部分の共有が出来るようになったかなと思ってます。 個人的な考えですが、メンバー1人1人の課題はチームの課題だと言っても過言ではないと個人的に思ってます。 なのでこれからはどんどん不要な課題は取り除けたら良いなと思ってます。

カイゼン・ジャーニーは勉強になる事ばかりだったので、困ったらとりあえず読み直そうと思います。

rubyのcountについてメモ

countを使わなくて失敗したので戒めを含めメモ。

Active Recordのデータ(配列)に対して

sizeを使えば配列を全てオンメモリで扱って、結果を返す。

countはを使えばdbに投げて結果を返してくれる。

↑のことはわかっていたけど、物理的な部分を理解しているつもりで終わっていた。

例えば、100件程度のデータならsizeの方が良いと思うが、数十万件となるとcountの方が良いと思う。

理由としては

数十万件のデータを全てメモリに載せようとするとおそらくメモリが足りずに落ちる

からである。

blank?とかpresent?とかも同じことが言える。

配列を判定する時に値が存在する、存在しないという処理も配列のデータをオンメモリで扱おうとするので仮に数十万件データが入っていると落ちる可能性がある。

array.count > 0

という処理はpresent?を使えば良いと思っていたけど、時には必要なんだなと思った。

countが使えない場合はfind_eachとかを使って頑張るしか無いかなと思う。

その辺をわかっているつもりでわかっていなかったから、不具合を産んでしまった。次は絶対に同じミスをしない。