townsy.io
Answering that Stack Overflow question

Stack Overflow – Now let’s learn how to answer

I’m going to cover my approach to answering a question on Stack Overflow. If you are unfamiliar with Stack or don’t know how to validate a question, please see my previous post. Just visit it here.

I’m going to focus on a question I answered previously as an example for this post. It was very replicable and it was something I hadn’t tried before. This article assumes you are familiar with AWS S3 and localstack as this is required to replicate this questions environment

The Question

I am working on an API that can handle requests as though it is the S3 API, and should therefore work with the Go S3 SDK. I am specifically encountering a problem when attempting to pass a Bucket name to Go S3 SDK functions.

The question which can be found here states that the person is having problems with the bucket name when passing that through to the AWS SDK. The user gives a decent code snippet and description of the error, which in this case was related to the resolving of the bucket URL. It’s not actually stated in the question, but the user was using localstack, which is a tool to replicate AWS services.

Replicating the environment

My first step to giving this person an answer was to replicate the environment and see if I got the same bug.

Docker

I didn’t have all the code but was fairly confident setting this up as I’d used Localstack in Docker previously. I started by creating this localstack docker-compose file so I could spin up my required AWS services

# docker-compose.yaml
version: "3.7"
services:
  localstack:
    image: "localstack/localstack"
    ports:
      - "4566:4566"
    environment:
      DEFAULT_REGION: eu-west-1
      SERVICES: s3

Running docker-compose up at the root with this file spins up a localstack instance running in a docker container. The environment variable specifies the services I want to run. In this case, it’s S3 but you can also run services like SNS or SQS. Once this is up and running I can make requests to this using the URL http://localhost:4566. Notice the port number matches the ports: section in the docker-compose file because I’ve exposed 4566 as an external port.

I highly recommend running Docker containers in this way, you can spin up environments very quickly. You can simply spin up Python, Node or even PHP environments

Golang

The question we are answering is in Go, so I needed to replicate this code. Something I didn’t mention previously was that I usually have a directory called scratch in my workspace. I just create a new directory inside scratch that relates to the question and add the required resources. In my case, this was the docker-compose.yaml file and a main.go file, it’s also worth noting that I always use Go Modules so will run the command go init mod {project name}.

I don’t really want this to turn into a Go tutorial so I’ll just supply the code here. If you have any questions about the code feel free to comment on the post

func main() {
	ctx := context.Background()

	// for custom localstack endpoint
	customResolver := aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
		if service == s3.ServiceID {
			return aws.Endpoint{
				PartitionID:   "aws",
				URL:           "http://localhost:4566",
				SigningRegion: "eu-west-1",
				// HostnameImmutable: true,
			}, nil
		}
		// returning EndpointNotFoundError will allow the service to fallback to it's default resolution
		return aws.Endpoint{}, &aws.EndpointNotFoundError{}
	})

	config, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("eu-west-1"), config.WithEndpointResolver(customResolver))
	if err != nil {
		log.Fatalf("unable to load SDK config, %v", err)
	}

	client := s3.NewFromConfig(config)

	bucketName := "dave"
	input := s3.CreateBucketInput{
		Bucket: &bucketName,
	}
	r, err := client.CreateBucket(ctx, &input)

	fmt.Println(r)
	if err != nil {
		panic(err)
	}
}

Once I had replicated the code I could then try and reproduce the bug. In this case, I did actually get the same bug. The hostname was different based on a single bucket name compared to a camelCase bucket name. This would cause the AWS client to fail as it was looking for a hostname that didn’t exist. The URL the AWS SDK would communicate with was http://bucket.localhost:4566 which was incorrect, there was no host with this subdomain.

So I’ve reproduced the bug now what?

I comment on the user’s post to confirm that I was able to replicate the bug and I am investigating further. You could use the opportunity to ask for more information or even check it’s still active.

This is the fun part, we need to solve the issue which is why I think Stack Overflow is a great place to learn. We have an everyday issue, that someone is experiencing right now. It’s a very relatable problem that could happen to any of us. You can visit the question, but I want to focus on how to approach and write an answer rather than focus on solving the issue.

  • Look for documentation – understand how the hostname is resolved and see if there are different options/config available
  • Debug and step through the code. Most code editors can debug through the code, add a breakpoint and step in and out of functions. It will give you a clear understanding of how the package was written, and it gives you context. If you do not understand what you are stepping into, just take your time, read and read some more. It will pay off… I promise
  • If you replicated the problem, is there an issue with the tools being used? Visit the Github page of the package and look at issues. If there isn’t one, raise one and just make sure you follow issue guidelines on that particular repo. I actually requested support on this question from the AWS SDK team which helped me with the answer.

What if I couldn’t find the answer?

Then you didn’t find the answer… it’s okay, move on and attempt another question. You are probably not going to answer every question, don’t beat yourself up, get back in the game. Here’s my pre-emptive thank you for taking a look. Your time is very appreciated!

Someone answered before me!

Just because someone answered the question, doesn’t mean it’s correct. It may not even solve the problem, you should Ignore the answer and carry on your own path. This is for you just as much as it is for the user answering the question. We all want the rep but really understanding the problem is only going to grow your knowledge and skills. It’s not a race and you may even find that your answer will be more comprehensive. This will help thousands in the future.

Formatting your answer

An answer should be good enough for you to use. Read it a few times, would this help you solve the problem? Here are some tips:

  • Context – Focus on the problem and how your answer solves the question. Imagine you are teaching this person, and give a clear explanation
  • Code – Don’t just paste all of your code into the code block. try to pick out the most relevant parts.
  • Links – Did you raise a Github issue? Did you look at documentation? Did you make a Playground or a codepen with the solution?
  • Pleasantries – It’s nice to say thank you but leave that to the comments. You want your answer to be clear and to the point. Again this is for future users that have the same problem

The Takeaway

Well done on answering that first, second or even 100th question on Stack. I hope I was able to support you in making that super answer.

  • Focus on what you learned, not whether you got those rep points. You’ll quickly burn yourself out and be frustrated
  • Stack Overflow can be toxic, if you get downvote or an ungrateful comment, as long as you followed the advice, brush it off and move on to the next one.
  • Remember, you may even need to come back to your answer one day. Go back and update it. Keep it relevant!

Stack Overflow is a great place to learn and contribute to the coding community, yes there is some negativity there but if we all do our part, we can keep supporting each other.

See you there, over and out!

Chris