profile-pic
Vetted Talent

SAISH NAIK

Vetted Talent
I am qualified and professional developer with more than years of experience in building highly concurrent and available systems like adtech and telecom. Strong creative and analytical skills. Team player with an eye for detail.
  • Role

    FULL STACK DEVELOPER

  • Years of Experience

    9.9 years

  • Professional Portfolio

    View here

Skillsets

  • Docker - 5 Years
  • Microservices Architecture - 6 Years
  • JavaScript - 6 Years
  • Rest APIs - 9 Years
  • Go - 6 Years
  • SQL - 6 Years
  • Full Stack
  • Node Js
  • Kubernetes
  • Node
  • On
  • Backend
  • New Relic
  • AWS - 5 Years
  • Go Lang - 5 Years
  • MySQL
  • JS
  • Apache Spark
  • GCP
  • Mongo DB
  • Spark
  • RabbitMQ
  • Database
  • PHP
  • Mongo DB - 6 Years
  • Node Js - 5 Years
  • Go Lang - 5 Years

Vetted For

9Skills
  • Roles & Skills
  • Results
  • Details
  • icon-skill_image
    Senior Golang Engineer (Remote)AI Screening
  • 76%
    icon-arrow-down
  • Skills assessed :Communication, API development, Database Design, AWS, Go Lang, Kubernetes, Problem Solving Attitude, Redis, Security
  • Score: 68/90

Professional Summary

9.9Years
  • Jan, 2024 - Present2 yr 5 months

    Technical Lead

    Bristlecone
  • Jan, 2021 - Jan, 20243 yr

    Senior Software Engineer

    Circles.Life
  • Jan, 2016 - Jan, 20215 yr

    Senior Software Engineer

    Mobobeat
  • Jan, 2015 - Jan, 20161 yr

    Software Developer

    Kaves Technology and Anant Infomedia

Applications & Tools Known

  • icon-tool

    Golang

  • icon-tool

    Node.js

  • icon-tool

    PHP

  • icon-tool

    MySQL

  • icon-tool

    MongoDB

  • icon-tool

    Cassandra

  • icon-tool

    ELK Stack

  • icon-tool

    Docker

  • icon-tool

    Kubernetes

  • icon-tool

    GCP

  • icon-tool

    AWS

  • icon-tool

    RabbitMQ

Work History

9.9Years

Technical Lead

Bristlecone
Jan, 2024 - Present2 yr 5 months
    Leading the Flexera Cloud Cost Optimisation team of 8 members. Responsible for end to end delivery of the new Azure bill pipeline which reduced processing time by 40%. Developed a prototype and MVP for Azure MCA CSP bill consumption increasing stats visibility by 30%. Deployed Microservices Kubernetes cluster using Terraform on AWS EKS and Google Cloud for Azure bill pipeline to increase scalability of the system to 60%. Monitored the Azure bill pipeline system using Newrelic, Grafana and PagerDuty to reduce incidents by 20%. Created a test plan for the Azure bill pipeline which involved automated and manual testing, reducing the rollback percentage by half. Built and developed the whole cloud architecture of the new azure pipeline bill project from scratch. Successfully released the Azure bill pipeline to production with 0 downtime. Worked on technical backlog/debts such as go version update, newrelic integration etc increasing resilience and reliability of system by 50%. Conducted thorough code reviews making sure that the engineering of SOLID, YAGNI, Test Driven Development and others are always followed. Have one on ones and tech brainstorming sessions with junior developers to discuss latest technologies and resolve their queries. Supported both Restful and GRPC API with singular code using go grpc gateway reducing development effort by half. Introduced event driven architecture in microservices systems with RabbitMQ and Kafka reducing coupling by 30%.

Senior Software Engineer

Circles.Life
Jan, 2021 - Jan, 20243 yr
    Led the Telco domain development team and was a part of the architecture team during roadmap discussion. Golang, Postgres,MySQL(relational), Mongo(schema less) and ElasticSearch(ELK) were the major tools used in terms of language and database. Efficiently handled B2B client traffic increase from 0.5 million to 2 million and then from 2 million to 5 million by rigorously conducting performance tests and identifying bottlenecks. Integrated linting and automated testing into the CI/CD pipeline, increasing code quality and reducing bugs in production by 30%. Split legacy monoliths into microservices ensuring flexible scalability, independent development and deployment to Google Cloud and AWS Kubernetes cluster via Helm and Terraform thus decreasing time to market by at least 25%. Reduced the incident rate of subscription pipeline by 60% by introducing event driven architecture, resilience, fault tolerance and monitoring using golang, RabbitMQ, Kafka, New Relic and A/B testing. Developed observability, monitoring,logging and alerting systems and reduced mean time to resolution(MTTR) by 40% and improved system availability by 25% by using opsgenie, prometheus, grafana, newrelic and ELK stack. Designed and Implemented a fully automated ci/cd pipeline and reduced deployment time by 50% using Jenkins and bitbucket pipelines. Added auto recharge functionality to data add ons benefiting customers by removing the hassle of manual recharge and also increasing the overall revenue by 3x.

Senior Software Engineer

Mobobeat
Jan, 2016 - Jan, 20215 yr
    Migrated Real Time Bidder application from Node.js to golang increasing the qps by 6x. Split monolith into microservices architecture thus increasing scalability to serve 43 million requests per hour. Moved internal microservice communication from REST to gRPC thus improving performance by at least 20%. Added containerisation alongside Kubernetes thus improving availability of the system by 25%. Learned cassandra and used it as the traffic database to increase scalability and availability by 30%.

Software Developer

Kaves Technology and Anant Infomedia
Jan, 2015 - Jan, 20161 yr
    Built and managed CRM software for pharmaceutical companies reducing client tickets from 15 to 3 per day. Introduced what you see is what you get editor which helped in lowering formatting mistakes by 20%.

Achievements

  • Reduced processing time by 40%
  • Increased stats visibility by 30%
  • Increased scalability by 60%
  • Reduced incidents by 20%
  • Reduced rollback percentage by half
  • Released with 0 downtime
  • Increased resilience and reliability by 50%
  • Reduced development effort by half
  • Reduced coupling by 30%
  • Increased concurrency by 60%
  • Increased code quality and reduced bugs by 30%
  • Decreased time to market by 25%
  • Reduced incident rate by 60%
  • Reduced MTTR by 40%
  • Improved system availability by 25%
  • Reduced deployment time by 50%
  • Increased revenue by 3x
  • Increased qps by 6x
  • Improved performance by 20%
  • Improved availability by 25%
  • Increased scalability and availability by 30%
  • Reduced client tickets from 15 to 3 per day
  • Lowered formatting mistakes by 20%

Major Projects

9Projects

PUSH NOTIFICATION + RTB

    This project was created to generate push notifications ads along with a real time bidder system. This project was built using Nodejs, MySQL, Cassandra, MongoDB, Apache Spark, docker, kubernetes, gcp and aws. It was then rebuilt using golang.

Built white labeled CMS solution for pharmaceutical companies

AD SERVING PLATFORM

FAKE TRAFFIC GENERATOR

Built bot traffic generator

TELCO SERVICES

Addon subscription

Account orchestration for handling end to end flow with

RTB PLATFORM

Education

  • BACHELOR OF TECHNOLOGY

    NIT GOA (2015)

AI-interview Questions & Answers

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.