Technical Lead
BristleconeSenior Software Engineer
Circles.LifeSenior Software Engineer
MobobeatSoftware Developer
Kaves Technology and Anant Infomedia
Golang
Node.js

PHP

MySQL

MongoDB

Cassandra
.png)
ELK Stack
.png)
Docker

Kubernetes

GCP

AWS

RabbitMQ
Yeah, hi. My name is Saish Knight, and I'm a senior software developer. I have 6 years of experience in Golang. And I also worked with Node.js. I have around 6 years of experience in JavaScript as well. I'm currently working in a telecom-based company. So, I've worked there on microservices, Golang, Node.js, and AWS. We use AWS for cloud. Then we have Kubernetes for container orchestration. In total, I have around 9 years of experience.
So most of the time for solid principles, if I'm using Go lang, I basically try to use interfaces, then interfaces are a basic thing for solid principles. Single responsibility as in I would only use a function to do one thing and not more than that. Correct? And then if we are talking about objects, modification, that is if you do want to keep your object open for your object to change, you only keep it open for modifications. So that for that, I actually use an interface. So by sending in the interface type, you can actually achieve that. So that is the O in solid sense for open close principle that is for open for modification. Open for new changes, but close to change the existing code. So that can be achieved by using interfaces again. So I would like to give an example, but let me go on to the Liskov substitution principle. This cost substitution principle basically says it should be easy to substitute values. Again, here, we'll be using what you call interfaces. So for this one as well, we will be using an interface. And let's just say if we have something like MySQL or Mongo. So if I'm using MySQL at the moment, I won't be passing the MySQL struct, rather I'll be using the interface. So based on that, we can follow the list of it. Now in the future, if I want to change it to Mongo, I will just pass in the interface. So my Mongo will follow a certain interface. Let's just say a DB interface. I'll be passing it to that. Then interface segregation. That is the key of it. That means we will be creating big interfaces. We'll be dividing it into small and smaller interfaces. So what happens is let's just see if I keep a big interface. I will any struct which has to do something, which has to, like, suppose it, we are talking about some sort of job or some sort of action that it has to perform. It has to do all the actions of a big interface. Sometimes it might not have to, you know, you might just have to return nil or something like that or just write some dummy code. So if we do want to avoid that, we would have to do an interface aggregation wherein we'll be separating our data. Now, let's talk about D, that is the dependency inversion. So we won't be depending on the direct implementation of the code. We'll be depending upon the interface. By doing so, it's much easier to, you know, replace any sort of object. Can easily let's just say we are expecting, like, a MySQL. We can just put in that. If you want to pass a Mongo, we can put in the Mongo. We can make the Mongo follow the interface.
Or if we're talking about AWS deployment, we will be creating, what they call a private network everywhere. So, like, if I'm deploying a microservice architecture, in that case, I will be pushing all of this into one secure network. Okay? So you can create your own VPC. And when you do this, only then these resources can and you'll put all of your resources under this one VPC. So by doing this, by creating resources under so whenever you create the infrastructure, right, in a case where you're using some data form or something like that, you can create your own VPC. Okay? And then all of the other clouds, right, like, all of the other servers of yours will be using that VPC. So, and how do we secure that is basically, you will be allowing restricted access to them. Okay? You won't be allowing any other server or any public to access it. So that's how I would do it. Other than that, if we are looking at in terms of credentials, okay, so we can have, in AWS deployment, we can use secrets as well as, like, if you're using something like a Travis CI for doing an AWS requirement. You can save your secrets in that Travis CI file. So they will not be exposed to anyone. And that's how to securely log in to using a resource, suppose you have a database or suppose you have a file store. So based on both of these, you'll be using that and to do all of this stuff can be done using that. That is one way. Also, you can, like, in terms of deployment, that's how I would go with it. Like, I would be saving the secrets that way. Also, if you are looking in terms of Kubernetes or other deployments, okay, so you can then save your secrets in there. But in case of AWS, that's how I would go.
So dependency management, I mostly use Go mod. Okay. Now prior to this, we usually used dev, but now it's all about Go mod. And to avoid version conflicts, there are two ways of going about it. One way is to do vendor. Okay? So if you don't want your version to be affected, basically, what you would do is say "go mod vendor" and then create a vendor folder and then push that vendor folder. So your dependency versions won't change. Okay? Now let's just say you're talking about dependency versions in terms of version conflicts. Okay? So how would you avoid something like a version conflict? Let's just say if some developer has one version and you have another. Right? So in order to use that, you'd use Go mod. Okay? Then you would use Go mod tidy every time, so you would see whether all of the resources are working correctly or not. Okay? So let's say you have some sort of a GIN and then you have the dependency map. You have the version product. So I would say "go get" this version. I need this version. So I would say "go get" download this version. This will say, okay, I need a version greater than or equal to so and so. Okay? If I say this, then there will be hardly any version conflict. And to maintain a clean environment, one way is to do the vendor or the other way is to put your home mod into your VCS. Okay? And then we can handle this kind of situation.
So when we talk about go line, if I'm talking in terms of more microservice architecture, first of all, are you would you use distributed tracing with all of the errors? Okay? Like, when I'm in a situation where I have an error, I will be grabbing that error. Let's just say I get an error from the MySQL DB, and now that will be propagated to the service that will be propagated to the controller. So what I'll do is throw the error directly. Okay. Saying, the controller didn't work, but the service did. I would rather grab the error. So by grabbing the error, I will get exactly where the error failed. That's one way of knowing how it happened. Now in terms of maintainability, as you know, this would be much easier to maintain. With respect to robustness, I don't think there would be any issue in maintaining or with this not being robust. With respect to errors, right, like, now because we have a microservice showing an error. So how do I know which microservice actually threw that error? I will be using Elasticsearch logging. So I'll be logging the error, and the other part is I would be using distributed tracing. Distributed tracing will help me in identifying where the error actually occurred using the trace ID. That's one way of going about it. And, yes, there are other ways, if we are talking about robustness. I'm thinking it's more about how can we recover from the error. So, in this case, there's something called recovery. What we can do basically is instead of panicking, we can put it into recover. Let's just say we have an important piece of code. If it fails or if something happens, it's likely to panic. Although we should never try to avoid panic because if there is a panic, that means there's something wrong. But if we want to build a system like that, then we have to put it into recover. But just not just putting it into recover, but logging the actual error. So, also raising maybe an alert, like a Slack alert or an alert, something like that.
There are a lot of functions to do with this. A lot of libraries, okay, to implement rate limiting. So you can use those libraries basically to prevent the abuse on that. Also, one thing you can do is instead of these things hitting your server, you could do it at the API gateway level if that is possible, because most of the abuse will come from the services which are exposed to the public. Okay, so one way of doing that rate limiting is using some sort of Redis. You could have a Redis store which will keep track of accounts and then prevent them from doing it, or you can keep a load balancer in front of it and then say, okay, this is the amount of load it can handle, it shouldn't say no. But in case of Golang, there are a lot of things to prevent and abuse for. Like you could say the maximum buffer size or the maximum body size should be so much. Like too many or same client connections or same client IP you can restrict. Okay, so there are a lot of ways in doing this, but I would rather go if I'm going for rate limiting. I would be doing it based on IP because IP, if there is one, if someone is firing from one server itself, we can use the IP. In that case, you can also use the user agent. Okay, like sometimes what can happen is the IPs can be the same, but the user agent can be different. So again, because to separate those two, you can use a browser fingerprint basically to identify this kind of stuff. More for rate limiting. Other than that, like, if there are already 3rd party implementations, okay, which we can use to block any of these. Okay, block the IPs, block spam, block. You can also use a set of commonly used VPNs, which you get from IP 2 location. Basically, those can also be used to fix this.
So, basically, what is happening is we have created a main function, and the first part of it is, you are sending to a channel. Okay. There is no receiver for the channel, and you are trying to send to a channel. Now this channel is called an unbuffered channel. That means, basically, for this channel, if you send or receive, okay, like, in this case, since you're sending, and there is no receiver, it will block, okay, until a receiver is ready. But since you already sent to it and there is no goroutine running, which can unblock it, okay? So I have sent with the function, but there is no goroutine which will receive this because you have not found a goroutine. That's why it will definitely result in a deadlock. Okay. So to fix this, what you can do is run the goroutine code which is there. After the send, you can start it. Okay. And then what you can do is this will not sleep. Okay? It will then print it correctly.
First thing I would like to say with regards to this error, you don't know from which and what function it came from. Okay? So, basically, let's just say in the code, you are looking at this code. Right? Supposed to return my instructor there, but you don't know from where it came from. Okay? So I would then like to add certain functions. Okay? Like, you could wrap it with saying, okay. This came from fetch and pass. Okay? Because as you pass it, like, to the upstream or the upper code, it will no one will know from where this function came from. Other than that, if resource is not equal to nil, also, it would be better to do if resource is not equal to nil, even if error is not equal to nil, if there is some sort of body, then we can try to close it. And then if error is not equal to nil, return nil and error. So here in that error where we are returning, we can use error.wrap. So not errors or web. You can use error.wrap and then get this back. Okay. So to grab the error. Other than that, okay. So here also, now this will give you an error saying, cannot convert into JSON or some sort of error with decoding it. Okay? So if there is some sort of error with decoding, then you can do then you can throw a better error because this error is not clear. Okay? Here, that error won't actually specify what went wrong in a better way. Like, instead of throwing a MagalDA code, which will be difficult to read, that will make it better.
We're looking to handle a massive influx of API calls. By default, Go has its own goroutines. We'll have its own goroutines, and it will do the context switching on its own. But if we want to manage and let's just say we want to do some sort of rate limiting, so what do we do is basically we can put a queue in front of the request. This is something called an internal queue. So what happens? Let's just say we receive an API request. We don't directly give an API response to it. That is, we don't want a request-response warning. So it's just like a post call or something like that. So in that case, what we'll do is we'll take the request. We'll use it into the queue. We'll put it into the queue. And then we will slowly pop out from the queue. The first request as it is enqueued. And then it will be dequeued. So as in a queue, the first request gets the priority. So what it will do, it will take the request. Now let's just say we have some sort of context switching, which is more of an API code. So this will be handled by Go. And what we'll try to do is we'll say, okay, let it do its job, and we'll then try to get the next request. So let's just say that we have two requests. The first request we're handling, and it has to make some sort of other call. So in that case, what we can try to do is we can have some sort of lock, a mutex lock basically, and say, okay, now we can handle these many requests. This request is gone and doing something else. Now we say, okay, let's release the lock and let other requests come in. So what it will do is when it makes another call, the first request which was selected might make another call. At that point, instead of just waiting, we could do it normally. There are other ways of also doing it. It's something called pipelines. So, basically, what we can do is put a log and then tell the queue to fetch another request using another goroutine. So that's one way of doing it. That's how you control the context switching. The other way of doing something like this is, let's just say, we have a certain limit. If we have a certain limit, we can have a buffer channel. And say, okay, these many requests should be there. After that, we will wait for that channel to be full. If the channel is full, that means we cannot handle any more requests. Once the channel is released, then you will again pass the requests through that way. So we can have a follow-up wherein we are passing all of the requests. Let's just say we have only ten requests which we can handle. At that point of time, we'll say, okay, only ten requests from the queue will be done. The later ones, the next ones, which will be there, we will try to send on the channel, but it will be blocked because it is a buffer channel.
Experience in integrating whole lag applications with external services using the AWS SDK. Okay, I have actually used AWS SDK to sync up with other parties. Like, basically, if you are not using your own system and you have someone's SDK where they have given you an API key to work with, I've used it in one of those projects, but it was not a big project. It was I think 2 or 3 months, so it's not a big project wherein we used the Go application, making the call using the SDK. Okay? And then, yeah, I don't have so much experience in that.
So in Kubernetes, we can use the Kubernetes Autoscaler. Okay? So in that case, what we are trying to achieve is like we have let's just say we have Black Friday sales basically. In that case, we want our system to handle that big traffic. So by using the Kubernetes autoscaler, which will automatically scale it based on the metrics that you want to use. Suppose you want to use, like, CPU, suppose you want to use the average load, something like that. So based on that, you would automatically scale it. So it doesn't have much to do with Golang services. Okay? But it's got to do with how we would handle it in Kubernetes. Okay? So in Kubernetes, you can have that. And ideally, you can use that kind of scenario wherein we could auto scale based on the load. And I think that would, you know, actually be the better solution. And with regards to variable loads, right, like, this is something which is going to happen in case of ecommerce business, we are likely going to have it, so we can use that. Other than that, if we don't want to handle the load or we want to say, okay, after a certain point we don't want to, we can have some sort of system for that as well, like a rate limiting. Okay? So we can use rate limiting as well.