2025/11/16
Contents Do not write comments that merely restate the code (e.g., int a // declare integer a).
(コードを単に言い換えるだけのコメントを書かない(例:int a // 整数aを宣言))
解説 コードをそのまま言い換えただけのコメントは、情報を追加せず、コードのノイズとなります。コメントは、コードから読み取れない意図や理由、背景を説明するべきです。自明な内容をコメントで繰り返すことは時間の無駄であり、コメントのメンテナンスコストを不必要に増加させます。意味のあるコメントのみを書くことで、コードの可読性が向上します。
具体例 // 悪い例(自明な内容の繰り返し)
// increment i by 1
i ++
// create a new user
user := User {}
// check if name is empty
if name == "" {
return errors .New ("name is required" )
}
// loop through all items
for _ , item := range items {
// process item
process (item )
}
// 良い例(意図や理由を説明)
// ユーザーIDは1から開始(0は予約済み)
i := 1
// デフォルト値で初期化(後でAPIレスポンスで上書き)
user := User {Status : "pending" }
// 空の名前は無効(ビジネスルール)
if name == "" {
return errors .New ("name is required" )
}
// すべてのアイテムに対して在庫を減算
// エラーが発生してもロールバックしない(べき等性保証)
for _ , item := range items {
process (item )
}
// コメント不要な例(コード自体が明確)
func calculateTax (price float64 ) float64 {
return price * 0.1
}
if user .IsActive () {
sendNotification (user )
}
参考リンク core
coding-standard
2025/11/16
Contents Do not swallow errors.
(エラーを握りつぶさない)
解説 エラーを無視したり握りつぶしたりすると、問題の発生源を特定できず、デバッグが著しく困難になります。エラーは適切にログに記録するか、呼び出し元に返すべきです。エラーを無視することは、システムの健全性を監視できなくなり、予期しない動作やデータ破損につながる可能性があります。すべてのエラーは、少なくともログ記録または上位層への伝播のいずれかで処理されるべきです。
具体例 // 悪い例(エラーを握りつぶす)
func ProcessData () {
data , err := fetchData ()
if err != nil {
// エラーを無視
}
_ = saveData (data ) // エラーを無視
}
func SendEmail (to string ) {
err := emailClient .Send (to , "Hello" )
// errをチェックせずに無視
}
// 良い例(適切なエラー処理)
func ProcessData () error {
data , err := fetchData ()
if err != nil {
return fmt .Errorf ("failed to fetch data: %w" , err )
}
if err := saveData (data ); err != nil {
return fmt .Errorf ("failed to save data: %w" , err )
}
return nil
}
func SendEmail (to string ) error {
if err := emailClient .Send (to , "Hello" ); err != nil {
return fmt .Errorf ("failed to send email to %s: %w" , to , err )
}
return nil
}
// ログ記録する場合
func BackgroundTask () {
if err := doSomething (); err != nil {
log .Printf ("background task failed: %v" , err )
// 呼び出し元に返せない場合はログに記録
}
}
参考リンク core
coding-standard
2025/11/16
Contents Avoid hard-coding values. Place frequently changing values in configuration; rarely changing values may be declared as package-level constants.
(値をハードコーディングしない。頻繁に変わる値は設定に配置し、稀にしか変わらない値はパッケージレベルの定数として宣言してもよい)
解説 ハードコードされた値は、環境ごとの違いや将来的な変更に対応できず、コードの修正とデプロイを強制します。頻繁に変更される値は設定ファイルや環境変数に外部化し、変更時にコードの再コンパイルを不要にすべきです。定数として宣言すべき値と設定として外部化すべき値を適切に判断することで、保守性の高いコードベースが実現されます。
具体例 // 悪い例(ハードコーディング)
func ProcessPayment (amount float64 ) error {
tax := amount * 0.1 // 税率がハードコード
total := amount + tax
if total > 10000 { // 閾値がハードコード
return errors .New ("amount too large" )
}
apiURL := "https://api.payment.com/v1/charge" // URLがハードコード
return callAPI (apiURL , total )
}
// 良い例(定数と設定の適切な使用)
const (
TaxRate = 0.1 // 法律で定められた税率(稀に変更)
)
type PaymentConfig struct {
MaxAmount float64
APIBaseURL string
}
type PaymentService struct {
config PaymentConfig
}
func NewPaymentService (config PaymentConfig ) * PaymentService {
return & PaymentService {config : config }
}
func (s * PaymentService ) ProcessPayment (amount float64 ) error {
tax := amount * TaxRate
total := amount + tax
if total > s .config .MaxAmount {
return errors .New ("amount too large" )
}
apiURL := s .config .APIBaseURL + "/v1/charge"
return callAPI (apiURL , total )
}
参考リンク core
coding-standard
2025/11/16
Contents Instead of flag parameters that toggle behavior inside a function, split the function.
(関数内部で振る舞いを切り替えるフラグパラメータを使う代わりに、関数を分割する)
解説 フラグパラメータを持つ関数は、実質的に2つ以上の異なる処理を1つの関数に詰め込んでおり、単一責任原則に違反します。フラグによって振る舞いが変わる関数は、呼び出し側でフラグの意味を理解する必要があり、可読性が低下します。関数を分割することで、各関数の意図が明確になり、使用方法が直感的になります。これにより、コードの保守性と理解しやすさが向上します。
具体例 // 悪い例(フラグパラメータで振る舞いを変更)
func ProcessUser (user User , sendEmail bool ) error {
if err := validateUser (user ); err != nil {
return err
}
if err := saveUser (user ); err != nil {
return err
}
if sendEmail {
// メール送信処理
if err := sendWelcomeEmail (user .Email ); err != nil {
return err
}
}
return nil
}
func main () {
ProcessUser (newUser , true ) // trueは何を意味する?
ProcessUser (existingUser , false ) // falseは何を意味する?
}
// 良い例(関数を分割)
func RegisterNewUser (user User ) error {
if err := validateUser (user ); err != nil {
return err
}
if err := saveUser (user ); err != nil {
return err
}
if err := sendWelcomeEmail (user .Email ); err != nil {
return err
}
return nil
}
func UpdateExistingUser (user User ) error {
if err := validateUser (user ); err != nil {
return err
}
if err := saveUser (user ); err != nil {
return err
}
// メール送信なし
return nil
}
func main () {
RegisterNewUser (newUser ) // 意図が明確
UpdateExistingUser (existingUser ) // 意図が明確
}
参考リンク core
coding-standard
2025/11/16
Contents Use meaningful names for variables and functions (e.g., good: getUser() / bad: method1()).
(変数と関数には意味のある名前を使う(例: 良い getUser() / 悪い method1()))
解説 変数や関数に意味のある名前を付けることは、コードの可読性と保守性を高める基本原則です。名前から目的や役割が明確に伝わることで、他の開発者がコードを理解しやすくなります。抽象的な名前や番号付きの名前は、コードレビューやデバッグ時に混乱を招き、バグの温床となります。MUST項目として、すべての変数と関数に対して例外なく適用されるべきルールです。
具体例 // 悪い例
func method1 () User {
var a = "john@example.com"
var b = fetchData (a )
return b
}
// 良い例
func getUser () User {
userEmail := "john@example.com"
user := fetchUserByEmail (userEmail )
return user
}
参考リンク core
coding-standard
2025/11/16
Contents A function should have no more than five parameters. More than five suggests too many responsibilities or insufficient aggregation.
(関数のパラメータは5つ以内にすべき。5つを超える場合は、責任が多すぎるか、集約が不足していることを示す)
解説 パラメータが多い関数は、理解と使用が困難であり、単一責任原則に違反している可能性が高いです。パラメータが5つを超える場合、関連するパラメータをオブジェクトにまとめるか、関数の責任を分割すべきです。パラメータを集約することで、関連する値が明確になり、関数シグネチャがシンプルになります。これにより、コードの可読性と保守性が向上します。
具体例 // 悪い例(パラメータが多すぎる)
func CreateUser (
firstName string ,
lastName string ,
email string ,
phone string ,
address string ,
city string ,
zipCode string ,
country string ,
) error {
// パラメータの順序を覚えるのが困難
// ...
}
func main () {
CreateUser ("John" , "Doe" , "john@example.com" , "123-456" ,
"123 Main St" , "Tokyo" , "100-0001" , "Japan" )
}
// 良い例(パラメータをオブジェクトに集約)
type UserProfile struct {
FirstName string
LastName string
Email string
Phone string
}
type Address struct {
Street string
City string
ZipCode string
Country string
}
func CreateUser (profile UserProfile , address Address ) error {
// 関連するデータがグループ化され、理解しやすい
// ...
}
func main () {
profile := UserProfile {
FirstName : "John" ,
LastName : "Doe" ,
Email : "john@example.com" ,
Phone : "123-456" ,
}
address := Address {
Street : "123 Main St" ,
City : "Tokyo" ,
ZipCode : "100-0001" ,
Country : "Japan" ,
}
CreateUser (profile , address )
}
// さらに良い例(責任を分割)
func CreateUser (profile UserProfile ) (UserID , error ) {
// ユーザー作成のみに集中
// ...
}
func SetUserAddress (userID UserID , address Address ) error {
// 住所設定を別関数に分離
// ...
}
参考リンク core
coding-standard
2025/11/16
Contents Do not expose a function externally unless it truly needs to be called from outside. A public function must represent an external interface.
(外部から呼ばれる必要がない限り、関数を外部に公開しない。公開関数は外部インターフェースを表現する必要がある)
解説 関数の可視性を必要最小限に抑えることは、カプセル化の原則に基づく重要な設計です。不必要に公開された関数は、意図しない外部からの呼び出しを許し、内部実装の変更を困難にします。公開関数は契約として機能するため、変更時には後方互換性を考慮する必要があります。内部実装の詳細は非公開にすることで、リファクタリングの自由度が高まります。
具体例 // 悪い例
type UserService struct {
db Database
}
// 内部処理なのに公開されている
func (s * UserService ) ValidateUserInput (name string ) bool {
return len(name ) > 0
}
func (s * UserService ) CreateUser (name string ) error {
if s .ValidateUserInput (name ) {
return s .db .Insert (name )
}
return errors .New ("invalid input" )
}
// 良い例
type UserService struct {
db Database
}
// 内部処理は非公開
func (s * UserService ) validateUserInput (name string ) bool {
return len(name ) > 0
}
// 外部インターフェースのみ公開
func (s * UserService ) CreateUser (name string ) error {
if s .validateUserInput (name ) {
return s .db .Insert (name )
}
return errors .New ("invalid input" )
}
参考リンク core
coding-standard
2025/11/16
Contents Keep each function to 100 lines or fewer (logical lines; wrapped lines count as one).
(各関数は100行以内に収める(論理行;折り返された行は1行とカウント))
解説 長い関数は、複数の責任を持っている可能性が高く、理解とテストが困難です。100行を超える関数は、処理を小さな関数に分割することで、可読性と再利用性が向上します。短い関数は、単一の責任を持ち、名前から目的が明確になります。論理行でカウントするため、コメントや空行、折り返しは複数行とはみなされません。適切な粒度の関数は、バグの発見と修正を容易にします。
具体例 // 悪い例(長すぎる関数 - 200行以上)
func ProcessOrder (order Order ) error {
// バリデーション(30行)
if order .ID == "" {
return errors .New ("order ID is required" )
}
if order .CustomerID == "" {
return errors .New ("customer ID is required" )
}
// ... さらに20項目のバリデーション
// 在庫チェック(40行)
for _ , item := range order .Items {
stock , err := db .GetStock (item .ProductID )
if err != nil {
return err
}
// ... 複雑な在庫ロジック
}
// 価格計算(40行)
subtotal := 0.0
for _ , item := range order .Items {
subtotal += item .Price * float64(item .Quantity )
}
// ... 割引、税金、送料の計算
// 決済処理(40行)
// ... 決済ゲートウェイとの通信
// メール送信(30行)
// ... メール作成と送信
// データベース保存(20行)
// ... 複数テーブルへの保存
return nil
}
// 良い例(適切に分割された関数)
func ProcessOrder (order Order ) error {
if err := validateOrder (order ); err != nil {
return fmt .Errorf ("validation failed: %w" , err )
}
if err := checkInventory (order .Items ); err != nil {
return fmt .Errorf ("inventory check failed: %w" , err )
}
total , err := calculateOrderTotal (order )
if err != nil {
return fmt .Errorf ("calculation failed: %w" , err )
}
if err := processPayment (order .CustomerID , total ); err != nil {
return fmt .Errorf ("payment failed: %w" , err )
}
if err := saveOrder (order ); err != nil {
return fmt .Errorf ("save failed: %w" , err )
}
if err := sendConfirmationEmail (order ); err != nil {
log .Printf ("email failed: %v" , err )
// メール失敗は注文処理を失敗させない
}
return nil
}
// 各関数は単一の責任を持ち、100行以内
func validateOrder (order Order ) error {
if order .ID == "" {
return errors .New ("order ID is required" )
}
if order .CustomerID == "" {
return errors .New ("customer ID is required" )
}
// ... その他のバリデーション
return nil
}
func checkInventory (items []Item ) error {
for _ , item := range items {
if err := verifyStockAvailability (item ); err != nil {
return err
}
}
return nil
}
func calculateOrderTotal (order Order ) (float64 , error ) {
subtotal := calculateSubtotal (order .Items )
discount := calculateDiscount (order , subtotal )
tax := calculateTax (subtotal - discount )
shipping := calculateShipping (order )
return subtotal - discount + tax + shipping , nil
}
参考リンク core
coding-standard
2025/11/16
Contents Keep closely related data and behavior together in a class for high cohesion and clear separation of concerns. Conversely, do not split strongly related elements across separate functions.
(密接に関連するデータと振る舞いをクラスにまとめて高い凝集度と明確な関心の分離を実現する。逆に、強く関連する要素を別々の関数に分割しない)
解説 高い凝集度は、関連するデータと操作を1箇所にまとめることで実現されます。データとそれを操作する振る舞いが離れていると、変更時に複数箇所を修正する必要が生じ、整合性を保つことが困難になります。クラス(構造体)内で関連する要素を集約することで、コードの理解が容易になり、変更の影響範囲が明確になります。
具体例 // 悪い例
type User struct {
Name string
Email string
}
func validateUserEmail (email string ) bool {
return strings .Contains (email , "@" )
}
func formatUserName (name string ) string {
return strings .Title (name )
}
// 良い例
type User struct {
Name string
Email string
}
func (u * User ) ValidateEmail () bool {
return strings .Contains (u .Email , "@" )
}
func (u * User ) FormatName () string {
return strings .Title (u .Name )
}
参考リンク core
coding-standard
2025/11/16
Contents Implement every detail stated in the specification.
(仕様に記載されたすべての詳細を実装する)
解説 仕様書に記載された要件は、ステークホルダーとの合意事項であり、完全に実装される必要があります。仕様の一部を省略したり、勝手に変更したりすることは、期待される機能が提供されないことを意味し、プロジェクトの失敗につながります。不明点や実装困難な要件がある場合は、実装前にステークホルダーと協議し、仕様を明確にする必要があります。実装後は、仕様との整合性を確認するテストが必須です。
具体例 // 仕様:
// - ユーザー登録時にメールアドレスの形式を検証する
// - パスワードは8文字以上必要
// - 登録完了メールを送信する
// 悪い例(仕様の一部のみ実装)
func RegisterUser (email , password string ) error {
if !strings .Contains (email , "@" ) {
return errors .New ("invalid email" )
}
return saveUser (email , password )
// パスワード長チェック未実装
// メール送信未実装
}
// 良い例(仕様をすべて実装)
func RegisterUser (email , password string ) error {
if !strings .Contains (email , "@" ) {
return errors .New ("invalid email format" )
}
if len(password ) < 8 {
return errors .New ("password must be at least 8 characters" )
}
if err := saveUser (email , password ); err != nil {
return err
}
if err := sendWelcomeEmail (email ); err != nil {
log .Printf ("Failed to send email: %v" , err )
// メール送信失敗は登録処理を失敗させない
}
return nil
}
参考リンク core
coding-standard