Go言語でカスタムエラー型を活用したエラーカテゴリの管理方法

Go言語におけるエラーハンドリングは、信頼性の高いソフトウェアを構築するうえで欠かせない要素です。特に、大規模なプロジェクトや複雑なシステムでは、エラーが多様なカテゴリに分類されるため、適切な管理が求められます。本記事では、Goの強力な特徴であるカスタムエラー型を活用し、エラーを論理的に分類・管理する方法について詳しく解説します。この手法を学ぶことで、コードの可読性を向上させるだけでなく、エラーの原因特定や修正が効率化され、開発の質を大幅に高めることができます。

目次

エラーハンドリングの基礎知識


エラーハンドリングとは、プログラム内で発生するエラーを検出し、適切に処理する仕組みを指します。Go言語では、エラーハンドリングが言語仕様に組み込まれており、エラーは通常の値として扱われます。この設計により、エラーの存在を明示的にチェックすることが推奨されています。

Go言語のエラーハンドリングの基本


Go言語では、標準ライブラリに定義されたerrorインターフェースを用いてエラーを扱います。このインターフェースは単一のメソッドError() stringを持ち、エラーメッセージを文字列として返します。

type error interface {
    Error() string
}

一般的なエラーハンドリングのパターン


Goでは、関数がエラーを返す場合、通常は戻り値としてエラーオブジェクトを返します。以下のようなコードが一般的です。

func doSomething() error {
    if someCondition {
        return errors.New("an error occurred")
    }
    return nil
}

func main() {
    err := doSomething()
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Operation successful")
    }
}

エラーハンドリングの特徴

  1. 明示的なエラーチェック: エラーが戻り値として返されるため、処理の成否を簡単に判定できます。
  2. 軽量な設計: 特別な構文や例外処理のメカニズムを必要とせず、シンプルなコードを保てます。
  3. エラーチェックの忘れ防止: Goでは未使用の変数がコンパイルエラーとなるため、エラーを無視することが困難です。

このような特徴を理解したうえで、Go言語ならではのカスタムエラー型を用いたエラー管理手法に進む準備を整えます。

カスタムエラー型の概要


Go言語におけるカスタムエラー型は、特定のエラー状況を表現するために独自のエラーストラクチャを定義する方法です。これにより、エラーをより詳細に表現し、効率的に分類・管理できます。

カスタムエラー型の利点

  1. 明確なエラー分類: 異なるエラーの種類を区別するために役立ちます。
  2. 情報の追加: 標準のerror型では提供できない詳細なエラー情報を含めることができます。
  3. コードの可読性向上: エラー内容を明確にすることで、デバッグやロジックの把握が容易になります。

カスタムエラー型が必要な場面

  • 複数のエラー原因が存在する場合: エラーを具体的に区別する必要がある場合に適しています。
  • エラー情報を拡張したい場合: エラーメッセージに加え、追加のデータを含めたい場合に役立ちます。
  • エラーに応じた特定の処理が必要な場合: エラーの種類に応じて異なる処理を行う場合に便利です。

カスタムエラー型の基本的な概念


Go言語では、任意の型にError()メソッドを実装することで、その型をerrorインターフェースとして扱うことができます。以下は基本的な例です。

type MyError struct {
    Code    int
    Message string
}

func (e MyError) Error() string {
    return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}

このように、カスタムエラー型を定義することで、エラー内容を詳細に管理できるようになります。次のセクションでは、このカスタムエラー型を具体的に実装する手順を紹介します。

Goでのカスタムエラー型の定義方法


カスタムエラー型を使用することで、特定のエラーに関連する情報を柔軟に扱うことができます。Goでは、任意の構造体や型にError()メソッドを実装することで、その型をエラーとして利用できます。

基本的なカスタムエラー型の定義


以下は、カスタムエラー型を定義する基本的な例です。

package main

import (
    "fmt"
)

type MyError struct {
    Code    int
    Message string
}

// Error メソッドを実装して error インターフェースを満たす
func (e MyError) Error() string {
    return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}

func main() {
    err := MyError{Code: 404, Message: "Resource not found"}
    fmt.Println(err)
}

このコードでは、MyError型にError()メソッドを実装し、errorインターフェースを満たすことで、独自のエラー型を作成しています。

構造体を使った詳細なエラー情報の追加


カスタムエラー型にフィールドを追加することで、エラーに関する詳細情報を含めることができます。

type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("Validation error on field '%s': %s", e.Field, e.Message)
}

func validateField(value string) error {
    if value == "" {
        return ValidationError{Field: "username", Message: "cannot be empty"}
    }
    return nil
}

エラー型の比較


カスタムエラー型を定義すると、特定のエラー型を直接比較することが可能になります。これにより、エラーの種類に応じた分岐処理を簡単に行えます。

func main() {
    err := validateField("")
    if err != nil {
        if vErr, ok := err.(ValidationError); ok {
            fmt.Printf("Field: %s, Problem: %s\n", vErr.Field, vErr.Message)
        } else {
            fmt.Println("An unknown error occurred")
        }
    }
}

ポイント

  1. Error()メソッドは必須: エラー型として機能するには、必ずError()メソッドを実装する必要があります。
  2. カスタムエラー型の利用は、エラーの詳細な分類や情報拡張を可能にします。
  3. 型アサーションを使用することで、エラーの種類を特定して適切な処理を実現できます。

これで、カスタムエラー型を用いて独自のエラーハンドリングを行うための基礎が整いました。次のセクションでは、これを活用してエラーカテゴリを分割する方法を紹介します。

カスタムエラー型を使ったエラーカテゴリの分割


大規模なシステムでは、エラーをカテゴリごとに分割して管理することが重要です。カスタムエラー型を活用すれば、エラーの種類を論理的に分類し、コードの可読性や保守性を向上させることができます。

エラーカテゴリの分割の利点

  1. エラーの識別が容易になる: 異なるエラーを型で区別することで、特定のエラーを迅速に特定できます。
  2. 再利用性の向上: カテゴリごとにエラー型を設計することで、異なるモジュール間で一貫性を保てます。
  3. デバッグ効率の向上: エラーカテゴリを明確にすることで、トラブルシューティングが効率化されます。

エラーカテゴリの具体例


以下に、カスタムエラー型を利用してエラーカテゴリを分割する例を示します。

package main

import (
    "fmt"
)

// データベース関連エラー
type DatabaseError struct {
    Query   string
    Message string
}

func (e DatabaseError) Error() string {
    return fmt.Sprintf("DatabaseError: query '%s' failed with message: %s", e.Query, e.Message)
}

// バリデーション関連エラー
type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("ValidationError: field '%s' is invalid: %s", e.Field, e.Message)
}

// ネットワーク関連エラー
type NetworkError struct {
    URL     string
    Message string
}

func (e NetworkError) Error() string {
    return fmt.Sprintf("NetworkError: failed to reach URL '%s': %s", e.URL, e.Message)
}

カテゴリごとのエラーハンドリング


各エラーカテゴリに応じた処理を行う方法を示します。

func handleError(err error) {
    switch e := err.(type) {
    case DatabaseError:
        fmt.Printf("Handle Database Error: %s\n", e)
    case ValidationError:
        fmt.Printf("Handle Validation Error: %s\n", e)
    case NetworkError:
        fmt.Printf("Handle Network Error: %s\n", e)
    default:
        fmt.Printf("Unknown error: %s\n", err)
    }
}

func main() {
    dbErr := DatabaseError{Query: "SELECT * FROM users", Message: "connection timed out"}
    valErr := ValidationError{Field: "email", Message: "invalid format"}
    netErr := NetworkError{URL: "https://example.com", Message: "connection refused"}

    handleError(dbErr)
    handleError(valErr)
    handleError(netErr)
}

ベストプラクティス

  1. 用途ごとにカスタムエラー型を設計: データベース、バリデーション、ネットワークなど、用途ごとに分割します。
  2. 一貫した命名規則を使用: エラー型に一貫した命名規則を用いることで、コードの可読性を向上させます。
  3. エラー型のドキュメント化: 各エラー型の目的と使用方法を明記しておくと、チーム開発で役立ちます。

これにより、システム全体でエラーを整理し、より効率的なエラーハンドリングを実現できます。次のセクションでは、具体的な実装例としてAPIエラーの管理方法を紹介します。

実装例:APIエラーの管理


カスタムエラー型を活用することで、APIから発生するエラーを効果的に管理できます。このセクションでは、APIエラーをカテゴリ化し、適切に処理するための具体的な実装例を紹介します。

APIエラーの構造


APIエラーは、HTTPステータスコード、エラーメッセージ、追加情報などを含むことが一般的です。以下は、APIエラー用のカスタムエラー型を定義した例です。

package main

import (
    "fmt"
)

// APIエラーのカスタム型
type APIError struct {
    StatusCode int
    Endpoint   string
    Message    string
}

// Error メソッドを実装
func (e APIError) Error() string {
    return fmt.Sprintf("APIError: [%d] %s - %s", e.StatusCode, e.Endpoint, e.Message)
}

この定義により、APIエラーの詳細な情報を管理できます。

APIエラーの発生と処理


次に、APIエラーを発生させ、適切に処理する例を示します。

func fetchAPIData(endpoint string) error {
    // ダミーデータとしてエラーを発生
    return APIError{
        StatusCode: 404,
        Endpoint:   endpoint,
        Message:    "Resource not found",
    }
}

func main() {
    endpoint := "/users/123"
    err := fetchAPIData(endpoint)
    if err != nil {
        // エラーの種類に応じた処理
        if apiErr, ok := err.(APIError); ok {
            fmt.Printf("Failed to fetch data from %s. Status: %d, Message: %s\n",
                apiErr.Endpoint, apiErr.StatusCode, apiErr.Message)
        } else {
            fmt.Println("An unexpected error occurred:", err)
        }
    }
}

高度な処理:HTTPステータスに基づく分岐


HTTPステータスコードを基にエラー処理をカスタマイズできます。

func handleAPIError(err APIError) {
    switch err.StatusCode {
    case 400:
        fmt.Println("Bad Request:", err.Message)
    case 401:
        fmt.Println("Unauthorized:", err.Message)
    case 404:
        fmt.Println("Not Found:", err.Message)
    case 500:
        fmt.Println("Internal Server Error:", err.Message)
    default:
        fmt.Println("Unexpected API error:", err.Message)
    }
}

func main() {
    err := APIError{
        StatusCode: 404,
        Endpoint:   "/products/999",
        Message:    "Product not found",
    }
    handleAPIError(err)
}

エラー管理の拡張例


APIエラーをさらに効率的に管理するため、ログ記録やリトライ機能を追加することも可能です。

func retryAPIRequest(err APIError, retryCount int) {
    fmt.Printf("Retrying request to %s (%d attempts remaining)...\n", err.Endpoint, retryCount)
    // 実際のリトライロジックはここに実装
}

func main() {
    err := APIError{
        StatusCode: 500,
        Endpoint:   "/orders",
        Message:    "Server error",
    }

    if err.StatusCode == 500 {
        retryAPIRequest(err, 3)
    }
}

ベストプラクティス

  1. エラー情報の明確化: ステータスコードやエンドポイントなど、必要な情報を含めます。
  2. 汎用的なエラーハンドリング: 型アサーションやスイッチ文を用いて柔軟な処理を実現します。
  3. リトライやロギングの実装: 必要に応じてエラーハンドリングを拡張し、信頼性を向上させます。

このようにカスタムエラー型を用いることで、APIエラーを効果的に管理し、堅牢なシステムを構築できます。次のセクションでは、エラーメッセージのフォーマットと整備について解説します。

エラーメッセージのフォーマットと整備


エラーメッセージは、システムの状態を正確に伝える重要な手段です。一貫性があり理解しやすいエラーメッセージを設計することで、デバッグ効率が向上し、ユーザーエクスペリエンスも向上します。

エラーメッセージ整備の重要性

  1. 迅速な問題特定: メッセージが詳細で一貫性があると、エラーの原因を迅速に特定できます。
  2. 開発者間のコミュニケーション向上: チーム内で一貫した形式を採用することで、エラー内容の共有がスムーズになります。
  3. ログ解析の効率化: 一貫性があると、自動化されたログ解析やモニタリングツールでの処理が容易になります。

エラーメッセージのフォーマット設計


エラーメッセージを設計する際には、以下のような基本フォーマットを採用することが推奨されます。

[エラー種別] (追加情報): 詳細メッセージ

  • [ValidationError] (field: username): cannot be empty
  • [DatabaseError] (query: SELECT * FROM users): connection timed out
  • [APIError] (endpoint: /users/123): resource not found

Goでの実装例


カスタムエラー型にフォーマット済みのメッセージを含める例を示します。

package main

import (
    "fmt"
)

// カスタムエラー型
type FormattedError struct {
    ErrorType string
    Context   string
    Message   string
}

// Error メソッドの実装
func (e FormattedError) Error() string {
    return fmt.Sprintf("[%s] (%s): %s", e.ErrorType, e.Context, e.Message)
}

// エラー発生関数
func generateError() error {
    return FormattedError{
        ErrorType: "ValidationError",
        Context:   "field: email",
        Message:   "must be a valid email address",
    }
}

func main() {
    err := generateError()
    fmt.Println(err)
}

エラーメッセージの一貫性を保つ方法

  1. テンプレートの活用: 汎用的なフォーマットをテンプレート化し、全体で共通の形式を使用します。
  2. エラーメッセージ管理用関数: フォーマット済みのメッセージを生成する専用関数を用意します。
func formatError(errorType, context, message string) string {
    return fmt.Sprintf("[%s] (%s): %s", errorType, context, message)
}

func main() {
    errMsg := formatError("DatabaseError", "query: SELECT * FROM products", "connection timed out")
    fmt.Println(errMsg)
}

エラーメッセージ設計のベストプラクティス

  1. 簡潔さと具体性: メッセージは簡潔でありつつ、原因や影響を具体的に記述します。
  2. 一貫した用語の使用: チーム内で定義された用語を統一して使用します。
  3. エラーコードの導入: 必要に応じてエラーコードを追加し、より直感的なデバッグを可能にします。

エラーメッセージの拡張例


JSON形式でエラーメッセージを整備することで、ログやAPIレスポンスでの利用を簡易化できます。

type JSONError struct {
    ErrorType string `json:"errorType"`
    Context   string `json:"context"`
    Message   string `json:"message"`
}

func main() {
    err := JSONError{
        ErrorType: "APIError",
        Context:   "endpoint: /users/123",
        Message:   "resource not found",
    }
    fmt.Printf("Error: %+v\n", err)
}

これにより、エラーメッセージを構造化して扱いやすくすることが可能になります。次のセクションでは、分類したエラーをロギングに活用する方法を解説します。

エラー分類を活用したエラーロギング


エラーロギングは、システムの健全性を保ち、問題発生時に迅速に対応するために重要な要素です。エラーをカテゴリごとに分類し、一貫したロギングを行うことで、分析やデバッグの効率を大幅に向上させることができます。

エラーロギングの目的

  1. 問題の特定: 発生したエラーを記録して、原因を迅速に特定します。
  2. 統計的分析: 特定のエラーが頻発するパターンを把握し、改善ポイントを明確にします。
  3. トラブルシューティング: 詳細なエラー情報を残すことで、後からデバッグが容易になります。

Goでのエラーロギングの基本


Goでは、標準ライブラリのlogパッケージを使用してロギングを行うことができます。

import (
    "log"
)

// 基本的なログ記録
func main() {
    err := simulateError()
    if err != nil {
        log.Println(err)
    }
}

func simulateError() error {
    return fmt.Errorf("an example error occurred")
}

エラー分類を活用したロギング


カスタムエラー型を活用して、エラーを分類したうえで適切なロギングを行います。

package main

import (
    "fmt"
    "log"
)

// カスタムエラー型
type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("[ValidationError] Field '%s': %s", e.Field, e.Message)
}

type DatabaseError struct {
    Query   string
    Message string
}

func (e DatabaseError) Error() string {
    return fmt.Sprintf("[DatabaseError] Query '%s': %s", e.Query, e.Message)
}

// ロギング処理
func logError(err error) {
    switch e := err.(type) {
    case ValidationError:
        log.Printf("Validation issue: %s\n", e)
    case DatabaseError:
        log.Printf("Database failure: %s\n", e)
    default:
        log.Printf("General error: %s\n", err)
    }
}

func main() {
    valErr := ValidationError{Field: "username", Message: "cannot be empty"}
    dbErr := DatabaseError{Query: "SELECT * FROM users", Message: "connection timed out"}

    logError(valErr)
    logError(dbErr)
}

高度なエラーロギングの実現


ログレベルを導入して、エラーの重要度に応じた記録を行います。

import (
    "log"
    "os"
)

func init() {
    log.SetOutput(os.Stdout) // ログを標準出力に設定
    log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

func logErrorWithLevel(err error, level string) {
    log.Printf("[%s] %s\n", level, err)
}

func main() {
    err := fmt.Errorf("critical system failure")
    logErrorWithLevel(err, "CRITICAL")
}

クラウドロギングや外部ツールとの連携


クラウドサービスや外部ツール(例: AWS CloudWatch, ELKスタック)を活用して、エラーログをリアルタイムで監視・解析する仕組みを構築することも可能です。

エラーロギングのベストプラクティス

  1. 詳細情報を記録: エラーの発生箇所、発生時刻、詳細なメッセージを含める。
  2. ログフォーマットの統一: 一貫した形式でログを出力し、分析を容易にする。
  3. ログレベルの導入: DEBUG、INFO、WARNING、ERROR、CRITICALなどのレベルを設定する。
  4. 監視とアラート: ログを監視して異常を検知した際にアラートを発生させる。

エラー分類とロギングを組み合わせることで、システムの信頼性と運用効率が大幅に向上します。次のセクションでは、エラーカテゴリを動的に管理する方法について解説します。

応用編:エラーカテゴリの動的管理


エラーカテゴリを動的に管理することで、柔軟性と拡張性の高いエラーハンドリングが実現できます。特に、エラーの種類や内容が多様化する大規模システムでは、このアプローチが役立ちます。

エラーカテゴリの動的管理とは


エラーカテゴリの動的管理では、あらかじめ定義されたカテゴリに加え、実行時にカテゴリを追加・変更できる仕組みを構築します。これにより、新しいエラーカテゴリや条件に対応しやすくなります。

動的エラーカテゴリの基本設計


動的にエラーカテゴリを管理するには、エラー情報をマップや構造体で管理し、必要に応じて拡張可能にします。

package main

import (
    "fmt"
    "sync"
)

// エラーカテゴリ管理構造体
type ErrorRegistry struct {
    categories map[string]string
    mu         sync.Mutex
}

// 新しいエラーカテゴリを追加
func (er *ErrorRegistry) AddCategory(code, description string) {
    er.mu.Lock()
    defer er.mu.Unlock()
    er.categories[code] = description
}

// エラーカテゴリを取得
func (er *ErrorRegistry) GetCategory(code string) string {
    er.mu.Lock()
    defer er.mu.Unlock()
    if desc, exists := er.categories[code]; exists {
        return desc
    }
    return "Unknown category"
}

// 初期化関数
func NewErrorRegistry() *ErrorRegistry {
    return &ErrorRegistry{
        categories: make(map[string]string),
    }
}

エラーカテゴリの動的管理の利用例


動的にカテゴリを追加し、エラー処理に活用します。

func main() {
    // エラーカテゴリ管理のインスタンスを作成
    registry := NewErrorRegistry()

    // カテゴリを動的に追加
    registry.AddCategory("404", "Resource Not Found")
    registry.AddCategory("500", "Internal Server Error")

    // エラーを動的に管理
    errorCode := "404"
    fmt.Printf("Error Code: %s, Description: %s\n", errorCode, registry.GetCategory(errorCode))

    errorCode = "401"
    fmt.Printf("Error Code: %s, Description: %s\n", errorCode, registry.GetCategory(errorCode))
}

動的エラーカテゴリの拡張例


さらに、エラーカテゴリを外部データ(例: JSONファイル、データベース)から読み込むように拡張することも可能です。

import (
    "encoding/json"
    "os"
)

func loadCategoriesFromFile(filename string, registry *ErrorRegistry) error {
    file, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer file.Close()

    decoder := json.NewDecoder(file)
    categories := make(map[string]string)
    if err := decoder.Decode(&categories); err != nil {
        return err
    }

    for code, description := range categories {
        registry.AddCategory(code, description)
    }
    return nil
}

func main() {
    registry := NewErrorRegistry()

    // JSONファイルからカテゴリを読み込む
    if err := loadCategoriesFromFile("categories.json", registry); err != nil {
        fmt.Println("Error loading categories:", err)
        return
    }

    // カテゴリを利用
    fmt.Println(registry.GetCategory("404"))
}

ベストプラクティス

  1. スレッドセーフな設計: 複数のゴルーチンでエラーカテゴリを操作する場合、sync.Mutexなどを利用して安全性を確保します。
  2. 外部リソースとの連携: JSONやデータベースを活用して、カテゴリの定義を動的に変更可能にします。
  3. エラーカテゴリの標準化: 動的な管理を行う場合でも、カテゴリの命名規則や構造を統一しておきます。

動的管理を導入することで、システムの拡張性が向上し、柔軟なエラーハンドリングが可能になります。次のセクションでは、学んだ内容を実践的に活用するための演習問題を提示します。

演習問題:カスタムエラー型の実装


これまで学んだ内容を実践するために、以下の演習問題に取り組んでみましょう。これらの課題は、カスタムエラー型の設計、エラーカテゴリの分割、動的管理の実装を深く理解するのに役立ちます。

問題1: 基本的なカスタムエラー型の作成


次の要件を満たすカスタムエラー型を作成してください。

  • エラー名: PermissionError
  • フィールド: User (エラーが発生したユーザー)、Action (許可されていない操作)
  • Error()メソッドで次のフォーマットのエラーメッセージを返す:
    [PermissionError] User 'JohnDoe' is not allowed to perform 'Delete'.

解答例

type PermissionError struct {
    User   string
    Action string
}

func (e PermissionError) Error() string {
    return fmt.Sprintf("[PermissionError] User '%s' is not allowed to perform '%s'.", e.User, e.Action)
}

問題2: エラーカテゴリごとの処理


以下のカスタムエラー型を利用して、エラーカテゴリに応じた処理を行うプログラムを作成してください。

  • ValidationError: 入力のバリデーションに失敗したエラー
  • DatabaseError: データベース操作に失敗したエラー
  • その他のエラーは「Unknown error」として処理する。

ヒント

  • 型アサーションを使ってエラー型を判別する。

問題3: 動的エラーカテゴリの管理


以下の要件を満たすプログラムを作成してください。

  1. エラーカテゴリを登録・取得できる構造体ErrorRegistryを作成する。
  2. 以下のエラーカテゴリを事前に登録する:
  • 400: “Bad Request”
  • 404: “Not Found”
  • 500: “Internal Server Error”
  1. ユーザーからエラーコードを入力させ、該当するカテゴリを表示するプログラムを実装する。

ヒント

  • mapを利用してカテゴリを管理します。
  • ユーザー入力にはfmt.Scanln()を使用します。

問題4: 応用 – JSON形式でのエラーロギング


以下の要件を満たすプログラムを作成してください。

  1. カスタムエラー型APIErrorを作成し、JSON形式でエラーをロギングする。
  2. ログのフォーマットは以下のようにする:
   {
       "type": "APIError",
       "endpoint": "/users/123",
       "status": 404,
       "message": "Resource not found"
   }

ヒント

  • encoding/jsonパッケージを使用してJSONを生成します。

課題の実施と振り返り


これらの問題を解くことで、カスタムエラー型の設計・運用、動的エラーカテゴリの管理、およびエラーのフォーマットとロギングの実装が理解できるようになります。コードを実行して動作を確認し、必要に応じてエラーメッセージの改善や機能拡張を検討してみてください。

まとめ


本記事では、Go言語におけるカスタムエラー型を活用したエラーカテゴリの分割と管理について解説しました。エラーハンドリングの基本から始まり、カスタムエラー型の設計、エラーカテゴリの動的管理、ロギングの実装まで、具体例を交えて紹介しました。

適切なエラーハンドリングは、コードの可読性と保守性を高め、デバッグ効率を向上させます。また、エラーカテゴリを明確に分割することで、エラー処理を一貫性のあるものにし、システム全体の信頼性を向上させることが可能です。学んだ内容をもとに、さらに実践的なエラーハンドリングを設計してみてください。

コメント

コメントする

目次