I'm attempting to mirror a "standard" folder struc...
# sst
k
I'm attempting to mirror a "standard" folder structure for a Golang project with SST. The main issue I have so far is that Golang considers the
src
folder an antipattern. They move the source directories, usually
cmd
,
internal
and
pkg
to the root. Most the module/lib code would be in
internal
and the compiled endpoint, what the stack points at, would be in
cmd
. This is different from the serverless-stack docs here. When I make these changes I get errors related to a missing
src
folder. Is this somehow required? If so, I'll probably nest my app source code following golang conventions under
src
, but am trying to make it work with the golang standard.
t
I actually recently updated our go example for our upcoming 1.0 release
one second
k
Oh cool, I actually prefer the "src" folder cause I come from JS and Java, but Go is pretty explicate that it is not the "correct" way to do it for golang
t
https://github.com/serverless-stack/serverless-stack/tree/master/examples/v1/rest-api-go This still has a similar issue but here's how to think about it:
backend
is the "root" for your go code, so
go.mod
etc goes there. This is set in
stacks/index.ts
under
srcPath
From there your project structure can put lambdas in
backend/cmd
(I didn't do that here but probably should)
a company I advise uses this exact structure and it works fine, you could put
cmd
at root but imo it's kind of strange to then have your frontend folder at the same level
k
Well for me I won't have any frontend in my project
t
actually looking at this the example got generated weird, need to fix
t
yeah in that case you can put everything at root, just remove that
srcPath
line in index.ts
k
here's the project that has been compiling "standard" go practices
so just sort of trying to find the balance
t
The thing is, serverless projects are innately monorepos so following a specific language's practice at the root of the repo risks running into some weird situations
We generally recommend following language practices in a subfolder - eg
backend
k
Makes sense
t
oh I linked you to the wrong thing I meant to link to our new v1 starters
k
Maybe I'll use the
backend
folder and then move all the Go standard Dirs into that
should work
You'd likely use
cmd
instead of
functions
cmd/func1/main.go
or something
k
cmd is for the binaries that get built
t
yeah
k
internal is for all the modules/libraries
that cmd uses
t
yep
k
and pkg is for all the public/sharable stuf
stuff
t
this is actually kind of how I structure my TS projects as well
k
I won't be using pkg though
cool
Ok I'll give this a shot
THANKS!
So if I were to change some folders around in an sst package to play with it, what meta files do in need to be thinking about where sst will be looking for paths? Package.json, sst.json… ?
t
pretty much the only things that I can think of are sst.json#main to point to the main stacks file
and
srcPath
in the function (usually in defaults)
srcPath should be pointed to the "project root" - typically where the language's lockfile is
k
So would that be the Language lockfile for sst or for in my case Go?
t
go.mod
k
Got it
t
Curious why you're doing this in go if you're familiar with ts
k
It's a very valid question ;)
t
Go lambdas perform really well! Can even feel it a lot during local dev, I'd probably saying it's the 2nd best language to use with SST after ts
but I still prefer keeping everything in TS when I can
k
There are a handful of reasons: 1. We have a bunch of solutions we need to solve for: desktop-services, high-performance compute for algorithmic simulation, gRPC services and plain old REST. 2. Our backend team is focused on Golang/Rust/C++ for most the above use cases, but I want to leverage them and their shared packages/modules for our core services that handle persistence and messaging. 3. Go is super super fast in Lambda (what you said) so under high load over time there should be a notable cost savings... pay for what you use. 4. I'm a nerd, and super interested in Go πŸ˜‰
All that said, I love TS, especially the SST experience with live lambdas... so will continue use it for some services for sure.
I agree that Go is prob the second best lang for SST, so thought since I have about 15 engineers to throw at this over time it would be good for us and the project to work out patterns... We'll share everything we learn along the way.
We'll be using TS for all the stack definition
Once we get through the basic setup... we already have things working well, but want to get the project structure nailed before moving ahead... Then I am hoping to work through Delve integration for live lambda with SST... if it is possible. I was talking with @Frank about this last week.
t
nice! yeah we don't dogfood go that much (outside of the company I advise) so would be cool to get more insight as you guys build more on it
k
when you say serverless tends to focus on monorepos... how would you approach a microservices architecture with that? We planned on one project per micro-service, on occasion it might have a frontend for things like swagger docs or example UI with a handful of shared package repos. Then we were gonna use something like meta multi-project, to stitch together when needed to get the monorepo advantage....
t
For me personally I very much prefer a single repo and organizing everything through folder hierarchies. I also stick with a single SST project and group things by using stacks + functions that return stacks. You don't get the benefits of having really granular builds in CI but I'm working on some updates to SST that'll bridge the gap a bit
With serverless I don't know if the concept of a microservice is as discrete as with traditional setups, you don't need to create strict service boundaries so you have a clear deployment artifact
k
interesting.... so what if you have 30-40 services spread across teams... will that still work? I guess it could... just thinking it through
t
Yeah some people really prefer multi-repos and find dealing with a larger team easier that way. But I've seen it done well in either setup
The thing I try to optimize for is local development and if you're certain people only ever need to work on on microservice at a time then multi-project makes sense. But if people often need to think cross service then they need to bring up a bunch of sst instances locally
k
hmmm... well our services won't be strict resource microservice boundaries... more focused on grouping of domains... so it might not be that hard to keep in monorepo
t
^ yeah that's how I do it, purely grouping domains
our upcoming graphql-stack reflects this pattern and we'll be talking more about how we use it
it's like a "light" version of the hexagonal pattern
k
awesome
yeah we were looking at hex/clean/onion pattern'y stuff
but more for inspiration
Hmmmm... so reading the multi instance of sst note... that has me thinking. Are you referring to Live Lambda?
t
yeah running
sst start
k
so if we have it all broken up we'd need to run multiple instances of SST for live lambda?
ok, now I'm catching up to you
t
If you make multiple sst.json projects yeah you'd need to start them all up individually to have the "whole system"
k
If I had ten services broken up and deployed... can I then take just one and
sst start
it.. and only live lambda that one?
I guess that wouldn't really work cause of
stage
right?
Well it wouldn't much matter if they were atomic in terms of workflow and dependency...
t
typically you wouldn't deploy to the same stage you're using for local development but nothing is stopping you from just running one project locally and pointing it to "shared" versions of the others
k
Yeah ok
We are not even close to that, but the stuff we'll be building this year will get there... I'm just working to sort out the architecture now so we have our patterns defined
t
yeah good to spend time up front
k
Copy code
tree
.
β”œβ”€β”€ Makefile
β”œβ”€β”€ README.md
β”œβ”€β”€ backend
β”‚   β”œβ”€β”€ cmd
β”‚   β”‚   └── handlers
β”‚   β”‚       └── main.go
β”‚   β”œβ”€β”€ go.mod
β”‚   β”œβ”€β”€ go.sum
β”‚   β”œβ”€β”€ internal
β”‚   β”‚   β”œβ”€β”€ config
β”‚   β”‚   β”‚   └── config.go
β”‚   β”‚   └── domains
β”‚   β”‚       β”œβ”€β”€ movies
β”‚   β”‚       β”‚   └── main.go
β”‚   β”‚       └── todos
β”‚   β”‚           └── main.go
β”‚   └── pkg
β”œβ”€β”€ package.json
β”œβ”€β”€ reports
β”‚   └── lint
β”‚       └── lint-report-output.html
β”œβ”€β”€ scripts
β”‚   └── commands.sh
β”œβ”€β”€ sst.json
└── stacks
    β”œβ”€β”€ MainStack.ts
    └── index.ts
Something like this
t
That's almost identical to my ts setup so I'd say I'm a fan haha
k
NICE πŸ˜‰
t
btw I've been playing with this pattern for application scripts: https://twitter.com/thdxr/status/1512117834809106462?t=VahzkOL4cxSXaIdbS1G5BA&s=19
k
Thanks for taking the time Dax, it helps to bounce this stuff off people in the same space
ALOT
Oh that's very cool
yes, like cleaning out a seed database
I've shifted to Dynamo for most things over the past few months, but still haven't gotten all the normal operations nailed... dropping and recreating is something I think I need to script
So you create a function for stuff like that and then just exec it
?
I've pushed my commands for project maintenance down to Makefiles lately, mostly cause we are so polygot... it's nice to know make is alway there
but end up calling scripts most the time, even if they are just in package.json/scripts
that's slick
(!ctx.app.local)
t
I use the sst console a lot during local development so I'll just go in there and click the function for scripts, things like resetting the db I use pretty often
k
sweet