SkillAgentSearch skills...

Goweave

Aspect Oriented Programming for Go

Install / Use

/learn @deferpanic/Goweave
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

goweave Aspect Oriented Programming for Go

wercker status

GoDoc

Weave

WARNING - Major Hackage

This really isn't meant to be used by anyone yet - definitely not in a production environment - you have been warned!

Many 'design decisions' were not decisions at all - they were simply the "most simplest thing that could work". Lots of work left to do.

TOC

What is AOP

Why

Usage

Examples

Loom

FAQ

Info

Reserved Keywords

Differences

Performance

Tests

Help

Todo

Roadmap

What is AOP !??

Aspect oriented programming

In short - this is a pre-processor that generates code defined by a goweave specification file - it's not a proper grammar yet although it probably should be.

Why!??!

"... which is our fulltime job, write a program to write a program" rob pike

The critics yell red in the face - "We came to go to get away from enterprise java!! What the hell is the matter with you!?"

I agree this concept can and has been abused in the past.

However, I'm definitely not a code purist - to me coding is a tool first and foremost.

I simply wanted an easy way to attach common bits of code to large existing codebases without having to hack it in each time to each different codebase. I also needed the ability to do this on large projects without modifying the source.

Sure I could write method wrappers, I could change code, etc. but I don't want to be constantly writing/re-writing/re-moving/inserting tons of code just to check things out.

Automate all the things. For me, this is simply a powertool for deep introspection of go programs.

That is the rationale behind this.

Existing Tools:

go fmt

This is actually used for around advice currently. It allows you to wrap methods. Having said that - we wish to do more proper around advice than simply re-writing the function declaration.

ex:

gofmt -r 'bytes.Compare(a, b) == 0 -> bytes.Equal(a, b)'

go fix:

This is one hell of an awesome tool. I just think it's a little too low-level for what we are wanting to do. Remember - one of the solutions of this tool is to make things as trivial as possible to insert new functionality.

go cover:

This is used to provide code coverage and has similar properties to what we want.

go generate:

We are generating code but we are looking for more extensive code generation.

Usage:

Where you might use

  go build

simply replace with

  goweave

Note: depending on how you build your go this may or may not work - patches/pulls to make this more generic for everyone are definitely welcome.

Use Cases

  • error detection && correction (ex: force logging of errors on any methods with this declaration)

  • data validation (ex: notate that this data was invalid but allow it to continue)

  • i18n (ex: translate this to esperanto if you can't detect the language)

  • security (ex: authenticate this user in each http request)

  • caching (ex: cache these variables when exposed in a http request)

  • logging (ex: log when this group of users accesses these methods)

  • monitoring (ex: ensure that if this channel closes we always alert joebob)

  • metrics (ex: cnt the number of times this function is called)

  • tracing (ex: print out the value of this variable in a pkg)

  • dealing with legacy code (ex: overriding a method/API w/minimum of work)

  • static validation (ex: force closing a file if we detect that it hasn't been closed)

Grammar:

The aspect 'grammar' if you can call it that is a total piece right now. It is a little bit of go, a little of json, etc. It is most definitely not going to stay the same - it will be improved in the future.

I apologize for giving you the forks to stab your collective eyes out.

I think a good goal to have is to make it as proper go as possible and then extend it maybe through comments.

Suggestions/pull requests/discussions more than welcome!

Definitions:

I probably have not defined certain things properly here - open a pull request if you find something off.

Join Points

Places in your code you can apply behavior.

Aspects:

A .weave file that contains our behavior.

Right now we support multiple .weave projects for a project and they will apply advice recursively over a project.

The programming theory department says that aspects are common features that you use everywhere that don't really have anything at all to do with your domain logic. Logging is a canonical example - most everything you log does not really have anything to do with all the other stuff you log.

Similarly if you had a http controller that whenever you got a request you would update a metric counter for that controller but you do this on each api controller - that really has nothing at all to do with the controller logic itself. The metric might simply be another aspect that is common everywhere.

Once again someone might point out why don't you just make a method and then wrap each call? The point here is that 1) we don't want to modify code, 2) we might not know all the places that happens and could easily leave something out, 3) we are eternally lazy and would rather the computer do this for us.

PointCut:

An expression that details where to apply behavior.

Pointcuts in other languages such as java can commonly use annotations -- we currently don't support this as we want to be un-obtrusive as possible -- that is - we don't want to modify go source

We support {call, execute, within} pointcut primitives right now: Also we are hacking in local/global get/sets and declarations.

call:

These happen before, after or wrap around calling a method. The code is outside of the function.

execute:

These happen before or after executing a method. The code is put inside the method.

within:

These happen for *every* statement within a function body declaration.

get:

These fire when a local/global variable has a get operation.

set:

These fire when a local/global variable has a set operation.

declaration:

This fires when a variable is declared.

All pointcuts are currently defined only on functions. Struct field members are definitely a future feature we could support although go generate might do this acceptably already.

Note: this 'grammar' if you can call it is nowhere close to 'ok' - expect it to change "heavily".

explicit method name

  call(blah())
  execute(blah())

partial match method name - TODO

  call(b.*)
  execute(b.*)

function declaration w/wildcard arguments

  call(http.HandleFunc(d, s))

wildcard function name w/explicit arguments

  execute((w http.ResponseWriter, r *http.Request))

doesn't work yet - TODO

sub-pkg && method name

  execute(pkg/blah())

sub-pkg && struct && method-name

  execute(pkg/struct.b())

struct && method name - TODO

  execute(struct.b())

Advice:

Behavior to apply:

  • before
  • after
  • around

Around advice currently only works with call pointcuts.

We currently support the following advice:

call examples:

  some.stuff()

Code will be executed {before, around, after} this call.

call before:

  fmt.Println("before")
  some.stuff()

call after:

  some.stuff()
  fmt.Println("before")

call around:

  somewrapper(some.stuff())

execute examples:

  func stuff() {
    fmt.Println("stuff")
  }

execute before:

  func stuff() {
    fmt.Println("before")
    fmt.Println("stuff")
  }

execute after:

  func stuff() {
    fmt.Println("stuff")
    fmt.Println("after")
  }

within examples:

  func blah() {
    slowCall()
    fastCall()
  }

within before:

  func blah() {
    beforeEach()
    slowCall()
    beforeEach()
    fastcall()
  }

Goals

  • FAST - obviously there will always be greater overhead than just running go build but we don't want this to be obscene - right now it's a little obscene

  • CORRECT - it goes w/out saying this is highly important to be as correct as possible w/our code generation

  • NO CODE MODIFICATIONS - my main use cases involve not modifying code so that is why we initially did not support annotations - I'm not opposed to adding these but that's not my intended goal

  • create tooling around AO development for go

  • maybe move towards compiler extension?

FAQ

Why not do everything via the AST?

We are moving all the regexen to AST modifications. This started out as a POC and I wanted functionality

Related Skills

View on GitHub
GitHub Stars223
CategoryProduct
Updated4mo ago
Forks9

Languages

Go

Security Score

92/100

Audited on Nov 4, 2025

No findings