Giter VIP home page Giter VIP logo

go-structure-examples's Introduction

Examples for my talk on structuring Go apps.

Note: I created an updated version of this repo here! These talks are 3+ years old now and I've changed my opinion on some of this stuff since then, so don't treat them as gospel. ๐Ÿ™‚

Links to video and slides:

Note: these talks refer to release (git tag) v1.0 of this repository.

2018-09-28 GoWayFest 2.0 video | slides

2018-09-19 London Gophers video | slides

2018-08-28 GopherCon 2018 video | slides

Older versions of this talk:

2018-06-02 GopherCon EU video | slides

2018-06-02 GopherCon UK video | slides

How to run

Pick the example (directory) you want to run, then run main.go:

go run main.go or go run cmd/beer-server/main.go

Release v1.0 notes

Not all examples will compile. Only the flat, domain, domain-hex and domain-hex-actor will compile. For more information about why that is, please refer to the talk.

go-structure-examples's People

Contributors

bajusz15 avatar bvwells avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar katzien avatar louvelmathieu avatar toffentoffen avatar umamimike avatar vanbrabantf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-structure-examples's Issues

gRPC example

First off, this is a great repo which I use often as a reference.

I adopted the DDD option in a few services with only REST APIs and would like to add gRPC support but:

  1. Where would you put the .proto files
  2. Would the protobuf service conflict the go interface service we already use
  3. How do you implement a repository interface for AddBeer without having 2 structs of storage implementing the same methods.
  • gRPC: func (s *StorageA) AddBeer(ctx, *pb.BeerRequest)
  • HTTP: func (s *StorageB) AddBeer(beer struct goes here)

Thanks ๐ŸŽ‰

Update example

Hi! Just found your talk and really appreciate it!

Thinking about how to handle an update use case using the domain-hex approach.

Based on the beer sample, let's say an update can update a beer ShortDesc only if the beer was added in the last month (so the field Created is needed). How do you approach it?

The Created field can not be added in the updating.Beer model and comes directly from the database so I'm pretty confused right now.

Thanks :)

[question] where would you put object based permission logic

Hello @katzien !

First of all, thanks a lot for this amazing repo showing all great examples :)

I was wondering, in a clean design, where would you put the object based permission logic?

  1. In domain services logic injecting a permission manager as done for repositories ?
    PROS: logic will be the same across all transports (REST, CLI, etc)
    CONS: I feel like it might not really be the proper place to put it (but maybe it is right to check permissions logic in the domain directly (e.q user, blog, post, comments))
  2. In the transport handlers
    PROS: do not pollute domain logic
    CONS: logic should be rewritten for every transport method (REST, CLI, etc)

Also, I would like to permissions information into the models so API clients knows what's possible or not to do on this model for the given user. For example, user 123 GET post 456 getting the following JSON response:

{
    "id": 456,
    "title": "Example",
    "content": "blablabla",
    "permissions": {
       "userId": 123,
       "canView": true,
       "canEdit": true
    }
}

This way, we don't need to do any extra call asking whatever the user can do X or Y on the given object like GET /permissions/posts/456 with user 123 which would return:

    {
       "userId": 123,
       "canView": true,
       "canEdit": true
    }

Feels like option 1 (put logic in domain service) is better but it just doesn't sound right to have to handle this extra permission model for each object ...

Did you have to tackle such things in the past? If so how did you do? What do you think about the above?

Thanks a lot :)

Modular example suffers from cyclic dependencies.

The 'storage' package imports both 'beers' and 'reviews' packages.
The handler.go file in the 'beers' and 'reviews' packages imports the 'storage' package.

I see that it's stated that all other examples will compile, but then I see no point in presenting a 'modular' example that will not work.

[Question] How do you deal with a large storage?

If you have a large domain with a lots of services using the storage, each defining it's own repository interface, then putting those implementations in a single folder under storage/

I find this pattern gets out of hand really quickly, it's fine for smaller examples like the beer review in this repo, but for large APIs where the storage needs to implement a couple of dozen or hundred repository functions is not really usable.

How would you organise the storage folder to break it down more?

I thought of moving the repository implementations in the domain logic, but that would circumvent this architectural pattern; and by further breaking down everything into sub-folders inside storage/ would circumvent Go's package layout.

The only, somewhat, manageable pattern I found is to create files under storage/ by the entities it represents, like storage/job.go, storage/ticket.go, storage/beer.go and write the repository implementations in these files.

Any other ideas?

Question about domain-hex mode.

Hi Kat,
I watched your talking at Youtube and I have a question about entity definition in domain-hex mode.
I saw the adding/listing folder has almost the same beer definition. I know the beer maybe different between assistants and customers, but will it need to be translated between the different beers?

How do you mock repository interface in a service in hexagonal architecture

Since we are returning domain objects (Beer) from a repository our repository is dependent on the domain package.

However, if you try and mock it with gomock it causes a cyclical dependency Because the mock imports from package and then the package improrts the mock so do I:

  1. Return another non-domain object from the repository (hard for slices of Beers for example)
  2. Put the Beer struct in another package
  3. Put the mock inside the package and not in its own folder.

How to define contexts and figure out which stuff belongs in which

Hi katzien,
First of all: Great talk!

But it left me with a lot of questions: I'm unsure how you would go about defining contexts. Let's say for example you have an app where you can create accounts, add contacts and share documents between them.

In your example you have an adding context, would I put the "adding" of new accounts, contacts and documents inside a common "adding" context (Which would be grouping by functionality again) or would I go and create a "register", a "addcontact" and a "createdocument" context? And if so, would I create a different context for updating e.g. the accounts and documents? If that would be the case wouldn't that mean that I would have to duplicate a lot of the validation logic?

I'm really unsure how to figure out what contexts there are in an application and how to figure out which stuff belongs in which.

Regards

BitPhinix

Question about Service interface in service packages

Hi Kat, after watching your talk, I found your project structure is very inspiring and I'm migrating my project to this structure now. I have a question. Why do you want to create a Service interface in every service package instead a Service struct? and all functions with (s *Service) automatically bind to the struct. Is there any special use case for Service interface?

[Question]: exponsing gRPC services to remote clients

What structure is proffered in case when some service needs to expose it's API calls to remote one (gRPC or HTTP) ?

Case 1)

client/grpc/client.go (returns listing.X and accepts adding.X)

Case 2)

client/grpc/client.go 
                   types.go (defines it's own types such as: GetX and AddX)

Maybe there is better option which is not mention?

Will be grateful if I get feedback on this topic.

[Question] About testing.

How to manage testing in hexagonal architecture? As every package will have it's own testing file too.

Dependabot cannot be upgraded to GitHub-native version due to unsupported `dep` package manager

Dependabot Preview will be shut down on August 3rd, 2021.

It appears that this repository has configured updates for dep.

The GitHub-native version of Dependabot does not support dep, which was deprecated as of 2020.
Guidance from the dep maintainers is to upgrade to go mod, which Dependabot supports.

In order to keep getting updates for your Go dependencies, you'll need to migrate to go mod and add a Dependabot configuration for it to this repository.

Different use case

Hello,

I am trying to implement this structure for a new project.

What I first tried was creating a listing and register service for users.
But I am getting to the point where I want to GetAUserByEmail in order to check if a user is already registered with that email.

So should I use the listing.GetUserByEmail in the register service or definitely not?

Like here:

  • clone https://gitlab.com/theobouwman98/wp/tree/hex-impl
  • run go run cmd/register-server/main.go

What would be a good fix for this.

Thanks in advance.

Filepath relative to module

This repository gave me lot's of inspiration for my own projects but I do have one question regarding filepath.

Let's say you have a static file ( html file or other) in your "rest" package, how would you link to this file from your handler.go file ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.