1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

combie-go — Goでの集約・加工処理をシンプルにするライブラリ

Posted at

はじめに

現代の業務システム開発では、似たようなクエリ・集約・フィルタ・組み合わせ処理
モジュールごとに何度も実装するケースが多くあります。

しかし、これらの処理はビジネスの文脈によって微妙に異なるため、再利用が難しく、
結果として重複コードや保守コストが増大しています。

combie-go は、こうした「似ているけど同じではない処理」を
一つの統一的な仕組みで再利用できるようにするためのライブラリです。


課題と動機:なぜ新しい仕組みが必要なのか

多くのプロジェクトでは、データ処理のロジックを統一的に表現する仕組みがありません。

  • ビジネスロジックがコードにベタ書きされ、再利用や拡張が難しい
  • 集約関数やフィルタ条件、コンテキスト情報が各層に分散している
  • 仕様変更のたびに再テスト・再デプロイが必要になる

こうした問題から、「データをどう処理するか」を都度書くのではなく、「データをどう扱うべきか」を宣言的に表現できる柔軟な仕組みが必要だと感じました。


解決策:combie-go の設計思想

combie-go は、こうした課題を解決するために設計されたコンポーネントです。
Java 開発で得た類似コンポーネントの経験をもとに、処理ロジックを関数として抽象化し、
その関数を構造体の Tag で宣言的に紐付けることで、
最小限のコードで集約・結合・加工処理を実現できます。

combie-go の目指すところは:

  • 統一的なデータ処理インターフェースにより、重複コードを削減する
  • Tag とコンテキストを活用して拡張性を高める
  • 複雑な業務データの流れをシンプルで明確にし、保守性とテスト容易性を両立する

コアバリュー

  • 開発時間の短縮:複雑な処理を毎回手書きする必要がない
  • 再利用性の向上:関数とロジックを統一管理し、再利用可能に
  • 可読性・メンテナンス性の向上:統一 API によりロジックの見通しを向上

インストールとクイックスタート

go get github.com/kyousukesan/combie-go

推奨 Go バージョン: 1.22+

package main

import (
	"fmt"
	"strings"

	combine "github.com/kyousukesan/combie-go"
)

type Item struct {
	ID       int      `combine:"combineItem,Items"`
	Name     string   `combine:"uppercase,Name"`
	Score    int      `combine:"avg_score,fn:SetAvg"`
	Items    []string
	AvgScore float64
}

func (i *Item) SetAvg(v any) {
	switch x := v.(type) {
	case float64:
		i.AvgScore = x
	case int:
		i.AvgScore = float64(x)
	}
}

func AvgScoreAgg(values []any, ctx map[string]any) map[any]any {
	out := make(map[any]any, len(values))
	for idx := range values {
		if idx == 0 {
			out[idx] = float64(20)
		} else {
			out[idx] = float64(100)
		}
	}
	return out
}

func main() {
    // コンテキスト。処理関数内で利用可能
	b := combine.NewCtxBuilder().
		Set("factor", 1.5).
		Set("env", "prod").
		Set("region", "ap-northeast-1").
		Set("trace", true)
    // 初期化。デフォルトで並列処理を有効化し、コンテキストを設定
	c := combine.NewCombine(
		combine.WithConcurrent(),
		combine.WithCtxBuilder(b),
	)
    
    // ハンドラ関数を登録。入力:values []any, ctx map[string]any、出力:map[any]any
	c.Register("uppercase", combine.HandleFunc(func(values []any, ctx map[string]any) map[any]any {
		out := make(map[any]any, len(values))
		for idx, v := range values {
			out[idx] = strings.ToUpper(fmt.Sprint(v))
		}
		return out
	}))

	c.Register("combineItem", combine.HandleFunc(func(values []any, ctx map[string]any) map[any]any {
		out := make(map[any]any, len(values))
		for idx, v := range values {
			if id, _ := v.(int); id == 1 {
				out[idx] = []string{"bbb", "aaa", "ccc"}
			} else {
				out[idx] = []string{"sss"}
			}
		}
		return out
	}))
    
    // 再利用可能な処理関数を登録。データモデルと紐付けて、どこでも利用できます
	c.Register("avg_score", combine.HandleFunc(AvgScoreAgg))

	items := []Item{
		{ID: 1, Name: "alice", Score: 90},
		{ID: 2, Name: "bob", Score: 80},
	}

    // 処理を実行。結果の map を元データにマッピング
	if err := c.Process(items); err != nil {
		panic(err)
	}

	fmt.Printf("%+v\n", items)
}

img.png


コアコンセプトと設計

  • 汎用データ処理[]struct または []*struct に対応し、リフレクションで自動的にフィールドを識別
  • Tag ベース集約combine タグで集約関数と出力方法を指定
  • コンテキスト対応NewCtxBuilder によるチェーン構築で、登録関数から combineCtx にアクセス可能
  • 並列実行WithConcurrent() で複数の集約関数を並列処理
  • 拡張性:カスタム集約関数を登録可能、様々な業務シナリオに対応

combine タグの構文

combine タグは、集約関数フィールド出力方法 を指定します。基本形式は以下の通りです:

`combine:"集約関数名,フィールド名[,fn:Method]"`

構成要素

  1. 集約関数名

    • Combine.Register() で登録した関数名
    • 例:uppercasecombineItemavg_score
  2. フィールド名

    • 集約結果を書き込む構造体フィールド
    • 例:NameItems
  3. fn メソッド(任意)

    • フィールドに直接書き込むのではなく、メソッド経由で出力
    • 例:fn:SetAvg

type Item struct {
    ID       int      `combine:"combineItem,Items"`       // combineItem の結果を Items フィールドに反映
    Name     string   `combine:"uppercase,Name"`         // uppercase の結果を Name に書き込む
    Score    int      `combine:"avg_score,fn:SetAvg"`    // avg_score の結果を SetAvg メソッドに渡す
    Items    []string
    AvgScore float64
}

補足

  • タグは コンポーネント駆動の核 であり、どのフィールドがどの関数で処理されるかを決定
  • 直接フィールド書き込み または 出力メソッド呼び出し(fn) の両方に対応
  • 集約関数内から Combine コンテキスト (combineCtx) にアクセス可能で、柔軟なロジックが実現可能

API(現行バージョン)

// Combine の生成
func NewCombine(opts ...Option) *Combine

// オプション
func WithConcurrent() Option                 // 集約関数の並列実行を有効化,並行実行時に安全である必要があります
func WithCtx(ctx map[string]any) Option      // コンポーネントコンテキスト combineCtx を設定
func WithCtxBuilder(b *CtxBuilder) Option    // CtxBuilder で複数 k-v を設定

// 集約関数登録
type AggregateHandler interface { Handle(values []any, combineCtx map[string]any) map[any]any }
type HandleFunc func(values []any, combineCtx map[string]any) map[any]any // adapter
func (c *Combine) Register(name string, fn AggregateHandler)
func (c *Combine) RegisterAggregate(name string, fn AggregateHandler)

// 実行
func (c *Combine) Process(items []any) error

今後の計画

  • 複雑な集約関数のサポート(グループ化・条件式対応)
  • キャッシュ層の実装(重複計算の抑制と性能最適化)
  • ソート・ランキング機能 の導入
  • ネストされた struct の集約への完全対応 への完全対応

サンプルとテスト

go run ./example
go test ./...

GitHub: https://github.com/Kyousukesan/combie-go

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?