streamline

package module
v0.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 23, 2021 License: Apache-2.0 Imports: 7 Imported by: 0

README

WARNING: This repo is currently under active developing, dependencies and itself will have breaking change frequently. If you are interested in this idea, please leave me a message!

Streamline

Inspiration

During my development, I found current way of building a web app is not agile enough, also not clear enough. Debugging is cumbersome, adding new feature to existing code base is a disaster. Therefore, inspired by AOP in Java Spring and analog of streamlines in factory, I made this package to address such problems.

Introduction

TLDR; This is a super flexible way to organize middlewares, and every single function is a middleware.

This project aim to address a production issue: Collaboration is hard. It is hard to understand other's code. It is hard to debug a super long function especially it is not written by you. More importantly, even among a group of skilled programmers, mass collaboration is still not possible since the parallelism is not big enough. In another word, there not that much work can process at the same time.

In this project I introduced a novel approach(not really) building a service. To demonstrate in a trivial way, I used an analog of factory and streamline.

Basic idea

Ideally, data and procedures that manipulate the data should be separated. Like the streamline in a factory: parts move along the conveyor belt, each time it arrives at a worker(in our case, procedure that manipulate this kind of data), the worker apply some change on the part.

Fortunately, Golang is very suitable for this task. By using interface, we can define what kind of information the data have, and define what information a procedure need. If the data satisfy the requirement, we can apply the procedure to the data and guaranteed a defined behavior.

Concepts

DataDomain

A data-domain belong to a ConveyorBelt, ConveyorBelt take this data-domain to all the procedures in the streamline that this ConveyorBelt is executing.

Data-domain contains all data and intermediate values needed to process the request. Thus, applying compatible procedure to this data-domain should behave like a mathematical operator that is closed under this domain.

Factory

A factory is used to produce new streamlines and manage their meta-data.

Procedure

A Procedure is a function, defined as func(*ConveyorBelt) int. The return value is status code, currently following http status code standard, but likely to change in the future.

Streamline

A streamline contains multiple procedures. It defines a series of operation and their sequence.

ConveyorBelt

ConveyorBelt execute a streamline, taking a data domain with it, and controlled by a context.

How

First, you need to think and define data-domains. A data-domain should be sufficient to hold all the data needed across the entire sequence of computation. Data-domain should implement getters for all fields, purpose of this is to use interface to validate compatibility in compiling time.

Second, create procedures you want to apply to your data. Each procedure should associate with an interface that defines all fields required by this procedure. The interface contains multiple getters, if the corresponding data-domain implements those getters, the interface assertion will success.

Third, use the given factory to create streamlines, which is simply a sequence of procedures.

Lastly, create a ConveyorBelt, give it a streamline, a data-domain and a context to control execution of this ConveyorBelt.

Future work

Apply this design pattern to an actual project and validate this idea. Any critic or comment are welcome!

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConveyorBelt

type ConveyorBelt struct {
	DataDomain interface{}
	S          *Streamline
	Ctx        context.Context
	Logger     log.Logger
	LogInfoGen func(*ConveyorBelt) string
}

func NewConveyorBelt

func NewConveyorBelt(s *Streamline, c context.Context, dataDomainRef interface{}, f func(*ConveyorBelt) string) *ConveyorBelt

func (*ConveyorBelt) Debugw

func (c *ConveyorBelt) Debugw(args ...interface{})

func (*ConveyorBelt) Errorw

func (c *ConveyorBelt) Errorw(args ...interface{})

func (*ConveyorBelt) Infow

func (c *ConveyorBelt) Infow(args ...interface{})

func (*ConveyorBelt) Run

func (c *ConveyorBelt) Run() (int, error)

func (*ConveyorBelt) Warnw

func (c *ConveyorBelt) Warnw(args ...interface{})

type Factory

type Factory struct {
	// contains filtered or unexported fields
}

func New

func New() *Factory

func (*Factory) Get

func (f *Factory) Get(name string) *Streamline

func (*Factory) GetAllStreamlines

func (f *Factory) GetAllStreamlines() map[string]*Streamline

func (*Factory) NewStreamline

func (f *Factory) NewStreamline(name, action, resource string) *Streamline

func (*Factory) Plot

func (f *Factory) Plot() string

type Proc

type Proc struct {
	F    ProcFunc
	Name string
}

type ProcFunc

type ProcFunc func(*ConveyorBelt) int

type Streamline

type Streamline struct {
	Name string

	Tags []string
	// These are for RBAC authentication
	// If any of them is nil, it means no authentication is enabled
	Action   string
	Resource string
	// contains filtered or unexported fields
}

func (*Streamline) Add

func (s *Streamline) Add(procName string, f ProcFunc)

func (*Streamline) AddTag

func (s *Streamline) AddTag(tag string)

func (*Streamline) Describe

func (s *Streamline) Describe() []string

func (*Streamline) Insert

func (s *Streamline) Insert(target string, procName string, f ProcFunc, insertBefore bool) error

func (*Streamline) InsertFront

func (s *Streamline) InsertFront(procName string, f ProcFunc) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL