DarkLogo

Golangでオニオンアーキテクチャを学ぶ

· ChatGPT Turbo

オニオンアーキテクチャとは

オニオンアーキテクチャは、アプリケーションを複数の層に分割して、それぞれの層が特定の役割を果たすようにするソフトウェアデザインパターンです。
このアーキテクチャによって、アプリケーションは柔軟性が高く、保守性が高く、テストがしやすくなります。

オニオンアーキテクチャは以下の3つの層に分割されます。

Domain層:ビジネスロジックが含まれる層です。ドメイン層は、アプリケーションの中心部であり、ビジネスルール、エンティティ、値オブジェクト、リポジトリインターフェースなどが含まれます。

Infrastructure層:データベース、外部API、ファイルなどのインフラストラクチャとの通信を担当する層です。データ永続化やデータアクセスなどの機能が含まれます。

Application層:ドメイン層とインフラストラクチャ層の仲介役となる層です。この層には、WebAPIやCLIなどのインターフェース層が含まれます。アプリケーションの起動、リクエストの受け付け、レスポンスの返却などが含まれます。

ディレクトリ構造

以下は、Golangでオニオンアーキテクチャを実装する場合のディレクトリ構造の例です。

myapp/
├── domain/
│   ├── entity/
│   │   ├── user.go
│   │   └── ...
│   ├── repository/
│   │   ├── user_repository.go
│   │   └── ...
│   ├── usecase/
│   │   ├── user_usecase.go
│   │   └── ...
│   └── service.go
├── infrastructure/
│   ├── persistence/
│   │   ├── user_persistence.go
│   │   └── ...
│   ├── webapi/
│   │   ├── router.go
│   │   └── ...
│   ├── config.go
│   └── database.go
├── application/
│   ├── service/
│   │   ├── user_service.go
│   │   └── ...
│   └── handler/
│       ├── user_handler.go
│       └── ...
├── main.go
└── README.md
  1. domain/ディレクトリ:ビジネスロジックが含まれる層です。
  • entity/ディレクトリ:エンティティと値オブジェクトが含まれます。
  • repository/ディレクトリ:リポジトリインターフェースが含まれます。
  • usecase/ディレクトリ:ユースケースが含まれます。
  • service.go:ドメイン層のサービスを提供するインターフェースが定義されます。
  1. infrastructure/ディレクトリ:データベース、外部API、ファイルなどのインフラストラクチャとの通信を担当する層です。
  • persistence/ディレクトリ:データ永続化に関連するコードが含まれます。
  • webapi/ディレクトリ:WebAPIに関連するコードが含まれます。
  • config.go:アプリケーションの設定が定義されます。
  • database.go:データベース接続の初期化が行われます。
  1. application/ディレクトリ:ドメイン層とインフラストラクチャ層の仲介役となる層です。
  • service/ディレクトリ:ドメイン層のサービスを提供するインターフェースの実装が含まれます。
  • handler/ディレクトリ:WebAPIのハンドラが含まれます。
  1. main.go:アプリケーションの起動とDIの設定が行われます。

サンプルコード

以下は、上記のディレクトリ構造を使ったサンプルコードの一部です。

// domain/user.go
package domain

type User struct {
    ID   int
    Name string
    Age  int
}

// domain/user_repository.go
package domain

type UserRepository interface {
    FindByID(id int) (*User, error)
}

// domain/user_usecase.go
package domain

type UserUsecase interface {
    GetUserInfo(id int) (*User, error)
}

// infrastructure/persistence/user_persistence.go
package persistence

import (
    "myapp/domain"
)

type UserPersistence struct {
    // データベースのクライアントなど
}

func (p *UserPersistence) FindByID(id int) (*domain.User, error) {
    // データベースからIDを使ってユーザ情報を取得
}

// application/service/user_service.go
package service

import (
    "myapp/domain"
)

type UserService struct {
    UserRepository domain.UserRepository
}

func (s *UserService) GetUserInfo(id int) (*domain.User, error) {
    user, err := s.UserRepository.FindByID(id)
    if err != nil {
        return nil, err
    }
    return user, nil
}

// application/handler/user_handler.go
package handler

import (
    "myapp/application/service"
    "net/http"
    "strconv"
)

type UserHandler struct {
    UserService
}

type UserHandler struct {
  UserService *service.UserService
}

func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
  id, _ := strconv.Atoi(r.URL.Query().Get("id"))
  user, err := h.UserService.GetUserInfo(id)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }
  // レスポンスを返却
}

// infrastructure/webapi/router.go
package webapi

import (
  "myapp/application/handler"
  "myapp/application/service"
  "github.com/gorilla/mux"
)

func NewRouter(userService *service.UserService) *mux.Router {
  r := mux.NewRouter()
  userHandler := &handler.UserHandler{UserService: userService}
  r.HandleFunc("/users", userHandler.GetUser).Methods("GET")
  return r
}

// main.go
package main

import (
  "myapp/application/handler"
  "myapp/application/service"
  "myapp/infrastructure/persistence"
  "myapp/infrastructure/webapi"
)

func main() {
  userPersistence := &persistence.UserPersistence{}
  userService := &service.UserService{UserRepository: userPersistence}
  router := webapi.NewRouter(userService)
  // ルーターを起動
}

以上がGolangでオニオンアーキテクチャを実装する方法の一例です。
このように、各層が疎結合になっているため、柔軟なアプリケーションを作成することができます。
また、テストを行う場合にも、各層をモック化することが容易になります。


上記をベースに色々試してるrepository作りました!!
一緒に遊びましょう!!