Open7

PHPerが集う会社でGo言語を布教するためのメモ

こーひーあーるこーひーあーる

Go言語の概要

https://go.dev/

  • Googleが開発、サポートするオープンソースのプログラミング言語
  • 簡単に習得でき、チームに最適(と謳われている)
  • コンパイル言語、静的型付け言語
こーひーあーるこーひーあーる

Go言語でHTTPアクセスしたらHelloWorldを表示してみる

### ホストマシンにGoをインストール
$ brew install go
### 作業用ディレクトリ作成
$ mkdir GoHelloWorld

### ディレクトリに移動
$ cd GoHelloWorld

### モジュール管理を初期化
$ go mod init GoHelloWorld

### Dockerファイル
$ touch Dockerfile

### エントリーポイントとなるファイルの作成
$ touch main.go

VSCodeでDockerfileを編集。

# ベースイメージとしてGoの公式イメージを使用
FROM golang:1.23-alpine

# 作業ディレクトリを設定
WORKDIR /app

# Goのモジュールを初期化
RUN go mod init GoHelloWorld

# ローカルのGoファイルをコンテナにコピー
COPY main.go .

# Goアプリケーションをビルド
RUN go build -o main .

# コンテナが起動する際に実行するコマンド
CMD ["./main"]

# アプリケーションが使用するポートを公開
EXPOSE 8080

VSCodeでmain.goを編集。

// mainパッケージは、Goプログラムのエントリーポイントとなる特別なパッケージです。
// Goでは、mainパッケージを含むプログラムが実行可能なバイナリファイルとしてビルドされます。
// そのため、プログラムを実行する際には必ず mainパッケージと main関数が必要です。
package main

// 必要なパッケージを読み込みます。
import (
	"fmt"      // 標準出力などを行うためのパッケージ
	"log"      // ログの出力を行うためのパッケージ。エラーメッセージや情報メッセージをコンソールに表示するために使用します。
	"net/http" // HTTPサーバー機能を使うためのパッケージ
	"time"     // 時間に関する操作を行うためのパッケージ
)

// アクセスログを記録するミドルウェアです。
func loggingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now() // 処理開始時間を記録
		next.ServeHTTP(w, r) // 次のハンドラーを呼び出す
		duration := time.Since(start) // 処理にかかった時間を計算

		// ログの出力
		log.Printf("%s %s %v", r.Method, r.URL.Path, duration)
	})
}

// HelloWorldする関数です。
// http.ResponseWriter: クライアントへのレスポンスを書き込むためのオブジェクト
// http.Request: クライアントからのリクエスト情報を保持するオブジェクト
func helloWorld(w http.ResponseWriter, r *http.Request) {
	// レスポンスに "Hello, World!" を書き込む
	fmt.Fprintf(w, "Hello, World Go!")
}

func main() {
	// パス("/hello")にアクセスがあった場合に実行されるハンドラーを設定します。
	// - http.Handle: 特定のパスに対してリクエストを処理するハンドラーを登録する関数です。
	// - "/hello": このパスに対するリクエストがあった場合に helloWorld 関数が呼び出されます。
	// - loggingMiddleware: アクセスログを記録するためのミドルウェア。次のハンドラー(helloWorld)をラップして、リクエストが処理される際にログを出力します。
	// - http.HandlerFunc(helloWorld): helloWorld関数をHTTPハンドラーとしてラップします。これにより、http.Handleで指定したルートパスに対するリクエストがこの関数に送られるようになります。
	http.Handle("/hello", loggingMiddleware(http.HandlerFunc(helloWorld)))

	// 8080ポートでHTTPサーバーを起動し、リクエストを待ち受けます。
	// http.ListenAndServeはサーバーを起動し、指定したポートでリクエストを受け付ける関数です。
	http.ListenAndServe(":8080", nil)
}

コンテナのビルド&起動

$ docker build -t go-hello-world . && docker run -p 8080:8080 go-hello-world

ブラウザでアクセス
http://localhost:8080/hello

こーひーあーるこーひーあーる

PHPとのパフォーマンス比較① 素朴にHelloWorld

PHPでHelloWorldするまで

$ mkdir PHPHelloWorld

### ディレクトリに移動
$ cd PHPHelloWorld

### Dockerファイル
$ touch Dockerfile

### PHPスクリプトを作成
$ touch hello.php
# PHPの公式イメージを使う
FROM php:8.3-apache

# 作業ディレクトリの指定
WORKDIR /var/www/html

# index.phpをコンテナにコピー
COPY hello.php /var/www/html/

# ポート80を公開
EXPOSE 80
<?php
echo "Hello World PHP!";
$ docker build -t php-hello-world . && docker run -p 80:80 php-hello-world

ブラウザでアクセス
http://localhost:80/hello.php

ApacheBenchでパフォーマンス比較

### Go
$ ab -n 1000 -c 10 http://localhost:8080/hello

### PHP
$ ab -n 1000 -c 10 http://localhost:80/hello.php

あんまり差がなかった (ちょっと意外)

こーひーあーるこーひーあーる

RESTAPI作る上での環境構築を調べる

  • ユーザーの取得・登録・更新・削除を実装してみる
  • 開発環境をコンテナで構築
    • Visual Studio CodeにDev Containersを
    • SQL Serverもコンテナで
  • フレームワークにGinを使用
  • ホットリロードのためAirを使用
  • デバッグのためにdlvを使用

https://github.com/coffee-r/PracticeGoWebAPI1