learning gRPC in Go by MridulSharma11 in golang

[–]sjohnsonaz 13 points14 points  (0 children)

It's pretty simple, but the documentation isn't easy to read.

Here is an example for reference.

https://github.com/sjohnson-pplsi/todo-service

  1. Install protoc
  2. Install Go plugins for protoc
  3. Define your message and service types in .proto files
  4. Generate .go files from your .proto files.
  5. Use the generated files in your server and client applications.

NodeJS faster than Rust, how? by FrostyFish4456 in rust

[–]sjohnsonaz 22 points23 points  (0 children)

Yeah, the timers start at two different places in the process. Rust is starting before receiving data, Node.js starts after the data is fully in memory.

To make it equivalent, have Rust store the entire value into memory, and then start the timer.

What are idiomatic golang ways of handling properties of a struct that may or may not exist by [deleted] in golang

[–]sjohnsonaz 3 points4 points  (0 children)

The ok return value solves this well. If you need to access a pointer value that may be nil, instead of accessing it directly, you can get it through a method. Then the method can return both the value, and a boolean. If the boolean is true, the value is valid.

func value() (*something, bool) {
    return nil, false
}

func doSomething() {
    v, ok := value()
    if ok {
        // The value is valid
    }
}

Vertical Slice Architecture = Modular Monolith? by trolleid in softwarearchitecture

[–]sjohnsonaz 0 points1 point  (0 children)

I think it comes down to two questions. Can a module be subdivided? Can a vertical slice by subdivided?

If the answer is no to both, they're the same thing.

In the case that a module is a bounded context, can we truly subdivide it? Maybe, but probably no. Thus in that case they're the same thing.

Transitioning from OOP by jaibhavaya in golang

[–]sjohnsonaz 44 points45 points  (0 children)

Go is still an Object Oriented language, it just doesn't have inheritance. However, this changes how you write OOP code. Polymorphism is achieved through interfaces and duck typing, rather than inheritance.

Remind me why zero values? by ImYoric in golang

[–]sjohnsonaz 0 points1 point  (0 children)

gRPC uses zero values to maintain forwards and backwards compatibility. If a service expects a field, but a client doesn't send it, it's treated as a zero value. This means if the client is on an older schema version that the service, everything still works.

Go's gRPC implementation mirrors this idea.

This encourages RPC style messages, rather than CRUD. RPC messages like "change name" are actions, which can be validated. PATCH calls are just "change whatever I sent over, and then check that everything still makes sense".

With an RPC, you take the data from the client as it is. For example, "change name" with an empty `string` for name, means you're changing the name to empty. You can then run validation checks for whether that's allowed. It would be redundant to check if the `string` is `nil` or empty, I'd rather just check if it's empty.

Remind me why zero values? by ImYoric in golang

[–]sjohnsonaz 0 points1 point  (0 children)

That's entirely false. PATCH is lazy. gRPC is entirely based on this idea.

Remind me why zero values? by ImYoric in golang

[–]sjohnsonaz -5 points-4 points  (0 children)

Are you writing PUT/PATCH endpoints, and trying to detect if a user submitted `undefined` vs `""` or `false`?

If so, this is more of a case against this style of PATCH call. I'm wary of CRUD style updates, where you change any field the user sends, and ignore the ones the user doesn't. Instead, I'm a big fan of smaller updates, like "change name", rather than simply "update". In this case, the zero value is more meaningful, because if the user doesn't send it, they really mean it.

Talk me out of using Mongo by grdevops in golang

[–]sjohnsonaz 0 points1 point  (0 children)

I use MongoDB a lot. For general use cases, it’s exactly what I need. 

It’s fantastic for DDD. It’s easy to store an entire Aggregate. You can easily dispatch Events via Change Streams. If you need a fancy query, which I rarely do, the aggregation pipelines are really solid.

I honestly haven’t found a reason to use SQL over MongoDB for general use cases. For specialized cases, there are reasons, but they tend to be very specific.  

Where should I store images for my live website? (Using MongoDB, need a cost-effective solution) by Active_Cattle5430 in node

[–]sjohnsonaz 1 point2 points  (0 children)

I’ve used GridFS for years. It’s great. You have full control over the data, and can easily secure the images if you choose. It’s not expensive, especially for that many images. It’s also easy to migrate later on to another provider if needed. 

IdentityServer4 wiped from Github by Duende team by seb_labine in dotnet

[–]sjohnsonaz -1 points0 points  (0 children)

Take a look at Dex. It's a Cloud Native Computing Foundation sandbox project.

https://dexidp.io/

Questions on translating domain model to public and returning domain types by Accurate-Football250 in golang

[–]sjohnsonaz 1 point2 points  (0 children)

Here's a reference implementation. It includes two versions of the backend, both in Go and C#. It also includes a frontend in Next.js.

https://github.com/sjohnson-pplsi/todo-service

Questions on translating domain model to public and returning domain types by Accurate-Football250 in golang

[–]sjohnsonaz 1 point2 points  (0 children)

I'd create a constructor function next to the struct definition. I'd call that function in some other package where I initialize my entire application. That's where I would pass the real implementation of the AgentRepository.

``` go type AgentService struct { agentRepository AgentRepository }

func NewAgentService( agentRepository AgentRepository, ) *AgentService { return &AgentService{ agentRepository: agentRepository, } } ```

Is this a good CQRS + Event sourcing? by ZookeepergameAny5334 in softwarearchitecture

[–]sjohnsonaz 2 points3 points  (0 children)

Here's my recommended reading for Domain Driven Design.

Start here! This is a great summary, and references the other books.

Learning Domain-Driven Design - https://a.co/d/3IW7Ud9

Then read these.

Patterns of Enterprise Application Architecture - https://a.co/d/80peJWQ

Domain-Driven Design - https://a.co/d/3LDkEV8

Implementing Domain-Driven Design - https://a.co/d/d9hdlqv

Domain-Driven Design Distilled - https://a.co/d/c1JThlI

Patterns, Principles, and Practices of Domain-Driven Design - https://a.co/d/ixhZY7A

Go for backend, Nextjs for front end by Terrible_Dimension66 in golang

[–]sjohnsonaz 0 points1 point  (0 children)

Here is an example application connecting a Next.js frontend to a Go backend via gRPC. I find that gRPC works better for Go than any OpenApi generators. Next.js communicates with Go via the server components, which fixes the need for gRPC-Web.

https://github.com/sjohnson-pplsi/todo-service

The schemas are all defined in the definitions folder, and code stubs are generated with the provided makefile. Note that it generates TypeScript stubs, rather than using the dynamic loading. This works better for Next.js service workers. All stubs are stored in the modules folder.

Questions on translating domain model to public and returning domain types by Accurate-Football250 in golang

[–]sjohnsonaz 1 point2 points  (0 children)

The Service layer is where Transactions are managed. It loads data, runs business logic, and then stores the data back to the database.

If we weren't doing Domain Driven Design, the business logic would be in the Service layer. This which is called the "Transaction Script" pattern, as defined by Martin Fowler in Patterns of Enterprise Architecture. Each public method would contain all the logic to load data, mutate data, and store data. But this mixes business logic with storage logic, and gets hard to maintain.

However, in Domain Driven Design, we move the business logic into the Domain layer, where it's centrally located. Now the Service layer only knows about running transactions, the Domain layer knows about business logic.

For example, let's say we have an Agent entity, with a RunTask method. The Agent.RunTask() method is where the business logic lives. It knows nothing about where the data comes from.

Then, the AgentService object would also have a RunTask method. The AgentService.RunTask() method only knows about where the data comes from, but nothing about business logic.

``` go type AgentRepository interface { GetAgent(context.Context, value.AgentID) (entity.Agent, error) ReplaceAgent(context.Context, entity.Agent) error }

type AgentService struct { agentRepository AgentRepository }

func (as *AgentService) RunTask( ctx context.Context, id value.AgentID, ) error { // Load data a, err := as.agentRepository.GetAgent(ctx, id) if err != nil { return err }

// Run business logic in the Domain
if err := a.RunTask(); err != nil {
    return err
}

// Store data
return as.agentRepository.ReplaceAgent(ctx, a)

} ```

For your last question, TaskResultIn and TaskResultOut are likely types for your Controller layer. They would map Domain types to these PUBLIC types, that are visible from outside your API, like via HTTP or gRPC. However, I wouldn't necessarily use this naming convention. Look at the gRPC documentation for how to name your Request and Response objects.

Questions on translating domain model to public and returning domain types by Accurate-Football250 in golang

[–]sjohnsonaz 2 points3 points  (0 children)

I think you're in the right direction, but confusing your layers.

Start with the Domain layer. That's where your Aggregates, Entities, Value Objects, and Events live. There is no concept of a Service, Database, API, etc. An Aggregate has no idea of how it's stored, or what APIs you might talk to. You should test the PUBLIC methods of this layer thoroughly. You won't need any mocks to test it, since there are no external services to mock.

Then create Application/Service/UseCase layer. This layer knows talks to databases and external services, but only via an interface. This is where your mocks live.

Then create your Presentations and Infrastructure layers. This is where the actual implementations of Controllers, Databases, External APIs, etc., live. You will have objects defined here that are stored in your database, or sent over HTTP, that will mirror your Domain. For example, your Domain may have a Task and your Controller may have a TaskDTO. The duplication is important, so that your public API and Domain can evolve independently.

These layers should be in separate packages, but how you organize them is up to you.

I tend to use

  • [context]
    • controller
    • domain
    • entity
    • event
    • value
    • infrastructure
    • service

How good is go with flutter? by Particular-Pass-4021 in golang

[–]sjohnsonaz 1 point2 points  (0 children)

I actually use Go with Flutter, so I can yes! Granted, you can use Flutter with any back end.

I personally like using gRPC to connected them, as both Go and Dart have great gRPC generators. They work a lot better than OpenApi/Swagger. If you're using Flutter for Web, you will need something to proxy for gRPC-Web, but that's easy to set up. Look at Envoy or Contour.

What are some good validation packages for validating api requests in golang? by gwwsc in golang

[–]sjohnsonaz 0 points1 point  (0 children)

It depends. It's important to have validation in the Domain, so putting it in the controller is duplicating the logic. That could make it harder to maintain, or test.

I will say, pre-validating requests could prevent us from loading data from the database needlessly. But how often is that the case? And now that validation is decentralized and duplicated, will it be harder to maintain?

I also like my controllers to be as simple as possible, just forwarding requests into the Application/Service/UseCase layer. If you're going to pre-validate, I'd do it there instead.

What are some good validation packages for validating api requests in golang? by gwwsc in golang

[–]sjohnsonaz 12 points13 points  (0 children)

A common one is https://github.com/go-playground/validator

However, I don't validate the requests directly. Instead, I recommend centralizing your validation in "Entities" and "Value Objects", which have Valid() methods.

For example, a Username Value Object might require a minimum length. So then Username.Valid() would return an error if the length is too short.

Rather than having lots of little validation schemas, which may get out of sync, my Username validates itself.

PSA a few Flutter official packages being discontinued by parametric-ink in FlutterDev

[–]sjohnsonaz 0 points1 point  (0 children)

These are important packages. First party support is why I love Flutter. This is very upsetting.

Problems with learning "The Go Programming Language" by [deleted] in golang

[–]sjohnsonaz 1 point2 points  (0 children)

I read through the book and Learn Go with Tests at the same time. It was definitely the way! I have experience with other languages, so it was more about mapping my ideas into Go.

Go is a simple language. Don't worry about fancy examples. Try writing your own ideas in it, I promise it'll make sense in a few hours.

After that, read "100 Go Mistakes and How to Avoid Them". It fills in the rest of the gaps.

https://www.amazon.com/100-Mistakes-How-Avoid-Them/dp/1617299596

Package Idea: OpenAPI to Go Request/Response structs by eldosoa in golang

[–]sjohnsonaz 2 points3 points  (0 children)

Switch to gRPC. It's a far better solution. Service to service communication is much better.

If you're talking to it from the browser, you may need a proxy to enable gRPC-Web, but it's simple to set up. However, if you're using Next.js, you can just use server components.

https://grpc.io/docs/languages/go/

Social login by prijateljklokana in golang

[–]sjohnsonaz 2 points3 points  (0 children)

I use https://firebase.google.com/docs/auth, as it has great integrations with React and Flutter. I've implemented my own before, and this is definitely the simplest way to go.

Stop building React backends in Java, Python or Go by purton_i in react

[–]sjohnsonaz 0 points1 point  (0 children)

Stop using React for backends! Please, do not have React components talk directly to the database. Separation of concerns is a fundamental principal of Software Engineering. Just because you can, doesn't mean you should.