Go関連のことを調べてみた

Go関連のことを調べてみた

サイバーエージェントのACEインターン体験記

## はじめに

2024年夏に、株式会社サイバーエージェントさんの「次世代トップエンジニア創出インターンシップ ACE」に参加しました!!

今回はインターンで得た学びや感想をブログにまとめておこうと思います。

## 概要

このインターンは、学生がチームに分かれて、与えられた仕様に沿ってプロダクトを開発するハッカソン形式のインターンです。
学生1人につき社員さんが1人メンターとしてついてくださり、技術的な相談などをさせていただきました。

### 日程

9/11 ~ 9/24 の2週間で行われました。

### チーム構成

チームはB, Cの2チームで、それぞれ5人ずつの学生で構成されていました。

私のチームでは、5人のうち3人がバックエンド、2人がフロントエンドを担当しました。

### プロジェクトテーマ

与えられたお題は「架空の動画配信サービス『あれまぁTV』の番組表を作成する」でした。

番組表には「マイリスト登録」機能があり、マイリストに登録した番組は「マイリスト」ページに表示されるようにします。

番組表という1ページの中に様々な情報が詰まっており、UIも複雑

元記事を表示

testifyパッケージのassert/requireとは? [Go]

Goのテストケースを実装した際に、testifyパッケージのrequireとasserを使ったのですが、あまり違いがわからなかったことありませんか?

今回は、Goのテストコードでよく使われる`testify/assert`パッケージと`testify/require`パッケージの違いと、それぞれのメソッドについて調べてみようと思います。

https://github.com/stretchr/testify

# assertとrequireはどのような役割をしているのか

この二つは、testifyパッケージに入っているテスト用ツールです。

違いは以下のようになっています。

|パッケージ名|違い
|—|—
|assert|テストが失敗しても実行し続ける
|require|テストが失敗したら即時終了

主な違いはテストが失敗しても実行し続けるか終了するかの違いになっています。

# インストール

下のコマンドで、go.modに依存関係を追加してください。

“`go:zsh
go get github.com/stretchr/testify
“`

# as

元記事を表示

golangのsamber/loを使って複数の構造体スライスを一気にマッピングしたい

# 概要
ある構造体の値を、別の構造体にマッピングしたいことがあると思います。

例えばインフラ層にはSELECT文を実行した結果をマッピングするための構造体Aがあって、それをドメイン層のモデルである構造体Bにマッピングして、さらにそれをクライアントに返すレスポンス用の構造体Cにマッピングして…

というように層ごとにデータ構造が変わる場合は適宜こうした操作が必要になります。
一般的にはこうした操作はヘルパー関数を作って対応されているのでしょうか。
自分はこれに対するベストプラクティスが分からないので、いい方法を知っていればぜひ教えていただきたいのですが、自分なりに `samber/lo` を使ってやってみたので小ネタ的な紹介です。

https://github.com/samber/lo

# ユースケース
2つ以上の構造体スライスの内容を1つの構造体スライスにマッピングしたいときなどです。
例えばあるメソッドを実行すると `構造体Userのスライス` と `構造体BlogPostのスライス` が返ってくるので、それらの内容を合わせたレスポンスを生成するために `構造体UserPo

元記事を表示

自作オブジェクトストレージ日記.part4

# part4の概要

前回は1MBごとにファイルを分割し、ハッシュ値を計算してフッターとして書き込みました。今回はリード・ソロモン符号を用いて、データの冗長性を持たせ、復元可能にします。

## 必要なパッケージのインストール

“`shell
go get -u github.com/klauspost/reedsolomon
“`

### リード・ソロモン符号の設定
データシャードとパリティシャードの数を設定します。

“`go
const (
DataShard = 6 //リード・ソロモン符号のパラメータ データの分割数
Parity = 2 //リード・ソロモン符号のパラメータ パリティーの数
)

var ErasureSetNum = DataShard + Parity //リード・ソロモン符号のパラメータ
“`

### データの分割とエンコード
データを分割し、リード・ソロモン符号を用いてパリティシャードを生成します。
datashrdsには この場合[8][1024*1024] のバイト配列を入力します。
“`go
func

元記事を表示

自作オブジェクトストレージ日記.part3

## part3
前回は1MBごとにファイルを分割し、マージしました。今回はデータ部分のハッシュ値を計算し、ファイルの最後に書き込みます。

まず、必要なパッケージをインストールします。
“`sh
go get -u github.com/minio/highwayhash
“`

### フッター構造体の追加
第2回ではフッターがありませんでしたが、第3回ではハッシュ値を格納するためのフッターを追加しました。
“`go
type Footer struct {
HashType uint8 //ハッシュの種類, 0:HighwayHash256
Hash [32]byte //ブロックのハッシュ値
}
“`
ハッシュの方法を今後変更する可能性を考えてハッシュタイプも追加します。今のところ唯一登録されている、ハッシュタイプ0はhighway hashの256bitです。

### ハッシュ値の計算とフッターの書き込み
データを分割して書き込む際に、ハッシュ値を計算し、フッターとして書き込む処理を追加しました。

“`go
key := make

元記事を表示

自作オブジェクトストレージ日記.part2

前回 : 自作オブジェクトストレージ日記.part1

# 第2回 1MBごとにファイルを分割する

前回は20GBのファイルを5GB事に分割しました。今回は1MBごとに分割し、マージします

リード・ソロモン符号を使ったイレイジャーコーディングを利用するための下準備です。
先頭にヘッダーを付け、ファイルサイズを記録しました。これによって最後のファイルサイズが1mBぴったりにならなかったとしても安心です。
“`go
package main

import (
“encoding/binary”
“fmt”
“os”

“github.com/cheggaaa/pb/v3”
)

type Header struct {
FileSize uint32 //ブロックのファイルサイズ
I_Counter uint32 //Iのカウンタ. 0から始まる
}

func main() {
fmt.Println(“Hello World!”)
// binary/inputをバイナリファイルとして読み込み、1MBごとに分割してbinary/fragments/%dに書き込

元記事を表示

自作オブジェクトストレージ日記.part1

# はじめに
今回作成するストレージは個人用のものであり、これを利用したことに起こった損害について一切の責任を負いませんのであしからず。

# なぜ作るのか
自分のデータを預けるのに他人の作ったソフトウェアだと不都合がありそうだから。あと自分にあったストレージソフトウェアが見つからなかったため

# 背景
## 大容量ストレージにおける状況
大容量ストレージを扱う技術はすでにあります。企業などでは昔から大容量ストレージを扱っていたため当然でしょう。しかし個人で使うにあたってそのソリューションを導入するのは高価で現実的ではありません。例としてSANストレージを束ねるスイッチの価格はまともな速度なもので10万円を超える。(Lenovo ThinkSystem DB610S、8 ポート )
## 私の求めるストレージ要件
ここは人によって異なるでしょうが、私の用途はデータ置き場に近いものなので以下のような要件になりました
– ストレージ効率が良い
値段に直結するので当たり前です。HDDはもちろん容量単価の一番安い16TBのものを使用します
– 待ち時間無しで拡張可能
毎日保存処理が走るのでR

元記事を表示

動的にGoroutinesのワーカーを増減させる

Goはゴルーチンを使うことで簡単に並行処理を行うことができます。
また、ゴルーチンはかなり軽量で大量に生成することができるとされています。

とはいえ上限はあるわけで、短時間であまりに大量にゴルーチンを作成した場合はパフォーマンスが悪化したり、リソースを確保しすぎてエラーが発生することもある(と思います)

そのためよく行われるのは、以下の2つかと思います(少なくとも自分は)

1. あらかじめ規定数の worker を作成しておく
1. セマフォを使って同時起動数を制限する

個人的にはどんどんゴルーチンを作るのがあまり好きではないので、あらかじめ規定数のworkerを作成することが多いです。

ただ設定ファイルなどで worker 数を設定していて、設定をリロードさせた場合に worker 数を反映させる際など動的に worker 数を変更したい場合に困ります。
セマフォを使っている場合であれば、セマフォの作りを工夫すれば動的に変更することは比較的簡単です。

ただ、随時ゴルーチンを起動するパターンだと、動作しているworker数をメトリクスとして取得しようとした場合に増減が激しい

元記事を表示

【個人開発】GoでECSの定義ファイルを生成するアプリを作ってみた

# 概要
久しぶりに人様のための個人開発をしてみました。

AWS Fargateにデプロイする際、環境ごとに異なる値をECSのタスク定義に埋め込む必要がありますよね。最初はシェルスクリプトで環境変数を埋め込んでいたのですが、シェルって意外と繊細でエラーも出やすい。少し書き間違えただけで動かない…なんてことも多く、もっと簡単に管理できないかと考えた結果、ECSタスク定義ジェネレーターをGoで作ってみることにしました。

Goならシェルスクリプトよりも読みやすく、go installで簡単にインストールして使うことができます。Go CLIアプリとして、このツールを導入することで、効率的で安定したタスク定義の生成が可能になりました。

# 作ったもの
https://github.com/rendaman0215/ECSBuilder

## 使い方
– 必要なファイルの用意
– タスク定義のテンプレートファイル
– .envファイル
– インストール
– “`go
go install github.com/rendaman0215/ECSbuilder

元記事を表示

パ行で会話するための変換プログラムを作成

# 概要

Go言語を勉強しようと思い、簡易的なプログラムを作って学習を進めたいと思います。

今回のテーマは、パ行だけで会話したいので、そのための文章を変換するプログラムを作成したいと考えています。具体的には、以下のような変換するプログラムを作成します。

例:**聞こえる 波の音が** → **ぴぽぺぷ ぱぴぽぽぽぱ**

母音がaだったら、「**ぽ**」。母音がiだったら、「**ぴ**」に変換されます。
(マリンエンジェモン語と呼んでます。例は歌詞の一部です。検索してみてね。)

# プログラム

6つの処理を作成し実装しました。
もっと良い方法や間違っているところがあればご指摘ください。

## 1. ひらがなに変換

**お寿司を食べる** → **おすしをたべる**

ひらがなに変換するには、外部のライブラリが必要なので、今回は長くなってしまうため、機械があれば次回以降の記事に書きたいと思いまう。

## 2. 文字列を分割
**おすしをたべる** → **[“お”, “す”, “し”, “を”, “た”, “べ”, “る”]**

Go言語では、配列より動的にサイズ

元記事を表示

【Go】スライスにおけるappendのキャパシティ依存の挙動と解決策

# はじめに
* Goのスライスは動的な配列として利用でき、要素数が固定されていないため、柔軟に扱えます
* ただし、`append`を使用して要素を追加する際には、スライスのキャパシティがどのように影響するかを理解しておく必要があります
* 本記事では、`append`の動作がスライスのキャパシティによってどのように変わるかを解説し、そのキャパシティ依存の問題を回避する方法の一つとしてフルスライス式を紹介します

:::note warn
本記事で話さないこと
本記事では挙動の違いについて理解することを重視するため、スライスの内部構造や、ポインタ、Goランタイムの正確な挙動については説明を省略します。

より詳細に知りたい方は、[3. 関数と型 – 3.1. 型 – Gopher道場 -](https://www.youtube.com/watch?v=q92KKz5RsnA)をご覧ください。スライスについては29:47〜、`append`については44:45〜から解説されています。
:::

# appendの基本的な動作

まず、`append`の基本的な使い方を見てみましょう。

元記事を表示

Go(Gin)でのDocker環境構築

# はじめに
今Goのボイラーテンプレートを作っています。マイクロサービスが活発になっているので、
それに伴って作っています。その手始めにDockerの環境構築をしました。

# GoのDocker Image(GinでのDockerの環境構築)
以下のサイトを参考にしてみました。

https://hub.docker.com/_/golang

# まずはGo(Gin)の導入
– Goのインストール
[Goの公式サイト]
https://golang.org/dl/からインストーラーをダウンロードしてインストール。

インストール後、以下のコマンドでGoのバージョンを確認
“`
go version
“`

– プロジェクトのディレクトリを作成
“`
mkdir my-gin-app
cd my-gin-app
“`
– Goモジュールの初期化
“`
go mod init my-gin-app
“`
– Ginのインストール
“`
go get -u github.com/gin-gonic/gin
“`
– 基本的なアプリケーションの作成
“`main.go

元記事を表示

GoでAPIクライアント自動生成とモックを実装してみた

# 背景・目的
以前、Swagger UIをGitHub Actionsで公開しました。その際に利用した設定ファイルを使用してコードを自動生成し、

https://qiita.com/zumax/items/86b0ba27b6f4c06de65c

今回は、`oapi-codegen`について、特徴を整理し、動作を確認してみます。

https://github.com/oapi-codegen/oapi-codegen

また、`uber-go/mock`を使用してモックを生成して単体テストも試します。

https://github.com/uber-go/mock

# まとめ
下記に、特徴を整理します。

|特徴|説明|
|:–|:–|
|oapi-codegenとは|OpenAPI 仕様を Go コードに変換するためのコマンドライン ツールおよびライブラリ|
|oapi-codegenのメリット|OpenAPI 3.0に基づくサービスの作成や統合に必要な定型文を削減できる。
これにより、ビジネス ロジックの作成と、組織にとっての真の付加価値の創出に注力できる|

元記事を表示

ChatGPTを使って簡単なSPAを実装すると、どのくらい時間がかかるのか

# 1. はじめに
生成AIでアプリ開発する記事を見かけて、今更ながら生成AIによるコーディングに興味が湧きました。そこでChatGPTを使って簡単なTodoアプリの実装をすると、どのくらい時間がかかるのか、タイムアタックをしてみることにしました。FrontendはVue.js、BackendはGo、DatabaseはPostgreSQLで作成しました。

結論から言うと、大体5時間くらいで完成しました。完成品のクオリティを見て、「このクオリティに5時間かかったのか」と自分でも思う一方、不慣れなところが多く詰まりまくったにも関わらず5時間でできたことに驚いています。

完成品は[こちら](https://github.com/utibori-jp/simple-todo)のレポジトリにあげてるので、興味あれば是非。

# とりあえずやってみる

早速ChatGPTにお願いしていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769595/65bcc8a5-066b-651c-1f

元記事を表示

MacOSからDatadog APMを送る (with Datadog Agent)

## 概要

DatadogのTraceを、アプリのローカル実行で確認したいケースがある。
今回は、Mac上にDatadog Agentを立てて、Datadogにトレースを送るのを試す。

## インストール

https://app.datadoghq.com/account/settings/agent/latest?platform=macos から Agentの設定をしていきます。

![Screenshot 2024-10-26 at 9.10.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7059/dffb566e-2ebc-3122-980a-7e5ea3c93979.png)

DD_API_KEYを取得してから、以下のコマンドでインストールすることができます。

“`
DD_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX DD_SITE=”datadoghq.com” bash -c “$(curl -L https://install.da

元記事を表示

Go言語とJavaScriptで数値を人にやさしく表示する方法

# はじめに

Go言語とJavaScriptで開発するプログラムから数値を表示する時、人にやさしく表示するためのパッケージをの紹介です。バイト数をMBやGBにしたり、大きな数値をカンマ区切りで表示するためのものです。
82854982Bytesより82MBのほうが直感的にわかりやすいです。
6582491という数値よりも、6,582,491のほうがわかりやすいというものです。

# Go言語のパッケージ

Go言語は、go-humanize

https://github.com/dustin/go-humanize

です。

サンプルプログラムは

“`go
package main

import (
“fmt”
“time”

“github.com/dustin/go-humanize”
“github.com/dustin/go-humanize/english”
)

func main() {
// バイト数
fmt.Printf(“That file is %s.\n”, humanize.Bytes(82854982)) // That file i

元記事を表示

[Go]Genericsを使ってWebアプリの共通処理をまとめて行う

最近、[Fiber](https://gofiber.io/)というWeb Application FrameworkでWebアプリを作っていますが、そこでGenericsを使ってWebリクエストを処理する「お約束」みたいな共通処理をまとめてやっています。

Fiberじゃなくても使えると思いますが、Fiberを例にしています。なお、Fiberは現在v3がベータ版ですが、以下はv2のコードです。

## リクエストごとに型を作る

最初にリクエストごとの型を作ります。

“`go
type TestGetApiReq struct {
Name string `json:”name” query:”name”`
}

type TestPostApiReq struct {
Country string `json:”country”`
}
“`

GETのほうは、QUERY_STRINGとして渡されることを想定しています(`json:”name”`は、レスポンスに使うためなので、普通は不要です)。POSTの方は、RequestBodyにJSONがくる想定です。
Fiberでは

元記事を表示

勉強会に参加してみたらエンジニアの尊さを感じた話 ~ Go Connect ~

株式会社Schoo 新卒1年目の [@hiroto_0411](https://x.com/hiroto_0411)です!
今回は、Go Connectという「Go言語の勉強と交流」を目的とした勉強会に参加してきたので、そのレポートを書いてみました。
一方的に「学ぶ」だけでなく、「交流」を通して「学ぶ」ことができる勉強会の設計になっていて、 **他者との交流を通して学び合うエンジニアコミュニティの文化って尊いなぁと感じることができる勉強会でした** 🫶

企画・運営してくださった方々、会場を提供してくださった株式会社LayerXさんありがとうございました!

https://gotalk.connpass.com/event/331992/

## この記事でわかること
– この勉強会でどんなことしたの?
– エンジニアの「学び合う」文化って尊いよね

## おすすめされていた本
勉強会が始まる前に1人ずつ自己紹介する時間があり、そこでは毎回自己紹介のテーマを決めているらしいのですが、今回は「おすすめの書籍を紹介する」というテーマでした。自己紹介からも「学び」を得ることができて素敵

元記事を表示

Go の 型が interface を満たすことを保証する

# 型を満たすことが保証されていない場合

例えば以下のような実装があるとします。

“`main.go
package main

func main() {}
“`

“`tasks.go
package main

type Tasks interface {
Create(task string)
Get(id int)
Update(id int, task string)
Delete(id int)
}
“`

ここで定義した `Tasks` interface を `Update(id int, task string)` メソッドを除いて満たすように実装します。

“`tasks_impl.go
package main

type TasksImpl struct{}

func (t TasksImpl) Create(task string) {
//TODO implement me
panic(“implement me”)
}

func (t TasksImpl) Get(id int) {
//TODO implement me

元記事を表示

Goのtime.AddDate()で月加算がズレる件の対処方法

## 概要

time.AddDate()で月末の月加算がずれることに気づいた際のメモ

下記の記事がとても参考になりました

[https://tech.mirrativ.stream/entry/2023/10/31/120000](https://tech.mirrativ.stream/entry/2023/10/31/120000)

## 問題点

– time.AddDate()で月末の月加算がずれる
– 12月末 + 2ヶ月 = 2月末としたいが、3/2や3/3となる

“`go
func main() {
start := time.Date(2023, 12, 31, 0, 0, 0, 0, time.UTC)
twoMonthLater := start.AddDate(0, 2, 0)

fmt.Println(twoMonthLater)
}

// 出力: 2024-03-02 00:00:00 +0000 UTC
“`

## 解決方法

– 独自に月を加算する関数を作成

“`go
// AddMonthsPreservingE

元記事を表示

OTHERカテゴリの最新記事