Day 1: 開発環境構築とHello World - 背景知識
プログラミングとは何か
コンピュータへの指示
プログラミングとは、コンピュータに「何をしてほしいか」を伝える作業です。
人間同士の会話では、「お茶を入れて」と頼めば相手は理解してくれます。しかし、コンピュータには以下のように詳しく伝える必要があります:
- やかんに水を入れる
- 火にかける
- 沸騰するまで待つ
- 茶葉を急須に入れる
- お湯を注ぐ
- 30秒待つ
- 湯呑みに注ぐ
- 第1世代(1940年代): 機械語 - 0と1の羅列
- 第2世代(1950年代): アセンブリ言語 - 記号を使った低レベル言語
- 第3世代(1960年代〜): C、Java、Python - 人間が読める高レベル言語
- 第4世代(現代): Go、Rust、Swift - モダンで安全性重視の言語
- 2007年: Google社内で開発開始(Robert Griesemer、Rob Pike、Ken Thompson)
このような「手順」をコンピュータが理解できる言葉で書いたものが「プログラム」です。
プログラミング言語の進化
コンピュータが直接理解できるのは「0」と「1」の羅列(機械語)だけです。しかし、人間が0と1でプログラムを書くのは非常に困難です。
そこで、人間が読み書きしやすい「プログラミング言語」が生まれました。Go、Python、Java、C++など、多くの言語があります。
プログラミング言語の世代:
---
Go言語について
なぜGoなのか
Go(別名:Golang)は2009年にGoogleで開発されたプログラミング言語です。
特徴:
| 特徴 | 説明 |
|---|---|
| シンプル | 覚えることが少なく、学習しやすい |
| 速い | コンパイル言語で実行速度が速い |
| 安全 | メモリ管理が自動で、エラーが起きにくい |
| 並行処理 | 複数の処理を同時に行いやすい |
| 実用的 | Google、メルカリ、LINEなど多くの企業で使用 |
Goの歴史と設計思想
開発の経緯:
- 2009年11月10日: オープンソースとして公開
- 2012年3月28日: Go 1.0リリース(後方互換性の保証開始)
- 2015年: Go 1.5でGoコンパイラ自体がGoで書き直される(セルフホスティング達成)
- 現在: 世界中で広く使われるモダン言語に
- シンプルさ: 「少ないことは多いこと(Less is more)」
- 実用性: 理論より実践を重視
- 並行処理: マルチコアCPU時代に対応
- 高速コンパイル: 開発者の待ち時間を最小化
- 明確さ: 暗黙的な動作を避け、明示的に書く
設計哲学:
Go言語の生みの親たち
Rob Pike(ロブ・パイク):
- UNIX、Plan 9、UTF-8の開発に関わった伝説的プログラマー
- 「シンプルさ」を徹底的に追求
Ken Thompson(ケン・トンプソン):
- UNIXとCの共同開発者
- チューリング賞受賞者
- 実行効率を重視した設計
Robert Griesemer(ロバート・グリースマー):
- JavaのHotSpot JVMやV8 JavaScriptエンジンに貢献
- 型システムと並行処理の専門家
---
実世界での活用事例
1. Google(開発元)
使用例:
- YouTube: 動画配信基盤の一部
- Kubernetes: コンテナオーケストレーションシステム(全体がGoで書かれている)
- Google Cloud Platform: 多くのバックエンドサービス
なぜGoを選んだのか:
- 大規模システムでの高いパフォーマンス
- 並行処理による効率的なリソース利用
- シンプルな構文による保守性の向上
2. Docker(コンテナ技術)
使用例:
- Docker本体が全てGoで実装
- 2013年の登場以来、DevOpsの標準ツールに
Goを選んだ理由:
- クロスプラットフォーム対応(Windows、Mac、Linux)
- 単一バイナリで配布可能
- システムプログラミングに適した性能
3. Uber(ライドシェア)
使用例:
- マイクロサービスアーキテクチャの基盤
- リアルタイム位置情報処理
- 高負荷トラフィック処理
導入効果:
- サービスの応答時間が大幅に改善
- メモリ使用量の削減
- 開発者の生産性向上
4. Netflix(動画ストリーミング)
使用例:
- Rend: 分散キャッシュシステム
- インフラストラクチャツール
選定理由:
- 1億人以上の同時接続を支える性能
- 障害時の自動復旧機能
- 運用コストの削減
5. メルカリ(日本)
使用例:
- マイクロサービス基盤
- API Gateway
- データ処理パイプライン
導入背景:
- 急成長するトラフィックへの対応
- グローバル展開を見据えた技術選定
- エンジニアの採用しやすさ
- Dropbox: データ同期エンジン
- Twitch: チャットシステム
- Cloudflare: CDNとセキュリティサービス
- BBC: ニュース配信システム
- Medium: ブログプラットフォーム
6. その他の著名企業
---
Go言語エンジニアの市場価値
年収データ(2024年現在)
日本国内:
- ジュニアレベル(1-3年): 450万円〜650万円
- ミドルレベル(3-5年): 650万円〜900万円
- シニアレベル(5年以上): 900万円〜1,500万円
- テックリード/アーキテクト: 1,200万円〜2,000万円以上
海外(主に米国):
- ジュニア: $80,000〜$120,000
- ミッド: $120,000〜$180,000
- シニア: $180,000〜$250,000
- スタッフエンジニア: $250,000〜$400,000以上
求人需要トレンド
Stack Overflow Developer Survey 2024:
- 最も需要が高い言語: 5位
- 最も愛されている言語: 4位
- 最も学びたい言語: 6位
求人数の推移:
- 2020年比で約3倍の求人増加
- クラウドネイティブ開発案件が急増
- DevOps/SREポジションでの需要が特に高い
- バックエンドエンジニア → シニアバックエンドエンジニア
キャリアパス
典型的なキャリアパス:
- クラウドエンジニア → クラウドアーキテクト
- SREエンジニア → リードSRE
- フルスタックエンジニア → テックリード
スキルの組み合わせで市場価値UP:
- Go + Kubernetes: クラウドネイティブ開発
- Go + Docker: コンテナ化・DevOps
- Go + gRPC: マイクロサービス通信
- Go + AWS/GCP/Azure: クラウドインフラ
---
開発環境の構成要素
1. Go言語処理系
プログラムを実行するために必要なソフトウェアです。
┌─────────────────────────────────────────┐
│ あなたが書くコード │
│ (main.go) │
└─────────────────┬───────────────────────┘
↓ コンパイル
┌─────────────────────────────────────────┐
│ 実行可能ファイル │
│ (main または main.exe) │
└─────────────────┬───────────────────────┘
↓ 実行
┌─────────────────────────────────────────┐
│ 出力結果 │
│ "Hello, World!" │
└─────────────────────────────────────────┘
コンパイルとインタプリタの違い:
| 方式 | 言語例 | 特徴 | 速度 |
|---|---|---|---|
| コンパイル | Go、C、Rust | 実行前に機械語に変換 | 速い |
| インタプリタ | Python、Ruby | 実行時に逐次解釈 | 遅い |
| JIT | Java、JavaScript | 実行時にコンパイル | 中間 |
2. テキストエディタ
プログラムを書くためのソフトウェアです。
Visual Studio Code(VS Code)が推奨される理由:
必須のVS Code拡張機能:
- Go(公式): Goの開発支援
- Error Lens: エラーをインラインで表示
- GitLens: Git履歴の可視化
- Better Comments: コメントの色分け
代替エディタ:
- GoLand: JetBrains製の有料IDE(機能豊富)
- Vim/Neovim: 軽量・高速なテキストエディタ
- Sublime Text: シンプルで高速
3. ターミナル(コマンドライン)
コマンドを入力してプログラムを実行する画面です。
$ go run main.go # プログラムを実行
Hello, World! # 出力結果
よく使うGoコマンド:
| コマンド | 用途 |
|---|---|
| `go run` | コンパイル&実行 |
| `go build` | 実行ファイルを生成 |
| `go test` | テストを実行 |
| `go fmt` | コードを整形 |
| `go mod` | 依存関係管理 |
---
Goプログラムの基本構造
必須要素
すべてのGoプログラムには以下の要素が必要です:
package main // 1. パッケージ宣言
import "fmt" // 2. インポート
func main() { // 3. main関数
// ここに処理を書く
}
各要素の説明
1. パッケージ宣言(package)
package main
packageで始まるmainパッケージ = 「このプログラムを実行できる」という意味パッケージの役割:
- コードを論理的な単位に分割
- 名前空間の提供(名前の衝突を防ぐ)
- 再利用可能なコードの作成
2. インポート(import)
import "fmt"
fmtは「フォーマット」の略で、文字を表示する機能を持つimport (
"fmt"
"math"
"strings"
)
標準ライブラリの主要パッケージ:
fmt: フォーマット付き入出力os: オペレーティングシステム機能io: 入出力プリミティブnet/http: HTTPクライアント・サーバーencoding/json: JSON処理time: 時刻・日付処理
3. main関数
func main() {
// 処理
}
func = function(関数)の略main() = プログラムの「入口」(エントリーポイント){ } = 処理の範囲を示す(ブロック)main関数の特徴:
- プログラム実行時に自動的に呼ばれる
- 引数を取らない
- 戻り値を返さない
- mainパッケージに必ず1つ存在する必要がある
---
fmt パッケージ
主な関数
| 関数 | 説明 | 例 |
|---|---|---|
| `Println` | 文字列を表示して改行 | `fmt.Println("Hello")` |
| `Print` | 文字列を表示(改行なし) | `fmt.Print("Hello")` |
| `Printf` | フォーマット付きで表示 | `fmt.Printf("Age: %d", 25)` |
| `Sprintf` | フォーマットした文字列を返す | `s := fmt.Sprintf("Age: %d", 25)` |
| `Scan` | 標準入力から読み込む | `fmt.Scan(&name)` |
Println vs Print
// Println(改行あり)
fmt.Println("りんご")
fmt.Println("みかん")
// 出力:
// りんご
// みかん
// Print(改行なし)
fmt.Print("りんご")
fmt.Print("みかん")
// 出力:
// りんごみかん
Printfのフォーマット指定子
| 指定子 | 型 | 説明 |
|---|---|---|
| `%d` | int | 10進数 |
| `%f` | float | 浮動小数点数 |
| `%s` | string | 文字列 |
| `%t` | bool | 真偽値 |
| `%v` | any | デフォルトフォーマット |
| `%T` | any | 型を表示 |
| `%p` | pointer | ポインタアドレス |
---
文字列(String)
基本ルール
""(ダブルクォート)で囲む''(シングルクォート)は使えない(runeリテラル用)"Hello, World!" // OK
"こんにちは" // OK(日本語)
'Hello' // NG(シングルクォートは文字列に使えない)
Hello // NG(クォートなしは変数名と解釈される)
文字列の連結
+演算子で文字列を連結できます:
"Hello, " + "World!" // → "Hello, World!"
エスケープシーケンス
特殊な文字を表現する方法:
| シーケンス | 意味 |
|---|---|
| `\n` | 改行 |
| `\t` | タブ |
| `\"` | ダブルクォート |
| `\\` | バックスラッシュ |
fmt.Println("1行目\n2行目") // 改行
fmt.Println("名前\t年齢") // タブ
---
開発手法とベストプラクティス
Test-Driven Development (TDD)
TDDの3ステップ:
- Red: 失敗するテストを書く
- Green: テストが通る最小限のコードを書く
- Refactor: コードを改善する
初心者向けTDD:
// main_test.go
package main
import "testing"
func TestHello(t *testing.T) {
result := "Hello, World!"
expected := "Hello, World!"
if result != expected {
t.Errorf("got %s, want %s", result, expected)
}
}
Gitワークフロー
基本的なGitコマンド:
git init # リポジトリ初期化
git add . # 変更をステージング
git commit -m "メッセージ" # コミット
git status # 状態確認
git log # 履歴表示
良いコミットメッセージの書き方:
- 1行目: 何をしたか(50文字以内)
- 2行目: 空行
- 3行目以降: なぜそうしたか(詳細)
Add hello world program
初めてのGoプログラムとして、
標準的なHello Worldを実装
コードレビューの観点
チェックポイント:
- 動作確認: プログラムが正しく動くか
- 可読性: 他の人が読みやすいか
- 保守性: 後で変更しやすいか
- 効率性: 無駄な処理がないか
デバッグ戦略
段階的デバッグ:
- エラーメッセージを読む: 何が問題か理解する
- print文を追加: 変数の値を確認する
- コードを分割: 問題箇所を特定する
- 最小再現: 問題を単純化する
デバッグ例:
func main() {
name := "太郎"
fmt.Printf("DEBUG: name = %s\n", name) // デバッグ出力
fmt.Println("こんにちは、" + name + "さん")
}
---
ソフトスキル:エンジニアとしての成長
質問の仕方
良い質問:
- 何をしようとしているか説明
- 何が期待される動作か説明
- 実際に何が起きたか説明
- エラーメッセージを共有
- 試したことを共有
例:
【質問】Hello Worldが表示されません
【やりたいこと】
"Hello, World!"という文字列を画面に表示したい
【期待される動作】
Hello, World!と表示される
【実際の動作】
エラー: undefined: fmt.Printl
【試したこと】
1. go runコマンドで実行
2. スペルを確認(Printlと書いている)
【環境】
- Go version: 1.21
- OS: macOS
チーム開発とコミュニケーション
効果的なコミュニケーション:
- 明確に: 曖昧な表現を避ける
- 簡潔に: 要点を絞る
- 具体的に: 例を示す
- 建設的に: 解決策を提案する
ペアプログラミング:
- ドライバー: コードを書く人
- ナビゲーター: レビューする人
- 定期的に役割を交代
- 学習効果が高い
学習戦略
効果的な学習方法:
- アクティブラーニング: 読むだけでなく書く
- 反復練習: 同じコードを何度も書く
- プロジェクトベース: 実際のものを作る
- 教える: 他人に説明することで理解が深まる
プログラミング上達の段階:
- 模倣: サンプルコードを写経
- 理解: なぜそう書くか理解
- 応用: 少し変更してみる
- 創造: ゼロから書く
---
本番環境への考慮事項
セキュリティ
基本原則:
- 入力検証: ユーザー入力を信頼しない
- エラー処理: エラーを適切に処理
- 最小権限: 必要最小限の権限で実行
- ログ記録: 重要な操作を記録
避けるべきこと:
- パスワードをコードに直接書く
- エラーメッセージで内部情報を露出
- 権限チェックを省略
パフォーマンス
最適化の優先順位:
- まず動かす: 正しく動くコードを書く
- 測定する: ボトルネックを特定
- 最適化: 必要な部分だけ改善
Goのパフォーマンス特性:
- 静的型付けによる高速実行
- ガベージコレクションによるメモリ管理
- ゴルーチンによる並行処理
スケーラビリティ
スケーラブルな設計:
- ステートレス: 状態を持たない設計
- 疎結合: モジュール間の依存を減らす
- 並行処理: ゴルーチンを活用
---
よくあるエラーと対処法
エラーメッセージの読み方
./main.go:6:5: undefined: fmt.Printl
この形式の意味:
./main.go= エラーがあるファイル6:5= 6行目の5文字目undefined: fmt.Printl=fmt.Printlは定義されていない
代表的なエラー
| エラー | 原因 | 解決方法 |
|---|---|---|
| `undefined` | スペルミス、または未定義 | 正しいスペルを確認 |
| `syntax error` | 文法エラー | `{ }` や `""` の対応を確認 |
| `imported and not used` | importしたのに使っていない | 不要なimportを削除 |
| `declared and not used` | 変数を宣言したのに使っていない | 変数を使用するか削除 |
---
インストール手順の詳細
macOS
# Homebrewがない場合は先にインストール
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Goのインストール
brew install go
# 確認
go version
# パスの設定(.zshrcまたは.bashrc)
export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
Windows
.msiファイルを実行go versionを実行して確認環境変数の確認:
echo %GOPATH%
echo %GOROOT%
Linux(Ubuntu/Debian)
sudo apt update
sudo apt install golang-go
# または、最新版を直接インストール
wget https://go.dev/dl/go1.21.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
# パスの設定(.bashrc)
export PATH=$PATH:/usr/local/go/bin
# 確認
go version
---
設計原則の基礎
KISS(Keep It Simple, Stupid)
シンプルに保つ:
// 複雑(避けるべき)
func isEven(n int) bool {
if n % 2 == 0 {
return true
} else {
return false
}
}
// シンプル(推奨)
func isEven(n int) bool {
return n % 2 == 0
}
DRY(Don't Repeat Yourself)
繰り返しを避ける:
// 悪い例
fmt.Println("こんにちは、太郎さん")
fmt.Println("こんにちは、花子さん")
fmt.Println("こんにちは、次郎さん")
// 良い例(後の学習で理解)
names := []string{"太郎", "花子", "次郎"}
for _, name := range names {
fmt.Printf("こんにちは、%sさん\n", name)
}
---
参考資料
公式リソース:
学習サイト:
コミュニティ:
書籍:
- 「プログラミング言語Go」(通称:ゴーファーの本)
- 「Go言語による並行処理」
- 「スターティングGo言語」