Evolving systems for new products

A common anti-pattern to avoid is preemptively optimizing systems for the future while still trying to establish the current market fit. It leads to slower iterations between product experiments.
Read more

Evolving systems for new products

  • A common anti-pattern to avoid is preemptively optimizing systems for the future while still trying to establish the current market fit. It leads to slower iterations between product experiments.
  • You can try to expedite the development by reusing existing systems and tooling.
  • Evaluate your business logic performed at read time to identify what data was shared with an application to enable better data modeling and quick, small product changes.
  • Be alert to scaling challenges and set new goals accordingly. For example, you might perform nightly load tests to catch issues and decide to reduce the complexity of a system to quickly develop on the backend in response to new feature requests.
  • For a design that lasts in the future, you might relate data in what used to be disparate stores so that a single request suffices instead of a string of orchestrated calls by a read service. You might need to modify your ETL pipeline to consolidate data (which can be complex and risky) for sharing and passing downstream. And while you migrate, you may want to use a dual write pattern to old and new databases, but it will reduce dependencies and make it easier to triage issues.

Full post here, 8 mins read

Improving resiliency and stability of a large-scale monolithic API service

The results of microclustering include the ability to limit downstream failures and bugs to a single vertical, and each cluster can be tuned independently of the others for better capacity planning, monitoring and granular control over deployment.
Read more

Improving resiliency and stability of a large-scale monolithic API service

Lessons from the API layer service used by LinkedIn:

  • They chose a cross-platform design (with all platforms using the same API and same endpoints for the same features) and an all-encompassing design (one API service calls all product verticals), to allow for high code reuse.
  • They reused data-schema definitions and endpoints to make it easier for engineers to collaborate but it led to issues at scale, when extended to deployment architecture. It was addressed by microclustering rather than breaking the monolith into microservices: Endpoints of the services were partitioned without breaking the code, routing traffic for each partition to a dedicated cluster of servers. Data from monitoring systems were used to identify which verticals had enough traffic to justify a partition.
  • For each vertical, the build system was modified to create an additional deployable named after the vertical, with configuration inherited from the shared service and extended. Traffic from the vertical’s endpoints was examined to estimate the number of servers needed in the new cluster.
  • While deploying, capacity testing was carried out - when there was enough traffic to overload at least three servers, servers were slowly taken down to observe latencies and error rates, revealing how many queries-per-second each server could process without incident. This information was used for capacity planning, to fine-tune resource allocation.
  • The results of microclustering include the ability to limit downstream failures and bugs to a single vertical, and each cluster can be tuned independently of the others for better capacity planning, monitoring and granular control over deployment.

Full post here, 5 mins read

The differences between gateway, microgateway and service mesh

An API gateway is a central interface for all external communications. It typically works by invoking multiple microservices and aggregating results to determine the best path.
Read more

The differences between gateway, microgateway and service mesh

  • An API gateway is a central interface for all external communications. It typically works by invoking multiple microservices and aggregating results to determine the best path.
  • It may also handle authentication, input validation and filtering, and metric collection, as well as transforming requests and/or results. For the microservices network, it offers lower latency, better efficiency and higher security, as well as easier isolation of single sources of failure.
  • API microgateways are proxies sitting close to microservices for internal communication between microservices, allowing better governance, discovery, observability, and stability for developers and expose the policy enforcement point and security controls to operators.
  • They are a more granular solution than a single API gateway due to the control of exposure. They offer low latency and a small footprint, as requests don’t need to wait their turn. This does imply code duplication across multiple microservice instances, which can be inefficient if code is not intelligently structured.
  • A service mesh is a layer between microservices for all service-to-service communication that replaces direct communication between services. It will often have in-built support for resiliency, error checking, and service discovery. It is similar to a microgateway but with network communications entirely abstracted from business logic, allowing developers to focus entirely on the latter.

Full post here, 8 mins read

To create an evolvable API, stop thinking about URLs

To build an evolvable API, instead of forcing clients to have prior knowledge of URLs, fields and HTTP methods, you should let the client ask the server what is required to complete an operation and indicate the preferred host and path.
Read more

To create an evolvable API, stop thinking about URLs

  • To build an evolvable API, instead of forcing clients to have prior knowledge of URLs, fields and HTTP methods, you should let the client ask the server what is required to complete an operation and indicate the preferred host and path.
  • Critical aspects of evolvable API include:

a) The state of the conversation being stored in the network - not sourced from either client or server.

b) No versioning needed - when you add or remove data from a response, clients should know how to react. If they don’t know how to react to a new feature, they should be able to ignore it and work in the old way.

c) The server owns actions which contain values for URLs, methods, and fields, so that they control where clients go to continue the conversation, with only the entry point hardcoded in the client.

  • With control of URLs in the server, it can run A/B testing and direct clients to different servers running the same instance of the application. The server can also implement a polling functionality to track the status of requests.
  • Model communication on how people actually operate. Think not only about a generic language but developing a shared domain vocabulary.

Full post here, 10 mins read

An overview of caching methods

The most common caching methods are browser caching, application caching and key-value caching. Browser caching is a collaboration between the browser and the web server and you don’t have to write any extra code.
Read more

An overview of caching methods

  • The most common caching methods are browser caching, application caching and key-value caching.
  • Browser caching is a collaboration between the browser and the web server and you don’t have to write any extra code. For example - in Chrome when you reload a page you have visited before, the date specified under ‘expires’ in the 'Responses' header determines whether the browser loads resources directly from cache (from your first visit) or requests the resources again from the server. The server uses the headers passed by the browser (headers like If-modified-since or If-none-match or Etag) to determine whether to send the resources afresh or ask the browser to load from its cache.
  • Application-level caching is also called memoization and it is useful if your program is very slow. Think of cases where you are reading a file and extracting data from it or requesting data from an API. The results of any slow method are placed in an instance variable and returned on subsequent calls to the method. This speeds up the method. Though the downsides to this kind of caching are that you lose the cache on restarting the application and you cannot share the cache between multiple servers.
  • Key-value data caching takes memoization a step further with dedicated databases like memcache or Redis. This allows cached data to persist through user requests (allowing data sharing) and application reboots, but does introduce a dependency to your application and adds another object to monitor.
  • To determine the best method for you, start with browser caching as the baseline. Then identify your hotspots with an application profiling tool before choosing which method to grow with to add a second layer of caching.

Full post here, 7 mins read

Designing resilient systems beyond retries: rate limiting

You can limit requests by client or user account or by endpoints. These can be combined to use different levels of thresholds together, in a specific order, culminating in a server-wide threshold possibly.
Read more

Designing resilient systems beyond retries: rate limiting

  • In distributed systems, a circuit-breaker pattern and retries are commonly used to improve resiliency. A retry ‘storm’ is a common risk if the server cannot handle the increased number of requests, and a circuit-breaker can prevent it.
  • In a large organization with hundreds of microservices, coordinating and maintaining all the circuit-breakers is difficult and rate-limiting or throttling can be a second line of defense.
  • You can limit requests by client or user account (say, 1000 requests per hour each and then reject requests till the time window resets) or by endpoints (benchmarked to server capabilities so that the limit applies across all clients). These can be combined to use different levels of thresholds together, in a specific order, culminating in a server-wide threshold possibly.
  • Consider global versus local rate-limiting. The former is especially useful in microservices architecture because bottlenecks may not be tied to individual servers but to exhausted downstream resources such as a database, third-party service, or another microservice.
  • Take care to ensure the rate-limiting service does not become a single point of failure, nor should it add significant latency. The system must function even if the rate-limiter experiences problems, and perhaps fall back to its local limit strategy.

Full post here, 11 mins read

Distributed systems learnings

Building a new distributed system is easier than migrating the old system over to it. Migrating an old system is more time-consuming and just as challenging as writing one from scratch.
Read more

Distributed systems learnings

  • Building a new distributed system is easier than migrating the old system over to it. Migrating an old system is more time-consuming and just as challenging as writing one from scratch. You tend to underestimate the amount of custom monitoring needed to ensure they both work the same way and a new system is more elegant, but you need to decide whether to accommodate or drop edge cases from the legacy system.
  • To improve reliability, start simple, measure, report and repeat: establish simple service-level objectives (SLOs) and a low bar for reliability (say 99.9%), measure it weekly, fix systemic issues at the root of the failure to hit it, and once confident, move to stricter definitions and targets.
  • Treat idempotency, consistency and durability changes as breaking changes, even if technically not, in terms of communication, rollouts, and API versioning.
  • Give importance to financial and end-user impacts of outages over the systems. Talk to the relevant teams and use appropriate metrics, and use these to put a price tag on preventive measures.
  • To determine who owns a service, check who owns the oncall(the operating of the system). The rest - code ownership, understanding of the system - follow from there. This means that shared oncall between multiple teams is not a healthy practice but a bandage solution.

Full post here, 6 mins read

An introduction to load testing

Common parameters to test should include server resources (CPU, memory, etc) for handling anticipated loads; quickness of response for the user; efficiency of application; the need for scaling up hardware or scaling out to multiple servers; and maximum requests per second.
Read more

An introduction to load testing

  • Load testing is done by running the software on one machine (or cluster of machines) to generate a large number of requests to the webserver on a second machine (or cluster).
  • Common parameters to test should include server resources (CPU, memory, etc) for handling anticipated loads; quickness of response for the user; efficiency of application; the need for scaling up hardware or scaling out to multiple servers; particularly resource-intensive pages or API calls; and maximum requests per second.
  • In general, a higher number of requests implies higher latency. But it is a good practice in real life to test multiple times at different request rates. Though a website can load in 2-5 seconds, web server latency should typically be around 50-200 milliseconds. Remember that even ‘imperceptible’ improvements add up in the aggregate for a better UX.
  • As a first step, monitor resources - mostly CPU load and free memory.
  • Next, find the maximum response rate of your web server by setting desired concurrency (100 is a safe default but check settings like MaxClients, MaxThreads, etc for your server) and test duration in any load testing tool. If your software only handles one URL at a time, run the test with a few different URLs with varying resource requirements. This should push the CPU idle time to 0% and raise response times beyond real-world expectations.
  • Dial back the load and test again for how your server performs when not pushed to its absolute limit: specify exact requests per second, and cut your maximum requests from the earlier step in half. Step up or down requests by another halfway each time till you reach your maximum for acceptable latency (which should be in the 99th or even 99.999th percentile).
  • Some options among load-testing software you can explore - ab (ApacheBench), JMeter, Siege, Locust, and wrk2.

Full post here, 13 mins read

How to continuously profile tens of thousands of production servers

Some lessons & solutions from the Salesforce team that can be useful for other engineers too.
Read more

How to continuously profile tens of thousands of production servers

Some lessons & solutions from the Salesforce team that can be useful for other engineers too.

  • Ensure scalability: If writes or data are too voluminous for a single network or storage solution to handle, distribute the load across multiple data centers, coordinating retrieval from a centralized hub for investigating engineers, who can specify which clusters of hosts they may want data from.
  • Design for fault-tolerance: In a crisis where memory and CPU are overwhelmed or network connectivity lost, profiling data can be lost too. Build resilience in your buffering and pass the data to permanent storage, while allowing data to persist in batches.
  • Provide language-agnostic runtime support: If users might be working in different languages, capture and represent profiling and observability data in a way that works regardless of the underlying language. Attach the language as metadata to profiling data points so that users can query by language and ensure data structures for stack traces and metadata are generic enough to support multiple languages and environments.
  • Allow debugging engineers to access domain-specific contexts to drive their investigations to a speedier resolution. You can do a deep search of traces to match a regular expression, which is particularly useful to developers debugging the issue at hand.

Full post here, 9 mins read

Benefits of dependency injection

It improves code maintainability. Stand-alone classes are easier to fix than complicated and tightly coupled classes.
Read more

Benefits of dependency injection

  • It improves code maintainability. Stand-alone classes are easier to fix than complicated and tightly coupled classes.
  • It improves code quality by improving code testability. If it is easy to test code, it will get tested more often which will lead to higher quality codebase.
  • Dependency injection makes code more readable as the classes used are small, to the point, compact and more clearly defined.
  • When you use dependency injection, you get loosely coupled code that is more flexible. Small classes that do one thing can more easily be reassembled and reused, which in turn saves time and money.
  • It leads to a more extendable class structure.
  • It facilitates team development as after defining abstractions, teams working together can write their code using the abstractions, even before implementations are written.

Full post here, 4 mins read

How to improve a legacy codebase

Begin with a backup - copy everything to a safe place in read-only mode. And check if the codebase has a build process and that it actually produces what runs in production.
Read more

How to improve a legacy codebase

  • Begin with a backup - copy everything to a safe place in read-only mode. And check if the codebase has a build process and that it actually produces what runs in production.
  • Freeze the DB schema until you are done with the first level of improvements. It allows you to compare the effect your new business logic code has compared to the old business logic code.
  • When adding instrumentation to the old platform in a completely new database table, add a simple counter for every event and a single function to increment these counters based on the name of the event.
  • Never try improving both the maintainability of the code or the platform it runs on at the same time as adding new features or fixing bugs. It will invalidate some of the tests you made earlier.
  • When migrating to a new platform, all business logic and interdependencies should remain exactly the same as before.
  • Test the new DB with the new code and all the tests in place to ensure your migration goes off without a hitch.

Full post here, 11 mins read

Words are hard - an essay on communicating with non-programmers

When communicating with people outside of the programming world, stay away from using technical jargon. It can make people feel excluded and it can confuse them.
Read more

Words are hard - an essay on communicating with non-programmers

  • Remember communication is complete when you are understood and not when you have said what you had to say. When communicating with people outside of the programming world, stay away from using technical jargon. It can make people feel excluded and it can confuse them.
  • It’s often necessary to simplify things. Be respectful, and never condescending, while doing that. Try explaining things in a step by step fashion, mention what edge cases are you considering with an example or two, and present a generalised gist.
  • Before an important meeting with non-technical stakeholders, work with a non-technical person as a sounding board to help you see if you’re making sense to your audience.
  • Try to personify or use analogies when explaining yourself. Use visual analogies - draw diagrams, tables, charts, flowcharts and the like to help illustrate your points.
  • When explaining performance metrics, find a middle ground between accuracy and understandability.

Full post here, 14 mins read

The Joel Spolsky Test: 12 Steps to Better Code

Do you use source control? Can you make a build in one step? Do you fix bugs before writing new code?
Read more

The Joel Spolsky Test: 12 Steps to Better Code

You get 1 point for each “yes”. Score of 12 is perfect, 11 is tolerable, but 10 or lower and you’ve got serious problems:

  1. Do you use source control? Source control makes it easier for programmers to work together.
  2. Can you make a build in one step? If the process takes any more than one step, it is prone to errors.
  3. Do you make daily builds? It makes sure no breakage goes unnoticed.
  4. Do you have a bug database? If you haven’t been listing all known bugs in the code, you will ship low-quality code.
  5. Do you fix bugs before writing new code? The longer you wait before fixing a bug, the costlier - both in time and in money - it is to fix.
  6. Do you have an up-to-date schedule? The only way to factor in planning decisions is to have a schedule and to keep it up to date.
  7. Do you have a spec? Once the code is written, the cost of fixing problems is dramatically higher.
  8. Do programmers have quiet working conditions? Knowledge workers work best by getting into ‘flow, or ‘‘in the zone’.
  9. Do you use the best tools money can buy? Getting the best machines will stop programmers from getting bored while the compiler runs.
  10. Do you have testers? Skimping on testers is a false economy.
  11. Do new candidates write code during their interview? Would you hire a caterer for your wedding without tasting their food?
  12. Do you do hallway usability testing? Grabbing the next person that passes by in the hallway and ask them to try to use the code you just wrote.

Full post here, 16 mins read

How to refactor a monolithic codebase over time

If source code is not stored under version control, get it under version control. Check for static code analysis. If there is no test suite, build that before you refactor. If
Read more

How to refactor a monolithic codebase over time

  • Understand the application thoroughly. Talk to previous developers, business owners, PMs, etc. Read through code comments, code commit messages, README files, documentation, wikis. Checking the bug-reporting tool used as well. Put all the learning together.
  • If source code is not stored under version control, get it under version control. Check for static code analysis.
  • If there is no test suite, build that before you refactor. If there is a test suite, understand the level of code coverage. Check how long it takes to complete the suite, whether it exhausts available memory, how many tests fail, are skipped or are outdated, whether there is a good mix of unit, integration and functional tests, whether there are sections of codebase escaping coverage. Also, look for comments indicating something that was to be fixed later.
  • Begin refactoring, keeping in mind that your code will never be perfect. So know when to move on.
  • To clean up a complex codebase, sometimes you need to make seemingly trivial changes. But most of the changes should have a clear, effective purpose, such as creating a new feature or fixing a bug or defect.
  • Work to a project plan, with a series of achievable tasks, a realistic timeline, and resource requirement, sufficient staff to work on the tasks in isolation or in parallel with other projects.

Full post here, 8 mins read

The best ways to test your serverless applications

For the serverless functions you write, test for each of the following risks: configuration (databases, tables, access rights), technical workflow (parsing and using incoming requests, handling of successful responses and errors), business logic and integration.
Read more

The best ways to test your serverless applications

  • For the serverless functions you write, test for each of the following risks: configuration (databases, tables, access rights), technical workflow (parsing and using incoming requests, handling of successful responses and errors), business logic and integration (reading incoming request structures, storage order in databases).
  • Break up functions into hexagonal architecture (ports and adapters) with separation of concerns through layers of responsibility.
  • For unit tests, use a local adapter or mock as an adapter to test the function business layer in isolation.
  • Use adapters to simulate to test integration with third-party end services. Save memory and time by testing not for full integration but file storage integration with the in-memory adapter.
  • For proper monitoring of integrations, use back-end tools such as IOpipe, Thundra, Dashbird, Epsagon, etc., and front-end tools such as Sentry or Rollbar. You can also use an open-source error tracking app such as Desole that you install in your AWS account.

Full post here, 10 mins read

How to measure the reliability of your software throughout the CI/CD workflow

Look beyond log files and testing to determine quality of code: set up advanced quality gates to block problematic code from passing to the next stage and use feedback loops to inform more comprehensive testing.
Read more

How to measure the reliability of your software throughout the CI/CD workflow

  • In addition to CI/CD, you should consider incorporating continuous reliability in the workflow. This may mean more focus on troubleshooting than on writing code.
  • Consider whether to automate every step, or even whether some steps should be automated more than others.
  • Look beyond log files and testing to determine quality of code: set up advanced quality gates to block problematic code from passing to the next stage and use feedback loops to inform more comprehensive testing.
  • In addition to log aggregators and performance monitoring tools, get a more granular understanding of app quality by ensuring you can access the source code, variable state and stack trace at the time of an error. Aggregate this data across the app, library, class, deployment or another boundary for an insight into the functional quality of the code.
  • Based on this data, you can categorise known, reintroduced and unknown errors, classify events, understand frequency and failure rates, enabling you to write more comprehensive tests for development and pre-production environments alike, driving the higher code quality.

Full post here, 6 mins read

Our adventures in scaling

Handling sudden activity spikes poses different challenges than scaling a rapidly growing user base. Check whether databases are resource-constrained and hence slowing down. Check hardware metrics during spikes to check on CPU, disk i/o and memory.
Read more

Our adventures in scaling

  • Handling sudden activity spikes poses different challenges than scaling a rapidly growing user base.
  • Check whether databases are resource-constrained and hence slowing down. Check hardware metrics during spikes to check on CPU, disk i/o and memory.
  • If there are no spikes in those metrics, look higher up the infrastructure stack at service resources for increased resource acquisition times. Also, check the garbage collection activity, which indicates whether JVM heap and threads are the bottlenecks.
  • Check network metrics next to look for a constraint in the network between services and databases - for example, if the services’ database connection pools are consistently reaching size limits.
  • To collect more metrics, log the latency of all transactions and collect those higher than a defined time, which should be analysed across daily usage to determine whether removing the identified bottleneck would make a significant difference.
  • Some of the bottlenecks may be code-related, for example, inefficient queries, a service is resource-starved, inconsistencies in database response itself - so look for metrics on higher-level functioning and not just low-level system components.

Full post here, 6 mins read

Migrating functionality between large-scale production systems seamlessly

Incorporate shadowing to forward production traffic to the new system for observation, making sure there would be no regressions. This lets you gather performance stats as well.
Read more

Migrating functionality between large-scale production systems seamlessly

Lessons from Uber’s migration of its large and complex systems to a new production environment:

  • Incorporate shadowing to forward production traffic to the new system for observation, making sure there would be no regressions. This lets you gather performance stats as well.
  • Use this opportunity to settle any technical debt incurred over the years, so the team can move faster in the future and your productivity rises.
  • Carry out validation on a trial and error basis. Don’t assume it will be a one-time effort and plan for multiple iterations before you get it right.
  • Have a data analyst in your team to find issues early, especially if your system involves payments.
  • Once confident in your validation metrics, you can roll out to production. Uber chose to start with a test plan with a couple of employees dedicated to testing various success and failure cases, followed by a rollout to all Uber employees, and finally incremental rollout to cohorts of external users.
  • Push for a quick final migration, as options for a rollback are often misused, preventing complete migration.

Full post here, 6 mins read

How to optimize your website speed by improving the backend

Normalize relational databases at the design stage itself and ensure effective indexing so the indexes don’t slow down your website. In some cases, denormalization is more effective though - where there are many table joins, adding an extra field to one table may be better
Read more

How to optimize your website speed by improving the backend

  • The N+1 query problem slows down many apps when several queries are issued to linked fields in a database. You can use the ActiveRecord ORM tool in Rails that employs eager loading of all associated elements with a single query to help solve this problem.
  • Normalize relational databases at the design stage itself and ensure effective indexing so the indexes don’t slow down your website. In some cases, denormalization is more effective though - where there are many table joins, adding an extra field to one table may be better or adding calculated values you need often to a table can help if you frequently execute complicated calculations.
  • Cache carefully to speed up your site. For SQL caching in Rails, use low-level caching to store query results for a longer time. In general, prefer fragment caching of page blocks for dynamic web apps, use page caching in Rails with the actionpack-page_caching gem, but avoid it if your web has frequently updated content like news feeds. For authentication actions and error messages, use the actionpack-action_caching gem.
  • Use a content delivery network (CDN) of edge servers to cache static content like images, JavaScript, and CSS files for reduced latency across geographies, reduced operational costs compared to handling your own servers, stability and scalability.

Full post here, 11 mins read

Simple Java performance tuning tips

Use primitive types rather than wrapper classes wherever possible to minimize overheads as they are stored to the stack and not the heap.
Read more

Simple Java performance tuning tips

  • To start optimizing your app, use a profiler to find the real bottlenecks in the code and then create a performance test suite for the whole application based on that information. Run your tests before and after every attempt at optimization.
  • Use primitive types rather than wrapper classes wherever possible to minimize overheads as they are stored to the stack and not the heap. Avoid BigInteger and BigDecimal as they dramatically slow down calculations and use a lot of memory.
  • If your app uses a lot of replace operations and you aren’t updated to the latest version of Java, consider the Apache Commons StringUtils.replace method rather than String.replace. You can make the change easily by adding a Maven dependency for Apache’s Commons Lang to your app’s pom.xml to replace all instances.
  • Cache especially your more expensive resources or most-used snippets of code, such as database connections or the valueOf method for the Integer class. However, you are creating an overhead and you may need to manage the cache to keep it accessible and remove outdated information, so be sure the tradeoff is worthwhile.

Full post here, 9 mins read

Tips for 10x application performance

Cache both static and dynamic content to reduce the load on application servers. Use established compression standards to reduce file sizes for photos, videos, and music. Avoid leaving text data, including HTML, CSS, and JavaScript uncompressed.
Read more

Tips for 10x application performance

  • Accelerate and secure applications with a reverse proxy server to free up the application server from waiting for users to interact with it. It is also a prerequisite for many other performance increasing capabilities - load balancing, caching static files, and for better security & scalability too.
  • Apply load balancing to protocols such as HTTP, HTTPS, SPDY, HTTP/2, WebSocket, FastCGI, SCGI, uwsgi, memcached, TCP-based applications, Layer 4 protocols etc.
  • Cache both static and dynamic content to reduce the load on application servers.
  • Use established compression standards to reduce file sizes for photos, videos, and music. Avoid leaving text data, including HTML, CSS, and JavaScript uncompressed as their compression can have a large effect especially over slow or otherwise constrained connections. If you use SSL, compression reduces the amount of data to be SSL-encoded, saving time.
  • Monitor real-world performance closely, in real-time, both within specific devices and across your web infrastructure. You should use global application performance monitoring tools to check page load times remotely and also monitor the delivery side.

Full post here, 20 mins read

What is clean code?

Put in the extra effort today to refactor and test your code, in order to save yourself (and others) pains tomorrow. Poorly crafted code unravels fast, while high-quality code saves money and builds customer loyalty while reducing technical debt.
Read more

What is clean code?

Few key ideas from Robert C. Martin’s Clean Code:

  • Even though perfect code is an illusion, understand that craftsmanship matters because high-quality (thoughtful, flexible, maintainable) code results in long-term payoffs for the business. Code that ‘just works’ may only offer short-term success.
  • Put in the extra effort today to refactor and test your code, in order to save yourself (and others) pains tomorrow. Poorly crafted code unravels fast, while high-quality code saves money and builds customer loyalty while reducing technical debt.
  • Take pride in your work but recognize that your code is not your own and must be used and understood easily by others. So, avoid clever hacks and sleights of hand no matter how much fun they seem while coding. Focus on code that’s simple in implementation, readable (with consistent naming conventions, spacing, structure, and flow), considerate of future consumers and professionals, tested, relentlessly factored and SOLID (following the principles for longevity, maintainability, and flexibility).
  • Remember that the best way to write clean code is to do it all the time so that you retain and refresh the skill continually - even on your personal projects.

Full post here, 6 mins read

How to write good code documentation

There is no such thing as self-documenting code but your code needs to be self-explanatory. Invest time to review your work and write clean, structured code. It is less likely to contain bugs and will save time in the long run.Ensure you practice continuous documentation within your development process
Read more

How to write good code documentation

  • There is no such thing as self-documenting code but your code needs to be self-explanatory. Invest time to review your work and write clean, structured code. It is less likely to contain bugs and will save time in the long run.
  • Ensure you practice continuous documentation within your development process so that it is appropriately prioritized and is written, reviewed and delivered on time with the code.
  • You might write low-level tests for specific scenarios before the code, and leave architecture, user and support documentation to the end of the release cycle when all information is known and frozen. But store it all in one place and keep it up to date.
  • Get feedback on your documentation too - both as a health check and for clarity and comprehensiveness - and incorporate it. One of the best ways to do this is Jason Freedman’s 30/90 feedback method. At 30% completion, ask a reviewer to look at the broad outline, flow, and structure of document. At 90% have them go over it with a fine-toothed comb. Have peer, user and expert sessions in between.

Full post here, 6 mins read

Embracing the chaos of chaos engineering

You start with a hypothesis and you make an educated guess of what will happen in various scenarios, including deciding on your steady-state. Then you introduce real-world events to test your guesswork.
Read more

Embracing the chaos of chaos engineering

  • You start with a hypothesis and you make an educated guess of what will happen in various scenarios, including deciding on your steady-state.
  • Then you introduce real-world events to test your guesswork for hardware/VM failure, state inconsistency, running out of processing power or memory or time, dependency issues, rare conditions, traffic spikes, and service unavailability.
  • After that comes doing test runs in production on the properly pretested codebase (though be cautious of doing this to safety-critical systems such as banking) and then complete your hypothesis based on how real-world events affect your steady-state.
  • You should communicate your results not only to engineers but also to support staff and community managers who face the public.
  • Use different tools to run your experiments and ensure you have alerts & reporting systems in place to minimize potential damage. Abort quickly if needed.
  • Once you have defined ideal metrics and potential effects, increase the scope of testing by changing the parameters or events you test each time, applying fixes as you go till you find the points where the system really starts to break down.

Full post here, 6 mins read

Sampling in observability

Subcomponents of a system may need different sampling strategies, and the decision can be quite subjective.
Read more

Sampling in observability

  • You can use sampling APIs by way of instrumentation libraries that let you set sampling strategies or rates. For ex, Go’s runtime.setCPUProfileRate, which lets you set CPU profiling rate.
  • Subcomponents of a system may need different sampling strategies, and the decision can be quite subjective: for a low-traffic background job, you might sample every task but for a handler with low latency tolerance, you may need to aggressively downsample if traffic is high, or you might sample only when certain conditions are met.
  • Consider making the sampling strategy dynamically configurable, as this can be useful for troubleshooting.
  • If collected data tracks a system end to end and the collection spans more than one process, like distributed traces or events, you might want to propagate the sampling decision from parent to child process through the header passed down.
  • If collecting data is inexpensive but transferring or storage are, you can collect 100% of the data and apply a filter later to minimize while preserving diversity in the sample, retaining edge cases specifically for debugging.
  • Never trust a sampling decision propagated from an external source; it could be a DOS attack.

Full post here, 4 mins read

The 3 myths of observability

A myth is that getting an observability tool is a good strategy - Having an observability platform is not sufficient on its own. Unless observability becomes core to your engineering efforts your company culture, no tool can help.
Read more

The 3 myths of observability

  • Myth #1 is that you will experience fewer incidents if you implement an observability strategy - Just implementing a strategy has no impact on the number of event occurrences but having it in place means that when a problem arises, you will have enough telemetry data to quickly solve it.
  • Myth #2 is that getting an observability tool is a good strategy - Having an observability platform is not sufficient on its own. Unless observability becomes core to your engineering efforts your company culture, no tool can help.
  • Myth #3 is that implementing observability is cheap. As observability is a core part of any modern tech infrastructure, you should think of your observability budget as a percentage of your overall infrastructure budget. The value derived from a good observability program in terms of efficiency, speed, and customer satisfaction surpasses the costs it incurs.

Full post here, 4 mins read

Improving incident retrospectives

Often, too much focus is on triggers for the incident. The retrospective should instead review the timeline of incidents, remediation items and find owners for the remediation items.
Read more

Improving incident retrospectives

  • Incidents retrospectives are an integral part of any good engineering culture.
  • Often, too much focus is on triggers for the incident. The retrospective should instead review the timeline of incidents, remediation items and find owners for the remediation items.
  • Retrospectives should be used as an opportunity for deeper analysis into systems (both people and technical) and assumptions that underlie these systems.
  • Finding remediation items should be decoupled from the retrospective process. It helps participants to be free in conducting a deeper investigation as they are unburdened from finding any shallow explanations quickly.
  • It’s a good practice to lighten up the retrospective template you are using because any template will be unequipped to capture unique characteristics of varied incidents. Also, sticking rigidly to a template means limits open-ended questions that can be quite useful in evolving your systems in the right direction.

Full post here, 6 mins read

Why API responses should be signed

As a recipient of any data, you want to know who originally published it and be sure it was not tampered with to establish authenticity. This can be achieved by adding signatures to validate messages.
Read more

Why API responses should be signed

  • As a recipient of any data, you want to know who originally published it and be sure it was not tampered with to establish authenticity. This can be achieved by adding signatures to validate messages.
  • One option is to keep the signature and the message separate, requested by different API calls, to reduce complexity for the server so that it only makes the second call if the user demands it. Storage can be complicated with this approach.
  • The second option is to include the signature with the message, which you must encode first, but that renders the response no longer human-readable and the response must be decoded for interpretation.
  • A third option is to sign only critical parts of the response rather than all the metadata. This is easiest to implement, simple to parse for both humans and computers, but sometimes the metadata itself may be important information to verify.
  • In all the above options, the API provider must securely manage cryptographic keys, which is expensive and complicated, and the API can be compromised if a hacker gets hold of the keys.
  • To solve the problem effectively, you could checkout JOSE. It is a suite of specifications, including JSON web tokens which are already used across the internet mostly to sign OAuth logins.

Full post here, 5 mins read

Improving Mongo performance by managing indexes

To define an efficient index, you can build on top of a previously defined index as well. When you are compound indexing in this way, determine which property of your query is the most unique and give it a higher cardinality.
Read more

Improving Mongo performance by managing indexes

  • You can query large collections efficiently by defining an index and ensuring it is built in the background.
  • To define an efficient index, you can build on top of a previously defined index as well. When you are compound indexing in this way, determine which property of your query is the most unique and give it a higher cardinality. This higher cardinality will help in limiting the search area of your query.
  • To ensure your database uses your index efficiently, ensure the index fits in the available RAM on your database server as part of Mongo’s working set. Check this using the db.stats().indexSize and determining your default allocation of RAM.
  • To keep index sizes small, examine the usage of indexes of a given collection and remove the unused ones, examine compound indexes to check whether some are redundant, make indexes sparser by imposing a $partialFilterExpression constraint to tell them which documents to use, and minimize fields in compound indexes.

Full post here, 9 mins read

The good and bad of serverless

The good It’s truly scalable & saves you from the pains of managing servers manually. Serverless applications are a notch above Virtual Private Servers - you only pay for what you need.
Read more

The good and bad of serverless

The good

  • It’s truly scalable & saves you from the pains of managing servers manually.
  • Serverless applications are a notch above Virtual Private Servers - you only pay for what you need.
  • Developers on your team don’t have to deal with the technicalities of setting up scaling policies or configuring load balancers, VPCs, server provisioning, etc.

The bad

  • Cold starts when a function has been idle. To solve it, ping your functions periodically to ensure they’re always warm or set up a single function to handle all API calls in order to ensure that cold-starts only happen once.
  • The need for applications to be truly stateless. You must design your application to be ready to serve a request from a cold, dead state.
  • Not ideal for long-running jobs. Re-examine whether the time limit hinders your ability to process all the data or try using Lambda recursively.

Full post here, 9 mins read

API profiling at Pinterest

Common profiling measurements are CPU, memory, and frequency of function calls. There are two approaches to taking these measurements - event-based profiling & statistical profiling.
Read more

API profiling at Pinterest

  • Common profiling measurements are CPU, memory, and frequency of function calls. There are two approaches to taking these measurements - event-based profiling & statistical profiling.
  • In event-based profiling, you track all occurrences of certain events such as function calls, returns and thrown exceptions. Statistical profiling is about sampling data by probing the call stack periodically. And it is less accurate but faster, with lower overheads.
  • Pinterest’s API gateway service is written in Python. So, for memory profiling, tracemalloc package was used to track memory blocks.
  • To calculate operational costs, Pinterest needed to combine resource utilization data and request metrics that show the popularity of each endpoint. This helped them identify the most costly endpoints and they also identified the engineers/teams they belonged to. This encouraged ownership and proactive performance monitoring by the respective teams.
  • Dead code - unused, unowned code such as old experiments, tests and files, even lines of code in a file never actually called on in practice - can clutter repositories. Pinterest used a standard Python test coverage tool to identify dead code and then got rid of it.

Full post here, 7 mins read

What I talk about when I talk about logging

Separate production and logging (collecting, handling and archiving) so that log analysis does not create an additional load on production systems and also, logs are safeguarded from attackers trying to hide their trail.
Read more

What I talk about when I talk about logging

  • Analyzing logs is as, or more, important than logging. Only log what you intend to analyze.
  • Separate production and logging (collecting, handling and archiving) so that log analysis does not create an additional load on production systems and also, logs are safeguarded from attackers trying to hide their trail.
  • Transport logs to a centralized log server with appropriate access rights and archiving policies. Also, preserve the logs as raw as possible for later analysis and do not aggregate them in earlier phases.
  • Before log analysis, ensure you have created a clear understanding of your system’s baseline behavior. You will then know what to log, how long to retain the logs, and can add flexible tools to help you analyze the logs quickly and effectively in any format.
  • Enable automated reporting of event occurrences after setting baselines and thresholds. This way, you will be sure to look at logs whenever something important transpires.

Full post here, 6 mins read

Modernizing your build pipelines

Keep your pipeline highly visual and avoid over-abstraction. Visualization makes builds easy to understand and allows failed builds to be traced back quickly.
Read more

Modernizing your build pipelines

  • A high-quality pipeline must be fast. This needs quick feedback. To achieve this, let your CI tool parallelize all tasks that don’t have mutual dependencies and avoid running multiple checks together.
  • Have pipelines reflect in the code and call shell scripts that also work locally for easier testing before pushing to deploy, enabling a faster feedback loop.
  • To ensure your pipeline is reliable and reproducible, use containers to run each task in isolation and build the containers within the pipeline, a fresh container at each step.
  • While a persistent workspace saves time, it can build in flakiness, for which a good tradeoff may be improving speed by caching dependencies instead of downloading them each time.
  • Keep your pipeline highly visual and avoid over-abstraction. Visualization makes builds easy to understand and allows failed builds to be traced back quickly.
  • Your system must be scalable across multiple pipelines. Avoid duplication (slows the pipelines down) and parametrize tasks instead, so that you configure them by passing variables, and build a library of tasks that lets you reuse code across pipelines, while also reducing coupling between tasks and pipelines.

Full post here, 10 mins read

Cold start/warm start with AWS Lambda

Programming language can impact the duration of a cold start in Lambda: Java and C# are typically slower to initialize than Go, Python or Node but they perform better on warm calls.
Read more

Cold start/warm start with AWS Lambda

  • Programming language can impact the duration of a cold start in Lambda: Java and C# are typically slower to initialize than Go, Python or Node but they perform better on warm calls.
  • Adding a framework to structure the code deployed in Lambda increases execution time with cold calls, which can be minimized by using a serverless-oriented framework as opposed to a web framework. Typically, frameworks don’t impact warm calls.
  • In serverless applications, one way to avoid cold starts is to keep Lambda warm beyond its fixed 5-minute life by preventing it from being unloaded. You can do this by setting up a cron to invoke Lambda at regular intervals. However, AWS Lambda will still reset every 4 hours and autoscaling must be taken into account.
  • To avoid cold starts in case of concurrent calls from automatic autoscaling, make pools of Lambda instances kept warm as above; but you will need to determine an optimal number to avoid wasting resources.

Full post here, 11 mins read

Tips for architecting fast data applications

Implement an efficient messaging backbone for reliable, secure data exchange with low latency. Apache Kafka is a good option for this.
Read more

Tips for architecting fast data applications

  • Understand requirements in detail: how large each message is, how many messages are expected per minute, whether there may be large changes in frequency, whether records can be batch-processed, whether time relationships and ordering need to be preserved, how ‘dirty’ the data may be and does the dirt need to be cleaned, reported or ignored, etc.
  • Implement an efficient messaging backbone for reliable, secure data exchange with low latency. Apache Kafka is a good option for this.
  • Leverage your SQL knowledge, applying the same relational algebra to data streams in time-varying relations.
  • Deploy cluster managers or cluster management solutions for greater scalability, agility, and resilience.

Full post here, 7 mins read

How to optimize the API response package

Offer filtering of results according to parameters specified by the requester. This reduces the calls made and results displayed as well as limits the resources fed to the user, resulting in tangible optimization and better user experience.
Read more

How to optimize the API response package

  • Paginate responses into batches of content that are easily browsable, because they are segmented into set numbers (10 per page, 20 per page, etc), limited (say only the first 1,000 entries are paginated), and standardized (using ‘next’, ‘last’ etc for cursor navigation).
  • Offer filtering of results according to parameters specified by the requester. This reduces the calls made and results displayed as well as limits the resources fed to the user, resulting in tangible optimization and better user experience. Do this while keeping in mind that overly complex filtering can work against optimization.
  • Use ranges to restrict results based on a user-specified structure, so that only specific elements within the range are considered applicable for the request to execute. This lets you offload data processing from the client-side to the server.
  • Avoid over-fetching and under-fetching, which can result from poorly formed requests or badly implemented scaling techniques.

Full post here, 12 mins read

Optimizing website performance and critical rendering path

Many things can lead to high rendering times for web pages - the amount of data transferred, the number of resources to download, length of the critical rendering path (CRP), etc.
Read more

Optimizing website performance and critical rendering path

  • Many things can lead to high rendering times for web pages - the amount of data transferred, the number of resources to download, length of the critical rendering path (CRP), etc.
  • To minimize data transferred, remove unused parts (unreachable JavaScript functions, styles with selectors not matching any element, HTML tags always hidden with CSS) and remove all duplicates.
  • Reduce the total count of critical resources to download by setting media attributes for all links referencing stylesheets and making some styles inlined. Also, mark all script tags as async (not parser blocking) or defer (evaluated at end of page load).
  • You can shorten the CRP with the approaches above, and also rearrange the code amongst files so that the styles and scripts of above-the-fold content load before you parse or render anything else.
  • Keep style tags and script tags close to each other in HTML (linewise) to help the browser preloader, and batch HTML updates to avoid multiple layout changes (such as those triggered by window resizing or device orientation).

Full post here, 8 mins read

Tips to speed up serverless web apps in AWS

Keep Lambda functions warm by invoking the Ping function using AWS CloudWatch or Lambda with Scheduled Events and using the Serverless WarmUP plugin.
Read more

Tips to speed up serverless web apps in AWS

  • Keep Lambda functions warm by invoking the Ping function using AWS CloudWatch or Lambda with Scheduled Events and using the Serverless WarmUP plugin.
  • Avoid cross-origin resource sharing (CORS) by accessing your API and frontend using the same origin point. Set origin protocol policy to HTTPS when connecting the API gateway to AWS CloudFront and configure both API Gateway and CloudFront to the same domain, and configure their routing accordingly.
  • Deploy API gateways as REGIONAL endpoints.
  • Optimize the frontend by compressing files such as JavaScript, CSS using GZIP, Upload to S3. Use the correct Content-Encoding: gzip headers, and enable Compress Objects Automatically in CloudFront.
  • Use the appropriate memory for Lambda functions. Increase CPU speed when using smaller memory for Lambda.

Full post here, 4 mins read

Patterns for resilient architecture: Embracing failure at scale

Build your application to be redundant, duplicating components to increase overall availability across multiple availability zones or even regions. To support this, ensure you have a stateless application and perhaps an elastic load balancer to distribute requests.
Read more

Patterns for resilient architecture: Embracing failure at scale

  • Build your application to be redundant, duplicating components to increase overall availability across multiple availability zones or even regions. To support this, ensure you have a stateless application and perhaps an elastic load balancer to distribute requests.
  • Enable auto-scaling not just for AWS services but application auto-scaling for any service built on AWS. Determine your auto-scaling technology by the speed you tolerate - preconfigure custom golden AMIs, avoid running or configuring at startup time, replace configuration scripts with Dockerfiles, or use container platforms like ECS or Lambda functions.
  • Use infrastructure as code for repeatability, knowledge sharing, and history preservation and have an immutable infrastructure with immutable components replaced for every deployment, with no updates on live systems and always starting with a new instance of every resource, with an immutable server pattern.
  • As a stateless service, treat all client requests independently of prior requests and sessions, storing no information in local memory. Share state with any resources within the auto-scaling group using in-memory object caching systems or distributed databases.

Full post here, 10 mins read

Tips for more helpful code reviews

While suggesting changes include code samples. Treat a code review as a public conversation, and remember even experienced developers can gain from ideas on implementation.
Read more

Tips for more helpful code reviews

  • Consider the impact of your words. If necessary, rewrite comments for empathy and clarity both.
  • Elaborate on your concerns to be more specific and to avoid ambiguity, even if it sounds more verbose.
  • While suggesting changes include code samples. Treat a code review as a public conversation, and remember even experienced developers can gain from ideas on implementation.
  • Include a link to relevant documentation when referencing a function, commit or pull request. For concepts, link a blogpost. Make it easy for the author to get to things you reference with a single click.
  • Offer to chat in person or on video call for clarifications, and volunteer to pair up and collaborate on any suggested changes.

Full post here, 5 mins read

Hard truths for new software developers

You don’t need to reinvent the wheel to make a difference. In the early years of your career, aim to learn about others’ thought processes and why things are being done the way they are.
Read more

Hard truths for new software developers

  • Accept that you don’t know everything, that tech knowledge is competitive and that you have to keep working and learning to stay relevant throughout your career.
  • Acknowledge that social and soft skills matter as much as tech knowledge. You will need to hold mature human conversations that solve human problems to grow through your career.
  • You don’t need to reinvent the wheel to make a difference. In the early years of your career, aim to learn about others’ thought processes and why things are being done the way they are.
  • You will not always get the help you need, so seek out a mentor you can trust, who is also invested in your success and with a 5-10 years’ experience gap.
  • Your goal in the workforce is not just your success but that of the product. So assume that in interviews you are being evaluated not for accuracy but for brainstorming human factors that can affect the product’s success and learn to test for them.

Full post here, 9 mins read

Truths about code optimization

Don’t assume you know the problem. Run your code with a profiler and see which bits are the slow ones before you start to write new code. Your obvious best guess could well be wrong.
Read more

Truths about code optimization

  • Make sure you start with working code in the first place and have good unit tests so that speeding it up does not break anything.
  • Don’t assume you know the problem. Run your code with a profiler and see which bits are the slow ones before you start to write new code. Your obvious best guess could well be wrong.
  • As you optimize your code, run the profiler after every change to check whether the change actually helped and whether there is a new bottleneck now.
  • It is obvious but if a change did not measurably help, take it out no matter how brilliant you think it was.
  • You can always keep on making things faster, lighter, cheaper but it will also gradually make the code harder to read, longer, complex. Know when to stop.

Full post here, 5 mins read

Go’s tooling is an undervalued technology

Go uses decentralized package management, or rather, module management. There is no central module manager or module registration, no external repository to trust and no need for an internal one.
Read more

Go’s tooling is an undervalued technology

  • As it has no external dependencies, you can build the latest version of Go using just the compiler in seconds and cross-compiling only needs setting a couple of environmental variables (GOOS and GOARCH).
  • Go uses decentralized package management, or rather, module management. There is no central module manager or module registration, no external repository to trust and no need for an internal one.
  • Since a module only needs to be hosted on a reachable network with valid HTTPS certification, with the network path becoming the name, there is no worry over duplicating popular module names.
  • Dependencies are cryptographically locked to versions. So, an upstream source cannot change a published module for those depending on it.
  • As each dependency is a single point of failure, Go checks with a module proxy before fetching the dependency. If you prefer, there is a GOINSECURE option for experimentation to avoid HTTPS certification.

Full post here, 6 mins read

Design principles for your HTTP APIs

Impose consistency so that similar endpoints behave in similar ways, even in edge scenarios, with consistent vocabulary, URL structure, request/response formats and error handling.
Read more

Design principles for your HTTP APIs

  • Impose consistency so that similar endpoints behave in similar ways, even in edge scenarios, with consistent vocabulary, URL structure, request/response formats and error handling. This will help ensure that users don’t need to read extensive documentation and handling updates becomes easier for developers.
  • Achieve performance by avoiding early optimization, waiting until you have the right metric in place to optimize based on hard data - and collect that data from day one, with an APM tool.
  • Use metrics to inform evolution, so that you update and add features based on actual user usage of endpoints to avoid or minimize disruptions to existing implementations.
  • For complex APIs, avoid a 1:1 mapping between database tables and API resources. Build in usability by simplifying business transactions to require a single API call rather than multiple. If it isn’t possible, be as flexible as you can.
  • Adopt simplicity by building on top of universally accepted standards and tools. This will mean less overheads and less room for mistakes.

Full post here, 7 mins read

Making Python programs blazingly fast

Find what parts of your code are slowing down the program. A simple & lazy solution is to use a Unix time command. You can also use cProfile for detailed profiling.
Read more

Making Python programs blazingly fast

  • Find what parts of your code are slowing down the program. A simple & lazy solution is to use a Unix time command. You can also use cProfile for detailed profiling.
  • Once bottlenecks are identified, time the slow function without measuring the rest of the code.
  • The most obvious way of making it faster is to use built-in data types.
  • Caching or memoization with lru_cache will help improve functions that perform expensive I/O operations or some fairly slow recursive functions.
  • You can improve performance, by using seemingly unnecessary assignments like local variables.
  • You can also speed up your code just by wrapping the whole code in the main function and calling it once.
  • Avoid or limit using dot operators (.) as they trigger dictionary lookup using getattribute, which creates extra overhead in your code.
  • Operations on strings like modulus (%s) or .format() can get quite slow when running in a loop. Go for f-string instead which is the most readable, concise and fastest method.

Full post here, 5 mins read

Ruby on Rails: Ensuring security is covered in your application

Use strong parameters to accept data being sent to you from a request, supplying whitelisted values to throw an error if incorrect data comes in.
Read more

Ruby on Rails: Ensuring security is covered in your application

  • Set up authentication to verify user access. You can use devise, which uses Bcrypt, to make it difficult for hackers to compute a password. It can also help recover passwords, register and track sign-ins, lock records, etc.
  • Use strong parameters to accept data being sent to you from a request, supplying whitelisted values to throw an error if incorrect data comes in.
  • Add slugs to URLs to identify records in an easy-to-read form without releasing the id of the record.
  • Protect sensitive data, especially logins and payment pages, by enforcing https through the config file and averting cross-site scripting (XSS) attacks.
  • Check for active record exceptions and create an exception concern to sit above the application controller to guard against specific exceptions.

Full post here, 3 mins read

A pragmatic take on REST anti-patterns

Sometimes, you will need to make concessions based on organizational context rather than best practice, and sometimes there are excellent business and security reasons to heed internal resistance over the purity of design, which does not functionally achieve anything better anyway.
Read more

A pragmatic take on REST anti-patterns

  • Implementing HATEOAS (hypermedia as the engine of application state) using the available tooling is not easy for a majority of developers. And, for consumers, this may dilute the simplicity of the API. You might want to choose a pragmatic REST approach - adopting most of REST but not all or you might create a remote procedure call (RPC) API. Just call it like it is, rather than getting stuck on the REST claim.
  • Sometimes, you will need to make concessions based on organizational context rather than best practice, and sometimes there are excellent business and security reasons to heed internal resistance over the purity of design, which does not functionally achieve anything better anyway.
  • Avoid making a REST “entity” of your customers. It adds complexity and yet no extra value to the consumer, mixes up the data and the security models by requiring the user to identify themselves by URI. This, in turn, results in a brittle interface, and in a ‘fallacy of nested interfaces’ that even a developer finds hard to parse. Instead, model only what you need to model in your API, not other associated things.

Full post here, 8 mins read

Software engineering is different from programming

As a software engineer, you must understand the problem fully, the limitations of the solutions offered as well as the privacy and security implications.
Read more

Software engineering is different from programming

“All software engineers can program, but not all programmers can engineer software.”
  • As a software engineer, you must understand the problem fully, the limitations of the solutions offered as well as the privacy and security implications.
  • Sometimes the solution is not writing code but combining existing programs, educating users, or preempting future problems.
  • Your code must be readable, easily extended, work well with other programs and maintainable, with clear error messages and error logging, backed by solid documentation for easy debugging.
  • Well-engineered programs will work in many different environments, differently-resourced devices and across time zones, even on limited memory and processing power, backed by a comprehensive test suite.
  • Find and use good tools to shorten feedback loops, for code static analysis, type safety, to deploy, debug and measure performance

Full post here, 11 mins read

Tips for building and managing containers

Curate a set of Docker base images for your container because these base images can be reused as many apps share dependencies, libraries, and configurations. Docker Hub and Google Container Registry have thousands of pre-configured base images for download.
Read more

Tips for building and managing containers

  • Curate a set of Docker base images for your container because these base images can be reused as many apps share dependencies, libraries, and configurations. Docker Hub and Google Container Registry have thousands of pre-configured base images for download.
  • However, don’t trust arbitrary base images. always use a vulnerability scanner - incorporate static analysis into your pipeline and run it for all your containers. If you do find a vulnerability, rebuild your base image and don’t just patch it, then redeploy the image as immutable.
  • Optimize your base image, starting with the leanest most viable one and build your packages on that to reduce overheads, to build faster, use less storage, pull images faster, and minimize the potential surface of attack.
  • Use only one (parent) process per container. As a rule, each container should have the same lifecycle as the app itself.
  • Avoid embedding secrets inside containers, even if you keep the images private. For security, use Kubernetes Secrets objects to store sensitive data outside containers, use the Secrets abstraction to expose them as mounted volumes inside containers or as environmental variables.

Full post here, 7 mins read

Why Kubernetes is the new application server

Figuring out how to connect to a service is easy and available out of the box with Kubernetes. You get configuration information from the runtime environment without it having to be hardcoded in the application.
Read more

Why Kubernetes is the new application server

  • Figuring out how to connect to a service is easy and available out of the box with Kubernetes. You get configuration information from the runtime environment without it having to be hardcoded in the application.
  • Kubernetes ensures reliability and availability for your applications by providing elasticity through ReplicaSets, which control the number of app replicas that should run at any time.
  • As Kubernetes run many replicas of the containerized application and auto-scales too, logging and monitoring become even more important than usual scenarios. And for this purpose, it has observability built-in. An important thing to note is that you must store your logs outside the container to ensure they are persistent across different runs.
  • Kubernetes is resilient. It ensures that your specified number of pod replicas are consistently deployed across the cluster. This automatically handles any possible node failures.

Full post here, 12 mins read

Designing a microservices architecture for failure

rchitectural patterns and techniques like caching, bulkheads, circuit breakers, and rate-limiters can help build reliable microservices.
Read more

Designing a microservices architecture for failure

  • 70% of the outages are caused by changes in code. Reverting code is not a bad thing. Implementing change management strategies and automatic rollouts become crucial.
  • Architectural patterns and techniques like caching, bulkheads, circuit breakers, and rate-limiters can help build reliable microservices.
  • Self-healing can help recover an application. You should add extra logic to your application to handle edge cases.
  • Failover caching can help during glitches and provide the necessary data to your application.
  • You should use a unique idempotency key for each of your transactions to help with retries.
  • You can protect resources and help them to recover with circuit breakers. Circuit breakers usually close after a certain amount of time, giving enough space for underlying services to recover.
  • Use chaos engineering methods to test.

Full post here, 11 mins read

How to safely throttle high traffic APIs

Adopting a scalable language and framework can help spread the traffic across multiple endpoints and systems, spreading the load across a wider structure.
Read more

How to safely throttle high traffic APIs

  • Adopting a scalable language and framework can help spread the traffic across multiple endpoints and systems, spreading the load across a wider structure.
  • Rate limiting is among the most common ways to managing API traffic and may be implemented by Dynamic Limits (staying within a range of requests), Server Rate Limits (limits on servers) or Regional Data Limits (restrictions based on heuristics and baseline analysis).
  • Build a backend for your frontend (BFF), i.e. break each element of your API into additional functions that are then accessed via facade APIs, turning your traffic from single to multiple sources.
  • API gateways are a proven, time-tested methodology for managing API traffic. API gateways can interact with microservices to bring many of the same functions and benefits of the BFF structure.

Full post here, 9 mins read

The two most important challenges with an API gateway when adopting Kubernetes

Encourage a diversity of implementations for consolidated tooling that supports architectural flexibility. However, take advantage of a consolidated underlying platform and offer a ‘buffet’ of implementation options rather than allowing developers to build bespoke ones for better security.
Read more

The two most important challenges with an API gateway when adopting Kubernetes

  • When building an API gateway using a microservices pattern that runs on Kubernetes, you must think about scaling the management of hundreds of services and their associated APIs and ensuring the gateway can support a broad range of microservice architectures, protocols and configurations across all layers of the edge stack.
  • The challenges of managing the edge increase with the number of microservices deployed, which also means an increased number of releases, so it is best that you avoid a centralized approach to operations and let each team manage their services independent of other teams’ schedules.
  • Encourage a diversity of implementations for consolidated tooling that supports architectural flexibility. However, take advantage of a consolidated underlying platform and offer a ‘buffet’ of implementation options rather than allowing developers to build bespoke ones for better security. This is a more manageable and scaleable approach too.

Full post here, 5 mins read

Design patterns in API gateways and microservices

Some of the most common cross-cutting concerns in applications include authentication, authorization, sessions, cookies, cache, logging and dependencies on other services.
Read more

Design patterns in API gateways and microservices

  • Some of the most common cross-cutting concerns in applications include authentication, authorization, sessions, cookies, cache, logging and dependencies on other services.
  • Authentication is best handled by a service that produces either a JSON web token or some other auth token which can be included in subsequent requests. Authorisation should be possible using a token too and should be performed before a request is proxied through to any microservice.
  • Cookies are best avoided by your microservices. If needed, they are easier and cleaner to implement in the gateway.
  • When it comes to caching, start with small expiration times. Maintaining REST-friendly routes will allow for simpler caching at higher levels.
  • Use log aggregation for logging.
  • Each microservice should be as independent as possible, and should not risk cascading failures because one service outage triggers another. Thinking about how the gateway will interface with its microservices is crucial to its robustness.

Full post here, 10 mins read

Microservices architecture as a large-scale refactoring tool

To refactor a monolith into microservices architecture, you need to break it into single responsibilities or services in an incremental fashion
Read more

Microservices architecture as a large-scale refactoring tool

  • If you have a functional monolith, you cannot afford to throw out all its current value and rebuild it from scratch.
  • Instead, you should do a cost/benefit analysis and then rebuild parts of it as microservices accordingly.
  • To refactor a monolith into microservices architecture, you need to break it into single responsibilities or services in an incremental fashion (to limit risk), replacing local function calls with a tool such as a REST operation to make a remote call for a microservice to integrate them; then remove the legacy code, slimming down the monolith.
  • Most of the time, splitting a monolith also means splitting the database it consumes. Ideally, avoid sharing the database among multiple applications to avoid data duplication.

Full post here, 10 mins here

Implementation of a monitoring strategy for products based on microservices

Proper instrumentation of microservices ensures faster pinpointing and troubleshooting of problems. These include metrics for availability, metrics for capacity planning or to detect resource saturation, and metrics to understand internal states of each instance of a microservice.
Read more

Implementation of a monitoring strategy for products based on microservices

  • Proper instrumentation of microservices ensures faster pinpointing and troubleshooting of problems.
  • These include metrics for availability, metrics for capacity planning or to detect resource saturation, and metrics to understand internal states of each instance of a microservice.
  • You need horizontal monitoring to monitor communication between microservices and their availability to each other.
  • Load balancing across instances of microservices depends on several instances of each microservice communicating with several instances of others, so it is useful to have each microservice monitor the quality of its own inbound or outbound calls with other services as well as to have smart gateways in the service mesh inform on traffic entering and leaving it.
  • Logs are the best place to keep metrics for each ETL job and are cheaper than metrics systems that are labeled by job ID.
  • While metrics monitor all events crossing a particular checkpoint over time, traces monitor each event as it travels through the entire microservices chain. Traces are really helpful in monitoring flows in the product.

Full post here, 8 mins here

Kubernetes deployment strategies

The standard for Kubernetes is rolling deployment, replacing pods of previous versions with the new one without cluster downtime. Kubernetes probes new pods for readiness before scaling down old ones, so you can abort deployment without bringing down the cluster.
Read more

Kubernetes deployment strategies

  • The standard for Kubernetes is rolling deployment, replacing pods of previous versions with the new one without cluster downtime. Kubernetes probes new pods for readiness before scaling down old ones, so you can abort deployment without bringing down the cluster.
  • In a recreate deployment, all old pods are killed at once and replaced with new ones.
  • A blue/green or red/black deployment offers both old and new versions together with users having access only to green (old version) while your QA team applies test automation to the blue (new version). Once the blue passes, the service switches over and scales down the green version.
  • Canary deployments are similar to blue/green but use a controlled progressive approach, typically when you want to test new functionality on the backend or with a limited subset of users before a full rollout.
  • Dark deployments or A/B testing are similar to canary deployment but used for front-end rather than backend features.

Full post here, 5 mins here

Common security gotchas in Python and how to avoid them

Prevent input injections (SQL or command injections) by sanitizing input using utilities that come with your web framework, avoid constructing SQL queries manually, and use shlex module to escape input correctly.
Read more

Common security gotchas in Python and how to avoid them

  • Prevent input injections (SQL or command injections) by sanitizing input using utilities that come with your web framework, avoid constructing SQL queries manually, and use shlex module to escape input correctly.
  • Avoid relying on assert statements except when communicating with other developers (such as in unit tests or to guard against incorrect API usage) because in the production environment it is common to run with optimisations and Python will skip the assert statements.
  • Python’s import system is very flexible, and installing third-party packages exposes security holes. You also need to consider the dependencies of your dependencies. So vet your packages: look at PyUp.io, check package signatures, use virtual environments for all apps, and ensure your global site package is as clean as possible.
  • Rather than the very powerful yaml.load, use yaml.safe_load.
  • Python can have overrun or overflow vulnerabilities related to memory allocation, so always patch your runtime, even with the latest version.

Full post here, 7 mins read

5 ways to make HTTP requests in Node.js

Request is a simplified HTTP client which is more user-friendly that you can install as a dependency from npm. It is easy to use and you can support Promises with the request-promise library.
Read more

5 ways to make HTTP requests in Node.js

  • You can use the default HTTP module in the standard library. It saves you the trouble of installing external dependencies but is not as user-friendly as other solutions.
  • Request is a simplified HTTP client which is more user-friendly that you can install as a dependency from npm. It is easy to use and you can support Promises with the request-promise library.
  • Axios is a Promise-based client for both the browser and Node.js, good for asynchronous code and more complex uses. It parses JSON responses by default and can handle multiple concurrent requests with axios.all.
  • SuperAgent, that is primarily used for Ajax requests in the browser, also works in Node.js. It offers functions like query() that you can chain on to requests to add parameters, and as with Axios, you don’t need to parse JSON responses yourself.
  • Got is a more lightweight library compared to Request, etc. Got work with Promises as well.

Full post here, 4 mins read

HTTP headers to secure your app for the busy web developer

Set an X-Frame-Options header to prevent someone from creating an iframe wrapper around your site to clickjack your site. Your safety options are DENY, SAMEORIGIN, and ALLOW-FROM.
Read more

HTTP headers to secure your app for the busy web developer

  • Set an X-Frame-Options header to prevent someone from creating an iframe wrapper around your site to clickjack your site. Your safety options are DENY, SAMEORIGIN, and ALLOW-FROM.
  • You can set X-XSS-Protection to block Reflected XSS (cross-site scripting) attacks.
  • Set the X-Content-Type-Options header to force browsers to respect the server-specified file type, preventing a Javascript injection through an HTML file.
  • Apply Strict Transport Security to refuse to connect as HTTP, enforcing HTTPS instead.
  • Prevent hackers from reading cookies by using HttpOnly to prevent Javascript accessing cookies, blocking an XSS attacker, and by using the Secure attribute to allow cookies to transfer only over HTTPS and not HTTP.

Full post here, 4 mins read

Walking the wire: Mastering the four decisions in microservices architecture

There should be no shared databases. If updates happen only in one microservice, you can use message queues to share data. If updates happen in two services, either merge the two services or use transactions.
Read more

Walking the wire: Mastering the four decisions in microservices architecture

  • There should be no shared databases. If updates happen only in one microservice, you can use message queues to share data. If updates happen in two services, either merge the two services or use transactions.
  • Handle microservice security by using a token-based approach. It pushes the authentication to the client and does access control at microservice level simplifying dependencies.
  • Handle microservice composition by driving flow from client browser, through orchestration or through a centralised server that runs the workflow.
  • Avoid a spaghetti of dependencies by having a proper & detailed plan of how & when which microservices should call each other. Understand the impact of such an invocation on the overall performance of the system.

Full post here, 9 mins read

Unique benefits of using GraphQL in microservices

The data structure in GraphQL allows for well-defined & delineated data ownership for each request. You can have great control over the data loading process and therefore control how data is transferred in a very granular way.
Read more

Unique benefits of using GraphQL in microservices

  • The data structure in GraphQL allows for well-defined & delineated data ownership for each request.
  • You can have great control over the data loading process and therefore control how data is transferred in a very granular way.
  • As GraphQL allows for request bundles composed of many requested resources, it can leverage a sort of parallel execution for data requests. This allows a single request to fulfill the requirements that would otherwise have been through multiple requests to multiple services over multiple servers.
  • GraphQL can budget requests, allows the server to prioritize requests and grant them where appropriate, and reduces timed out requests in the long run.
  • It saves ave processor time and effort because it utilizes Object Identifiers to cache often-requested data.

Full post here, 8 mins read

Do you have too many microservices? - 5 design attributes that can help

When you are developing microservices, ensure that each service relies on its own underlying data stores. If multiple services reference the same table in a DB, there is a great chance that your DB is a source of coupling. You must avoid such coupling.
Read more

Do you have too many microservices? - 5 design attributes that can help

  • When you are developing microservices, ensure that each service relies on its own underlying data stores. If multiple services reference the same table in a DB, there is a great chance that your DB is a source of coupling. You must avoid such coupling.
  • You should try to minimise the number of database tables a microservice uses.
  • At the onset, be clear about whether a service needs to be stateful or stateless.
  • Understand the system-wide relationships of a microservice with other services and what impact does non-availability of a particular microservice will have on the system.
  • Design your service to be the single source of truth for something in your system.

Full post here, 9 mins read

How we implemented domain-driven development in Golang

Some learnings from Grab’s implementation of the principles of domain-driven development (DDD) and idiomatic Go.
Read more

How we implemented domain-driven development in Golang

Some learnings from Grab’s implementation of the principles of domain-driven development (DDD) and idiomatic Go.

  • Work closely with business/domain experts to gather knowledge on the required functionality and flow of what you are building.
  • Break down this knowledge into different problems that need to be solved. Categorize these problems into bounded contexts and subcontexts (read here to know more about it).
  • Use these contexts to identify dependencies in the code & in the team. Identify the building blocks (value objects and entities) to further break down the functionality and flow.
  • Create interfaces to abstract the working logic of a given domain (i.e. repository).
  • Identify domain events and let them provide the relevant useful information to the user in other domains. This enables the independence of different classes.
  • Use a common language developed with the domain experts and apply it consistently in discussions and coding (for instance, to name classes and methods).

Full post here, 5 mins read

How we improved the observability of a Go project

Add comprehensive info-level logging coverage to make each step of processing more observable. Structure logging with log levels using the logrus package to eliminate noise and improve searchability within logs, and impose consistency.
Read more

How we improved the observability of a Go project

  • Add comprehensive info-level logging coverage to make each step of processing more observable. Structure logging with log levels using the logrus package to eliminate noise and improve searchability within logs, and impose consistency.
  • Create a structured error type to include a generic map of data. This will help you diagnose what exactly went wrong at the top level when error handling, indicating which errors are fatal and which indicate you should retry processing.
  • Use Go’s context package, threading it through all request handlers and message processors for greater control over your services, making for a more reliable shutdown in case of new deployment or scaling events.
  • Combine the detailed errors and logging into a common abstraction to reduce code repetition. You can add functions for creating errors and logs with basically the same interface, in turn using the context data.
  • Add service-level indicators (SLIs) for high-level functions in asynchronous processing to reveal end-to-end latency of different kinds of processing to end-users.

Full post here, 6 mins read

5 advanced testing techniques in Go

Use test suites - develop tests written against an interface for all implementations of that interface. Carefully consider interfaces before exporting them and avoid creating a hard dependency between a consumer package and your own.
Read more

5 advanced testing techniques in Go

  • Use test suites - develop tests written against an interface for all implementations of that interface.
  • Carefully consider interfaces before exporting them and avoid creating a hard dependency between a consumer package and your own. To avoid exporting an interface, use an internal/package subtree to keep the interface scoped to the package.
  • Don’t export concurrency primitives, especially channels and the sync package. Also, add documentation on whether a struct or package is safe for concurrent access by multiple goroutines.
  • Use net/http/httptest to speed up tests and run them in parallel more easily, without binding to a port or setting up a server.
  • Use a separate _test package inside the foo/ directory of the package you want to test, rather than the default package pkg. This is a workaround for cyclic dependencies, prevents brittle tests and lets you see what it is like to consume your own package.

Full post here, 8 mins read

Tips to power-up your Java security

Protect against SQL injections by binding variables in prepared statements, using the prepareStatement() function to validate inputs.
Read more

Tips to power-up your Java security

  • Protect against SQL injections by binding variables in prepared statements, using the prepareStatement() function to validate inputs.
  • Returning mutable objects leaves you vulnerable to unexpected changes in your class state. Instead, use an unmodifiable/immutable collection or a copy of a mutable object to return.
  • Avoid including XSS characters in log messages. Manually sanitize each parameter and configure your logger service to replace such characters.
  • Always validate user input, especially when dealing with files whose location might be specified by user input.
  • Replace predictable random values (java.util.Random) based on clock tickets or other predictable parameters with a secure random class and functions.
  • Eliminate dynamic class loading.

Full post here, 4 mins read

Ways to secure your applications

More than 70% of exploited applications are due to outdated dependencies. Ensure dependencies are up to date by using the latest packages and automating dependency management.
Read more

Ways to secure your applications

  • More than 70% of exploited applications are due to outdated dependencies. Ensure dependencies are up to date by using the latest packages and automating dependency management.
  • Explicitly declare acceptable user payloads and use database-level constraints, like maximum column size, refusing null values, etc.
  • Assert safe regular expressions.
  • Limit requests by IP address or user agent.
  • Store credentials outside your codebase, separating application configuration from code.
  • Disable HTTP requests to your server unless very specific use cases demand it. Enable certificate checking for outgoing connections so that communication with third-party APIs or services are also secured by HTTPS.

Full post here, 9 mins read

Top security best practices for Go

You should validate user entries (using native Go packages or 3rd party packages) not only for functionality but also to avoid attackers sending intrusive data.
Read more

Top security best practices for Go

  • You should validate user entries (using native Go packages or 3rd party packages) not only for functionality but also to avoid attackers sending intrusive data.
  • Use HTML templates to cover the vulnerability of XSS. You can use the html/template package to sanitize JavaScript executables.
  • Ensure each database user has limited permissions, that you are validating user inputs and that you are using parameterized queries to protect yourself from SQL injections.
  • Make the best use of Go’s crypto package to encrypt sensitive information.
  • Enforce HTTPS communication and implement in-transit encryption even for internal communication.
  • Remember that error messages and error logs can expose sensitive information. Use the native library in Go for logs or third-party options like logrus, glog or logo.

Full post here, 6 mins read

When DRY fails

DRY (Don’t Repeat Yourself) is about avoiding duplication of effort when writing the code. It also makes sure that when a bug is found it’s fixed across the board. Like many other principles, this one doesn’t work all the time.
Read more

When DRY fails

  • DRY (Don’t Repeat Yourself) is about avoiding duplication of effort when writing the code. It also makes sure that when a bug is found it’s fixed across the board. Like many other principles, this one doesn’t work all the time.
  • If DRY fails, it’s a good practice to reconcile. The simplest way to reconcile is to write a test that reads data A and data B and fails with a diff if they are out of sync.
  • Try having a great test suite that’s ideally 100% coverage and 100% mutation tested that you can run on both pieces of code.
  • Reconciliation does not mean synchronizing, overwriting,  comparing or even being disciplined and manually changing both places.
  • Reconciliation means checking all the data regularly and reporting all discrepancies, including fine-grained discrepancies.

Full post here, 3 mins read

Seven deadly sins of a software project

“Maintainability is the most valuable virtue of modern software development.” Do these seven things to make maintainable software.
Read more

Seven deadly sins of a software project

“Maintainability is the most valuable virtue of modern software development.”

Do these seven things to make maintainable software.

  1. Learn about elegant coding to avoid anti-patterns allowed by languages that are too flexible.
  2. Ensure all changes are traceable (what was changed, by who, and why), by always using a ticket to flag any problem, referencing the ticket in the commit, and preserving its history.
  3. Follow an automated process of testing, packaging and deploying for all releases to execute them from a single command line.
  4. Enforce static analysis rules so no build can pass if any of the rules are violated.
  5. Measure and report test coverage and aim for at least 80% coverage. This coverage metric also lets future developers see if coverage is affected when making changes.
  6. Beware of nonstop development. Always release and version-alize software so future developers can see your intentions and roadmaps from a clear release history (typically in Git tags and release notes), and have each version available for download.
  7. Ensure user interfaces are carefully documented to let the end-user see what the software does. 


Full post here, 7 mins read

Things you should never do

There is always a temptation to code from scratch rather than improve existing code because you may get a lot of excitement in building something grand. It is also harder to read code than to write it.
Read more

Things you should never do

  • There is always a temptation to code from scratch rather than improve existing code because you may get a lot of excitement in building something grand. It is also harder to read code than to write it.
  • You may assume the difficulty of reading and understanding how the old code works implies that you can write it better. This assumption is usually wrong because the old code worked and was tested and repeatedly debugged. New code will not automatically be better than old. What makes old code look messy is the patches.
  • And there are things you can try to improve in messy code. Work on improving architectural problems that require refactoring, moving code around, better defining base classes and sharpening interfaces carefully and work on smaller inefficient parts of a project which you can speed up.
  • Rewriting code from scratch is one of the worst mistakes companies/developers can make and should avoid

Full post here, 6 mins read

Top 5 cybersecurity predictions for 2020

Credential stuffing, where hackers steal login credentials from one site and use the same credentials to break into a user’s accounts on other sites, will continue to be an easy attack.
Read more

Top 5 cybersecurity predictions for 2020

  • Credential stuffing, where hackers steal login credentials from one site and use the same credentials to break into a user’s accounts on other sites, will continue to be an easy attack.
  • AI-focused detection products will lose the hype because of their inability to meet promises.
  • California Consumer Protection Act (CCPA) will have a big impact on many tech companies with regard to their data privacy practices.
  • Cybersecurity breaches for autonomous vehicles will increase because of systems not keeping pace with advancing threats in this area.
  • You will be required to do the operational work of assigning ownership & accountability in your companies to ensure data laws, regulations, norms and best practices are in place to improve cybersecurity.

Full post here, 4 mins read

Ways to hack an API and how to defend

Use base-level encryption to allow functionality to operate as expected but obscure relationships between data to defend against reverse engineering. To defend against spoofing you can encrypt all traffic in transit.
Read more

Ways to hack an API and how to defend

  • Use base-level encryption to allow functionality to operate as expected but obscure relationships between data to defend against reverse engineering.
  • To defend against spoofing you can encrypt all traffic in transit. This will ensure that what is captured is only “noise”. Another option is to set up a pre-configured server certificate that is trusted by the API and allowing a handshake to go through only if when the certificate passes. You could also try a two-factor authentication to prevent attacks from the user perspective.
  • Ensure proper session management. Be sure that sessions are invalidated once users get past an idle timeout period or if the user logs out. You should set the session lifespan to terminate at a certain point.
  • Enforce API level security by using opt-in heuristic systems to know when a user is coming from an unknown machine, unknown location, or if there is any other variation in a known behavior.

Full post here, 11 mins read

Security best practices for MongoDB

Configure Transport Layer Security to encrypt all traffic to and from the database. Use at rest encryption to protect the contents of the DB in the event that someone is able to copy the database files (in a backup, for instance) or the server image.
Read more

Security best practices for MongoDB

  • MongoDB doesn’t have access control enabled by default. You must enable it. Also, configure RBAC (role-based access control).
  • Configure Transport Layer Security to encrypt all traffic to and from the database.
  • Use at rest encryption to protect the contents of the DB in the event that someone is able to copy the database files (in a backup, for instance) or the server image.
  • Restrict network exposure to tighten the security of the network topology that hosts the MongoDB database.
  • Use official MongoDB package repositories. Ensure that the packages are official MongoDB packages and pass the authenticity checks.
  • Disable JavaScript execution where possible. Troublesome operators - $where, mapReduce, and group - can be incredibly dangerous.

Full post here, 7 mins read

4 serverless myths to understand before getting started with AWS

One myth is that serverless implies Functions as a Service (FaaS). Cloud services are serverless if no servers are exposed for you to administer, if they scale automatically and you pay for what you use only.
Read more

4 serverless myths to understand before getting started with AWS

  • One myth is that serverless implies Functions as a Service (FaaS). Cloud services are serverless if no servers are exposed for you to administer, if they scale automatically and you pay for what you use only. In fact, serverless need not mean web-based apps, and can include real-time analytics and processing, so look beyond functions.
  • Don’t think that serverless is a silver bullet. Serverless technology is best suited for event-based architectures, rather than traditional client-server architecture, and you need to beware of recreating monolithic structures.
  • Another common myth is that serverless means an end to operational burdens. Advanced observability is intrinsic, so you need operational effort to monitor, maintain and effectively scale, though you need not administer servers.
  • Don’t believe that serverless is infinitely scalable. Serverless services have high availability but cannot scale infinitely - each service has limits, such as lambda’s memory limits and Kinesis’ throughput limits - so you need to optimize for the limits and plan for failure scenarios to ensure resilience.

Full post here, 6 mins read

Production secret management at Airbnb

Airbnb built an internal tool Bagpiper which is a collection of tools and framework components that it uses for the management of production secret assets. They designed it to decouple secret management from other app configurations as Airbnb scaled, and to ensure a least-privileged access pattern
Read more

Production secret management at Airbnb

  • Airbnb built an internal tool Bagpiper which is a collection of tools and framework components that it uses for the management of production secret assets.
  • They designed it to decouple secret management from other app configurations as Airbnb scaled, and to ensure a least-privileged access pattern, encryption of secrets at rest, support for applications across several languages and environments, and managing secrets for periodic rotation.
  • Bagpiper creates segmented access by asymmetrically encrypting secrets with service-specific keys: a secret is encrypted with each of the public keys on a per-secret keychain, and only services with the corresponding private keys can decrypt the secret. It encrypts information at rest and decrypts it during use.
  • Engineers can add, remove and rotate secrets, and make them available to select production systems. Secrets and changes to code are typically deployed together.
  • Secrets are rotated continuously, using secret annotations that specify when a secret was created/last rotated and when to rotate it again.

Full post here, 6 mins read

Want to debug latency?

Latency is a critical measure to determine whether our systems are running normally or not. There are many collections libraries available that help you collect latency metrics.
Read more

Want to debug latency?

  • Latency is a critical measure to determine whether our systems are running normally or not.
  • There are many collections libraries available that help you collect latency metrics.
  • Heat maps are useful as they help visualize latency distribution over time.
  • After narrowing down the source of the latency to a service or process, look at the host-specific and in-process reasons why latency occurred in the first place.
  • If the host is behaving normally and networking is not impacted, go and further analyze the in-process sources of latency.
  • Some language runtimes like Go allows us to internally trace runtime events in the lifetime of a request.

Full post here, 6 mins read

Serverless for startups - it’s the fastest way to build your technology idea

Scaling is handled for you. You don’t have to worry whether a function is run once a day or a million times a day. Startups often need to change system concept and functionality mid-way and the agility serverless structure offers is perfect for this use case.
Read more

Serverless for startups - it’s the fastest way to build your technology idea

  • With serverless, you pay for what you use - the hidden infrastructural support for scaling is also built into the final bills.
  • Scaling is handled for you. You don’t have to worry whether a function is run once a day or a million times a day.
  • Startups often need to change system concept and functionality mid-way and the agility serverless structure offers is perfect for this use case.
  • It allows startups to dedicate all the engineers to solve business problems and not spend time on server management & infrastructure.
  • Serverless gives startups a chance to deliver quickly, and use speed and agility to their advantage.

Full post here, 7 mins read

Serverless deployment best practices

When you create IAM policies for your services, limit the roles to the minimum permissions required to operate.
Read more

Serverless deployment best practices

  • Keep your secret out of your source control and limit access to them. Use separate secrets for different application stages when appropriate.
  • When you create IAM policies for your services, limit the roles to the minimum permissions required to operate.
  • Restrict deploy times by locking down your deployments during periods you don’t want to be disturbed.
  • Use a single region or a subset of regions that suit your needs to offset inconsistencies with a geographically distributed team.
  • Create consistent service names for your Lambda functions. It will help you to find relevant functions easily and to tie multiple functions with a particular service faster.

Full post here, 6 mins read

Tips & tricks for developing a serverless cloud app

Focus on limiting the scope of your functions. Protect your code from malfunctioning by setting up a queue, or buffer requests..
Read more

Tips & tricks for developing a serverless cloud app

  • When going serverless, focus on limiting the scope of your functions.
  • Communication between your functions is important to exchange data within your app. You can either directly call another Lambda function from within a Lambda function or upload data to a service and let this service trigger another Lambda function.
  • Protect your code from malfunctioning by setting up a queue, or buffer requests if necessary for uniform scalability when working with numerous services.
  • Your functions have 15 minutes to run before they time out. So, the execution time for your app should be under that timeframe.
  • The more memory you allocate, the more CPU power you have. The same is true for network and I/O throughput.

Full post here, 5 mins read

Stretching, executing, coasting - and pacing yourself to avoid burnout

Look at how professional athletes build their careers. They pace themselves to optimize performance and ensure the longevity of their careers.
Read more

Stretching, executing, coasting - and pacing yourself to avoid burnout

  • Look at how professional athletes build their careers. They pace themselves to optimize performance and ensure the longevity of their careers. We, software developer can (and should) do the same too - use the model of stretching, executing and coasting just as they do.
  • Stretching is the most fun mode where you learn things quickly, apply them as you go, step up to new challenges, and move out of your comfort zone to accelerate learning. However, if you stretch too long and you will slow down or burn out.
  • Executing is the normal way of working where you use your existing skills and experience to get things done well, without continuously stretching. To get your manager’s support on this mode, list additional things you do and establish your intention to delegate or say no.
  • Coasting implies doing less or lower-quality work than you are capable of, say, as a short breather after a big project or because of personal circumstances.

Full post here, 5 mins read

7 things you don’t know about agile architecture

Build in feedback loops in every development cycle. Don’t mistake fast initial development for sustainable agility.
Read more

7 things you don’t know about agile architecture

  • Design the project so that introducing changes is not expensive.
  • Don’t spend too much time designing. Start building, learn and progress. Build in feedback loops in every development cycle.
  • Don’t mistake fast initial development for sustainable agility. You want to arrive sooner at the right end product rather than simply going faster.
  • Work in smaller teams, as bigger ones are less flexible and need more communication making them less agile. Know that more people does not guarantee earlier completion.
  • Avoid using speculation on future requirements to add complexity to projects. However, past changes can be clues to future needs, so watch for change hotspots and high defect density.

Full post here, 6 mins read

Programming: Doing it more vs doing it better

Learn to review and test more thoroughly and refactor sooner than later. Quit the struggle of trying to get faster at engineering.
Read more

Programming: Doing it more vs doing it better

  • The best way to get better at writing software is to write more software, not to seek perfection at every shot.
  • Put more thought into your design systems - strive to write readable, maintainable code without bugs.
  • Don’t assume that you will one day churn out beautiful code effortlessly. Instead, learn to review and test more thoroughly and refactor sooner than later.
  • Quit the struggle of trying to get faster at engineering. Taking your time to think and revising as you go helps you write better code.
  • However, realize it is impossible to do the last while meeting objectives; instead, apply diligence over the long-term.

Full post here, 4 mins read

Ways to stay motivated while learning to code

Aim for small incremental improvements. Look at the bigger picture of what you're enabling.
Read more

Ways to stay motivated while learning to code

  • You are going to spend a lot of time finding & fixing bugs. When you solve a problem completely, treat yourself.
  • Don’t learn to code - code to learn. Aim for small incremental improvements.
  • Amplify the positive, not negative. Don’t give in to the impostor syndrome. Learn to keep moving in spite of it.
  • Always look at the bigger picture of what you're enabling. Find and frame the reasons why you love your job.
  • Develop a hobby that gets your blood flowing, literally. Physical exercise helps a lot in staying motivated and focused!

Full post here, 14 mins read

Developers mentoring other developers: practices I've seen work well

Draw upon your own experiences, contexts and perspectives rather than giving textbook-ish suggestions.
Read more

Developers mentoring other developers: practices I've seen work well

  • When mentoring someone, you should delay sharing solutions to problems your mentee is facing as long as possible. Prompt them to introspect and figure out solutions on their own.
  • As they say, the devil is in the details. Ask specific questions to dive deeper and seek context. Listen intently and understand the underlying subtext.
  • Draw upon your own experiences, contexts and perspectives rather than giving textbook-ish suggestions.
  • Always be supportive and let the mentee know that you are on their side.

Full post here, 18 mins read

Is there a future beyond writing great code?

Work towards going into engineering management or look for pro-bono tech work for a social cause that’s close to your heart.
Read more

Is there a future beyond writing great code?

There are many things we developers can do that will make us more fulfilled in our professional lives. There are immediate options to explore beyond just writing code. You can work towards going into engineering management and be a great engineering leader. To move forward in life, one has to give back. And some ways of giving back could be as simple as code reviews, workshops, and individual assessments with some colleagues. Go do it and be a mentor to fellow developers. You will learn a lot of new things on the way too. If meaning is what you are looking for, why not consider doing pro-bono tech work for a social cause that’s close to your heart. There are always ways to get more fulfillment from our skillsets and our careers than we think. We just need to explore.

Full post here, 9 mins read

The headers we don’t want

Some unnecessary HTTP headers you want to avoid. Vanity headers such as server, x-powered-by and via. Some headers, such as p3p, expires, and x-frame-options represent deprecated standards.
Read more

The headers we don’t want

Some unnecessary HTTP headers you want to avoid:

  • Vanity headers such as server, x-powered-by and via offer little value to end-users or developers but at worst they divulge sensitive information.
  • Some headers, such as p3p, expires, x-frame-options and x-ua-compatible, represent deprecated standards.
  • Headers that are only useful to debug data but are not recognized by any browser, such as x-cache, x-request-id, x-aspnet-version, x-amzn-requestID. As a developer, you may want to keep them on but know that removing them makes no difference to how your pages are rendered.
  • x-robots-tag is a non-browser header only useful when the requesting agent is a crawler.

Full post here, 7 mins read

Principles of dependency injection

Use abstractions and make your code be reusable and flexible. Follow the single responsibility principle and let each class do only one thing.
Read more

Principles of dependency injection

  • Dependency injection can make your code more maintainable, using abstractions and by decoupling things.
  • If you code to implementation, you will get a tightly coupled and inflexible system. Use abstractions and make your code be reusable and flexible.
  • Follow the single responsibility principle and let each class do only one thing.
  • Differentiate between creatables (which should be created within the constructor if the whole class uses them) and injectables (which should be asked for by the constructor and not created directly).
  • Your constructors should only check for null, create creatables and store dependencies for later use. They should be free of any coding logic.

Full post here, 4 mins read

These four ‘clean code’ tips will dramatically improve your engineering team’s productivity

‘If it isn’t tested, it’s broken’, so write lots of tests, especially unit tests. Code not covered by a test gets invisibly broken until customers spot the bug.
Read more

These four ‘clean code’ tips will dramatically improve your engineering team’s productivity

Top strategies based on Robert Martin’s Clean Code:

  • ‘If it isn’t tested, it’s broken’, so write lots of tests, especially unit tests. Code not covered by a test gets invisibly broken until customers spot the bug.
  • Choose meaningful, short, precise names for variables, classes and functions and make it easy to find files by name. In case of conflict, choose precision over brevity.
  • Keep classes and functions small - four lines per function and 100 lines per class at most - and make them obey the single responsibility principle. This will help with documenting code better as you will have lots of well-named sub-functions.
  • Ensure functions have no side effects (such as modifying an input argument), and specify this explicitly in the function contracts if possible (such as passing in native types or objects that have no setters).

Full post here, 7 mins read

I didn't want to be a manager anymore - and the world didn't end

Understand the aspects of the new role that you know little about and figure out how you can get more exposure to them.
Read more

I didn't want to be a manager anymore - and the world didn't end

Here are a few key lessons I learned from this post:

  • If you’re interested in a new role, make sure you tell the right people about it in 1:1 conversations. Ask for advice and mentorship for the skills required for the role you want to be in.
  • Get to know yourself and what you like best. Learn as much as you can about aspects other than engineering, like product, design, compliance, support, sales, technical writing, etc.
  • Think about what you like & dislike in your current role and how those aspects would change if you moved to a different one.
  • Understand the aspects of the new role that you know little about and figure out how you can get more exposure to them.

Full post here, 9 mins read

Programming: Math or Writing?

The short answer is both. Just like when solving a math problem, you need to decompose a programming problem into smaller problems.
Read more

Programming: Math or Writing?

The short answer is both. The longer answer is:

  • Just like when solving a math problem, you need to decompose a programming problem into smaller problems.
  • The presence of functions, binary & hexadecimal numbers, Boolean logic, and big O notation for analyzing algorithm performance are either actual math or very close to it.
  • Abstractions are useful not only when constructing programs but also when reasoning about programs. Reasoning precisely about abstractions takes a nod from maths.
  • Your code needs to communicate the structure and organization of the program to other programmers. You need a good overall structure and you need to divide your programs into smaller snippets, just like paragraphs, for better readability.
  • Programming is a repetitive process of coding with frequent refactoring/revising, much like editing to revise and improve the written text.

Full post here, 4 mins read

What I learned about making software from my 3-year old daughter

If we focus, we might discover patterns and principles that can help us solve problems.
Read more

What I learned about making software from my 3-year old daughter

  • A meta-learning - observing children can teach us a lot.
  • When trying a new framework, tool or language, we need to play around and ask for help when we get stuck. Exploring is important.
  • When her toys get broken, we use the glue to fix them but once broken, they have a tendency of breaking again after some days. Even if they stay intact, she knows it is broken and at the risk of breaking again. Some code, like broken toys, cannot be repaired and the part or functionality needs to be completely replaced or rewritten.
  • She likes to play a game of spotting patterns. We tried to spot heart patterns one day. She was focused on finding those patterns everywhere and she won, of course. If we focus, we might discover patterns and principles that can help us solve problems. There are always patterns that we miss because we are not really looking for them.

Full post here, 4 mins read

Continuous testing of APIs

3 steps for having your APIs tested continuously: Write good test collection. Run tests on schedule and on-demand. Look at analytics & set up smart alerts.
Read more

Continuous testing of APIs

  • 3 steps for having your APIs tested continuously: Write good test collection. Run tests on schedule and on-demand. Look at analytics & set up smart alerts.
  • You should be running contract tests, integration tests and end-to-end tests in your build system on demand - when code changes happen or code merges happen.
  • You should have some scheduled tests run regularly. These are the ones for API health checks, DNS checks, security checks, and any infrastructure related checks.
  • For complete test coverage of your APIs, you will need both scheduled and on-demand tests.
  • Analytics from data generated from these tests will give you a view of system health, performance, stability, resiliency, quality and agility over time. Use it to find underlying problems and set up effective alerts.

Full post here, 7 mins read

Common API mistakes and how to avoid them

Be stingy with data you are sending through your APIs. Try to name attributes of objects in your API responses in such a way that they can be forward compatible with any future updates.
Read more

Common API mistakes and how to avoid them

Covering the “how to avoid” part here

  • Be stingy with data you are sending through your APIs. Figure out what’s the absolute minimum amount of data that satisfies the requirements you are trying to meet.
  • Represent upstream data internally as a Domain Object. You can both circumvent some bugs and provide a more consistent API by doing this.
  • Try to name attributes of objects in your API responses in such a way that they can be forward compatible with any future updates.
  • Apply Robustness Principle: “Be conservative in what you do, be liberal in what you accept from others.” Ensure all the API responses follow conventions and best practices but be accepting of inconsistent forms of requests (whenever you can) and normalize them into a consistent format at your end.

Full post here, 15 mins read

API practices if you hate your customers

Practices that make API experience bad for developers.
Read more

API practices if you hate your customers

Full post here, 16 mins read

Estimation 101 – a short guide

We all commit to deadlines based on our estimations and find ourselves in a tight spot later. For good estimations, break tour work down into a set of components, think about their individual complexity to understand the whole project.
Read more

Estimation 101 – a short guide

  • Estimations are hard and turn up inaccurate most of the time. We all commit to deadlines based on our estimations and find ourselves in a tight spot later.
  • For good estimations, break tour work down into a set of components, think about their individual complexity to understand the whole project. This can help you give more accurate estimates.
  • A PERT estimate is a good way to get to and also to share estimates. In this, you look at three values: pessimistic, optimistic, and most likely estimate. PERT estimate = (Optimistic + 4*Most likely + Pessimistic)/6. It is a weighted average of the three estimates.
  • When you are estimating your time or effort for projects, include time for writing tests, quality assurance, release scripts. Also include time for technical documentation and provisioning scripts for the cloud infrastructure to support the project, if any are required.

Full post here, 6 mins read

Understanding the hidden powers of curl

You can do many requests to any number of API endpoints on a single CLI line. It offers a great amount of flexibility with methodologies and protocols that you can use.
Read more

Understanding the hidden powers of curl

  • You can do many requests to any number of API endpoints on a single CLI line. You can also set a specific order to requests using --next.
  • You can pass the -v flag and generate a verbose record of the interaction that curl is doing. You can also output everything that occurs in curl using the --trace-ascii function. It will give an ASCII output for parsing and viewing.
  • curl offers a great amount of flexibility with methodologies and protocols that you can use.
  • It has many good options to compile your curl content and mimick curl activities in general. You can mimic the activity of a known browser by leveraging the “copy as curl” option available on Chrome, Firefox, Safari, etc.

Full post here, 8 mins read

Center stage: Best practices for staging environments

You should match staging & production as closely as possible. Use the same load balancers, security group settings, and deployment tooling.
Read more

Center stage: Best practices for staging environments

  • Staging environments help you validate the known-unknowns of your systems. Having good tests is not an alternative to staging environments. You must invest time & effort in a proper staging rollout across the company.
  • Your entire engineering team should have a consistent & homogenous deployment pipeline and runtime platform. This consistency will help with disaster recovery if and when it happens.
  • You should match staging & production as closely as possible. Use the same load balancers, security group settings, and deployment tooling.
  • Use a tool that allows teams to roll back the last deployment. No one’s work should be blocked by someone else’s bug.
  • Try to replicate production traffic loads & patterns as much as possible ion staging environments. The staging environment should be at proportionally the same scale as production. Avoid under-provisioning.

Full post here, 12 mins read

Stop writing crap code

Stop using else statements as your defaults. Make your code more descriptive. Use built-in functionality.
Read more

Stop writing crap code

  • Stop using else statements as your defaults. As code grows, logic gets complicated and these else statements come to bite you back while debugging code 6-12 months later.
  • Take the time to find & use built-in functionality of the language you are using. It will save your code from bloating.
  • Each function should have just one job to be done. Don’t hide your logic inside functions.
  • Make your code more descriptive by naming things properly, by adding code comments, etc.

Full post here, 4 mins read

Good code reviews, better code reviews

Questioning the necessity & impact of code changes in the context of your overall system. Look at abstractions introduced and aim for doing a contextual pass.
Read more

Good code reviews, better code reviews

  • You can make code reviews better by questioning the maintainability, necessity & impact of code changes in the context of your overall system. Look at abstractions introduced and aim for doing a contextual pass.
  • Any good code review avoids opinionated comments/statements. You can make code reviews better by focusing on being empathetic and all-round positive, kind and unassuming.
  • Good reviewers leave as many comments and questions as are needed, and prefer connecting with the author in-person, while better reviewers will proactively reach out to the person to avoid any misunderstandings in the first place.
  • You can have better coder reviews by looking beyond the errors and trying to figure out the underlying issue.
  • Companies with good code reviews ensure that everyone takes part in the code review process. Companies with better code reviews ensure that code just doesn’t make it to production without reviews.

Full post here, 8 mins read

Code less, engineer more

Build only what you absolutely must. Identify vendors for pieces you can more efficiently buy off the shelf than to build in-house. Focus on the impact of code and not the volume of code written.
Read more

Code less, engineer more

“…But just as we wouldn’t insist that every bridge be built with bespoke girders and bolts, or that all electrical plugs and sockets have their own form factors, we shouldn’t insist on custom-building every part of the designs that we craft.”
  • Build only what you absolutely must. Identify vendors for pieces you can more efficiently buy off the shelf than to build in-house. Document the rationales of your decisions for future use.
  • Encourage the mindset of focusing on the impact of code and not the volume of code written in your team.
  • If and when you write a completely new component, share it with everyone in the team and the company. While sharing write about what you made, why you made it and how you did it. This helps in avoiding duplication of efforts but another teammate or another team in the company.
  • In your team, encourage & reward reusing code.

Full post here, 6 mins read

What’s the difference between versioning and revisioning APIs?

Versioning implies that each group of related changes in an API is presented under a specific number, often denoting the type of release. Revisioning implies incremental changes have been made and it prevents version-to-version code breaks,
Read more

What’s the difference between versioning and revisioning APIs?

  • Look at release management as a communication tool - to and for your API consumers. You can take two approaches to it - versioning and revisioning.
  • Versioning implies that each group of related changes in an API is presented under a specific number, often denoting the type of release.
  • Revisioning implies incremental changes have been made and it prevents version-to-version code breaks, allowing legacy code to continue functioning.
  • You will find versioning useful when your API is flexible enough to support version 1 as legacy while transitioning to version 2; or when your API is only useful as a conduit to another API or system.
  • Revisioning is a more apt approach if your API supports vital business functions, medical purposes, security systems, etc., where it is essential for the API to stay up and running at all times.

Full post here, 7 mins read

4 ways your API specification can fall short and what to do about it

Your spec should clearly state the size constraint for each response developers should keep in mind while coding.
Read more

4 ways your API specification can fall short and what to do about it

  • You should communicate clearly about the number of items and pages developers can expect from each endpoint so that developers don’t make assumptions about it.
  • Your spec should clearly state the size constraint for each response developers should keep in mind while coding.
  • Your spec must set a performance standard and stick with it because developers code for their applications using your APIs after considering how fast/slow your APIs return requests.
  • Cover authorization extensively in your specs. Encourage the use of refresh tokens throughout your documentation.

Full post here, 5 mins read

Best design practices to get the most out of your API

Make your API easy to understand and fast to start up. Aim for intuitive consistency with repeating patterns and conventions
Read more

Best design practices to get the most out of your API

  • You should design your API in a way that it does one key thing really well. Don’t try to add too many what-if scenarios.
  • Make your API easy to understand and fast to start up.
  • Aim for intuitive consistency with repeating patterns and conventions in endpoint names, input parameters & output responses so that developers can begin without reading the documentation.
  • But still, create great documentation. And let developers try your API without the need to log in or sign up.
  • Make troubleshooting easier by returning meaningful error messages.
  • Make your API extensible with primitives that enable new workflows. Include an opportunity for feedback from top partners - perhaps allow few developers to test-drive beta options.

Full post here, 7 mins read

Go: best practices for production environments

Use a single, global GOPATH for your development environments. Try cloning your repos into their canonical paths within the GOPATH, and work there directly.
Read more

Go: best practices for production environments

  • Use a single, global GOPATH for your development environments. Try cloning your repos into their canonical paths within the GOPATH, and work there directly.
  • For repository structures, a good practice is to limit the number of source files. Your repos (with the exception of a vendor subdirectory) shouldn’t contain a directory named src, or represent their own GOPATH.
  • When it comes to passing configuration, package flag provides the best value and has strict typing and simple semantics.
  • Formatted code can significantly increase clarity. Use gofmt to format your code.
  • For logging and telemetry, try using package log that implements a simple logging package. It defines a type, logger, with methods for formatting output.

Full post here, 11 mins read

How not to store passwords

One of the good options for storing passwords is key derivation functions. They require more compute time to get cracked which means an attacker needs to spend more money to crack them.
Read more

How not to store passwords

  • It can’t be said enough - do not save passwords in plain text.
  • Encryption is only slightly better than plain text. It is not THE answer for sure.
  • Plain hashes are pretty weak too. They are vulnerable because users tend to replicate the same passwords for different websites and they also use very simple passwords making it easy to crack.
  • Salted hashes are much better at protecting passwords. But the speed at which hashes can be calculated by attackers makes brute-force attacks reasonably possible.
  • One of the good options for storing passwords is key derivation functions. They require more compute time to get cracked which means an attacker needs to spend more money to crack them.

Full post here, 7 mins read

Four load testing mistakes developers love to make

Being too focused on what you set out to test and ignoring any other warning signs while testing is a common mistake developers make. Reusing test data is another common mistake.
Read more

Four load testing mistakes developers love to make

  • If you run a short load test and it works fine, it is no guarantee that your service can handle that load for a long time. You should run your performance tests for more time and understand your system’s performance characteristics.
  • Being too focused on what you set out to test and ignoring any other warning signs while testing is a common mistake developers make. It’s good to pay attention and investigate unusual results or changes in your application’s behaviour as you increase load.
  • Reusing test data is another common mistake. You should either generate new data or spin up a new environment for each test.
  • Assuming the production environment is perfectly healthy permanently. Deliberately make things to go wrong during your load test to find out how your service will perform if such failures happen.

Full post here, 7 mins read

Be as serverless as you can, but not more than that

Once you find what does deliver value, you can consider going partly serverless and investing more in the infrastructure for it.
Read more

Be as serverless as you can, but not more than that

  • As a startup that’s exploring what may work, you want to rapidly provide options to your customers and see how they respond without investing too much. Serverless architecture helps with this.
  • Once you find what does deliver value, you can consider going partly serverless and investing more in the infrastructure for it.
  • Ask how much of your stack you need to own to deliver business value and differentiation.
  • Consider whether it makes sense to outsource SLA, regulatory compliance, pricing and roadmaps to a service provider.
  • Optimize for cost and latency as you start to find predictable patterns for your new product or service.

Full post here, 5 mins read

Security traps to avoid when migrating from a monolith to microservices

Rollback to the last known good state after a failure is more complex with microservices, so program in reverts carefully for data integrity.
Read more

Security traps to avoid when migrating from a monolith to microservices

  • Rollback to the last known good state after a failure is more complex with microservices, so program in reverts carefully for data integrity.
  • Move as many of your microservices as you can off the public networks to protect against DDoS attacks and other malicious actors.
  • Never pass data between services in plain text. Always encrypt.
  • Add monitoring to each service separately.
  • Develop a logging approach to follow for all teams, each service, consistently.
  • Don’t provide individual services too much access. Limit access intelligently based on need only.

Full post here, 7 mins read

Blue-green deployment: a microservices antipattern

Blue-green deployment is a technique that reduces downtime for your application by running two identical production environments called Blue & Green.
Read more

Blue-green deployment: a microservices antipattern

  • Blue-green deployment is a technique that reduces downtime for your application by running two identical production environments called Blue & Green.
  • At any time, one of the environments is live and one is idle. The live environment serves all production traffic. And your team deploys and tests in the idle environment. Once the new build runs fine, you switch the router to swap the live & idle environments.
  • Adopting this approach in case of microservices, tosses out the need for microservices to be independently deployable.
  • All microservices in a release need to be mutually compatible because the entire application is released in one go in the new environment.
  • “..this creates a distributed monolith whose pace of evolution is limited by the slowest-developing microservice.”

Full post here, 4 mins read

All about prefetching

Four common prefetching strategies - interaction-driven, state-driven, user-driven and download everything.
Read more

All about prefetching

  • Network Information APIs allow you to use different strategies for different connection types to improve prefetching performance.
  • Four common prefetching strategies are as follows. Many websites use a combination of these.

1. Interaction-driven - uses mouse and scroll activities as signals

2. State-driven - uses current page or URL to prefetch next logical step

3. User-driven - matches each specific user’s patterns of past usage, account information, etc

4. Download everything - so all the links in a page or all the bundles for an app.

  • The prefetch resource hint can be used to prefetch on all major browsers except Safari. You can either manually add prefetch resource hints with no dependencies or build tools based on developer configurations or use dedicated prefetch tools such as quicklink, Guess.js or Gatsby.

Full post here, 7 mins read

The value in Go’s simplicity

Super strong forward compatibility with careful attention to versioning and dependency. Great restraint to add ‘good-to-haves’ versus what you really need.
Read more

The value in Go’s simplicity

  • Super strong forward compatibility with careful attention to versioning and dependency. Libraries are super stable, and you can have very few external dependencies.
  • Great restraint to add ‘good-to-haves’ versus what you really need. So you get only two generic(ish) data structures of arrays (slices) and dictionaries (maps).
  • It comes with almost everything you need: the basic go test framework for testing; a sync package that covers most sync primitives that you may need; and an encoding package that works with json, xml, csv and other common formats.
  • The internal formatting tool gofmt provides enough consistency that your code looks idiomatic. This makes open-source code a lot more readable too.

Full post here, 5 mins read

Databases that play nice with your serverless backend

Modern cloud-native DBs, that expose stateless REST APIs, work best for serverless computing.
Read more

Databases that play nice with your serverless backend

  • Modern cloud-native DBs, that expose stateless REST APIs, work best for serverless computing.
  • Amazon’s Aurora Serverless variant scales to demand, resizes to meet storage capacity and handles routine maintenance as a managed service. Its Data API feature works with SQL DBs.
  • With Amazon DynamoDB, designing your data to work it while supporting access patterns is hard. Complex queries can be tricky too.
  • Microsoft’s Azure Cosmos works with several APIs & supports multiple data models. It lets you choose the exact tradeoffs between performance & consistency.
  • Google’s Cloud Firestore works well for web and mobile apps. It has built-in security without requiring a backend and it syncs across clients in realtime.

Full post here, 7 mins read

How to be a rock star developer

Write utility code that can be used by all. Focus on your work integrity, adaptability and the desire to do excellent work.
Read more

How to be a rock star developer

  • Write utility code that can be used by all and collaborate with other developers on projects beyond your scope of work.
  • Don’t give in to FOMO. Spend time doing the essential work that gets you real results.
  • At crunch times, rise to the occasion with a leadership mindset to rally, organize and collaborate.
  • Try to be essential but not indispensable. Indispensability eventually leads to burnout.
  • Focus on your work integrity, adaptability and the desire to do excellent work.

Full post here, 5 mins read

Become a better developer by mastering the superpower of deep work

Deep work is the ability to focus without distraction on a cognitively demanding task, to produce results in less time. To develop a good deep work habit, add routines to your work life.
Read more

Become a better developer by mastering the superpower of deep work

  • Deep work is the ability to focus without distraction on a cognitively demanding task, to produce results in less time. To develop a good deep work habit, add routines to your work life.
  • Check your agenda for important meetings and plan your day’s deep work sessions, breaks, and shallow work.
  • Arrive at work well before colleagues, when there is no noise, no meetings & no demands that require context switching.
  • Once your teammates arrive, take a social break or do some shallow work - answer emails, check feeds, engage in the daily scrum. Then tackle another deep work session.
  • Create a shutdown ritual to end the day - answer important emails, update task statuses and do small tasks that help you prepare for tomorrow.
  • Once you leave, practice stopping to think about work. If you can, turn off work-related notifications.

Full post here, 15 mins read

5 developer environment hacks to increase productivity

Use iTerm2 or Bash to know which Git branch you are working on and its status. Use Tmux to manage multiple window splits with fast shortcuts and hot-keys.
Read more

5 developer environment hacks to increase productivity

  • Use iTerm2 or Bash to know which Git branch you are working on and its status.
  • Use Tmux to manage multiple window splits with fast shortcuts and hot-keys. The screen function also lets you suspend sessions and return to them later.
  • Shell Aliases are handy to remember the syntax for tedious commands and long-winded texts.
  • Organising code directories helps differentiate between cloned repositories and something you might be tinkering with locally.
  • Ripgrep is way faster than git-grep and can blaze through lines and lines of code to find what you’re looking for quickly.

Full post here, 4 mins read

Autoscaling AWS Step Functions activities

Transactional flows are an ideal use case for auto-scaling because of unused compute capacity during non-peak hours.
Read more

Autoscaling AWS Step Functions activities

  • Transactional flows are an ideal use case for auto-scaling because of unused compute capacity during non-peak hours.
  • When you need to detect any scaling-worthy events, AWS components like Step Functions Metrics and Cloudwatch Alarms come in handy.
  • Support a scale-down cool-off time to prevent two consecutive scale-down actions within a certain amount of time.
  • Guard your system against any malicious, delayed, or duplicated scaling notifications by validating incoming scaling signals.
  • Review historical statistics for scale-down alarms so that they’re less susceptible to triggers and never occur during peak hours.
  • For a safe rollout, increment steps till you gradually reach the ideal minimal instance count.

Full post here, 5 mins read

When AWS autoscale doesn't

If the ratio of your actual metric value to target metric value is low, the maximum magnitude of a scale out event will get significantly limited.
Read more

When AWS autoscale doesn't

  • Scaling speed is limited. If the ratio of your actual metric value to target metric value is low, the maximum magnitude of a scale out event will get significantly limited.
  • Short cooldown periods can cause over-scaling or under-scaling because a scaling event may trigger before a previous scaling event has concluded.
  • Target tracking autoscaling works best in situations where at least one ECS service or CloudWatch metric is directly affected by the running task count, the metrics are bounded, or relatively stable and predictable.
  • The best way to find the right autoscaling strategy is to test it in your specific environment and against your specific load patterns.

Full post here, 8 mins read

4 common misconceptions about AWS auto-scaling

It is a myth that elastic scaling is more common than fixed-size auto-scaling. Maintaining the templates & scripts required for the auto-scaling process to work well takes a significant time investment.
Read more

4 common misconceptions about AWS auto-scaling

  • Do you think auto-scaling is easy? No, it is not. Maintaining the templates & scripts required for the auto-scaling process to work well takes a significant time investment.
  • It is a myth that elastic scaling is more common than fixed-size auto-scaling. Most useful aspects of auto-scaling focus on high-availability and redundancy instead of elastic load scaling.
  • A common misconception is that load-based auto-scaling is appropriate in every environment. Some cloud deployments will be better off without auto-scaling or on a limited basis.
  • There's a delicate balance between perfect base images and lengthy configurations that need to be run in an auto-scale event. This depends on how fast the instance needs to be spun up, how often auto-scaling events happen, the average life of an instance, etc.

Full post here, 6 mins read

Free ebook: An engineer’s guide to getting more recognition at work

Know what is effective work. Define your priorities. Deliver on time. Assess yourself honestly. Help your peers. Understand your manager's priorities. Get a mentor. Document what you do. Ask for explicit feedback. Talk to your manager regularly.
Read more

Free ebook: An engineer’s guide to getting more recognition at work

Everyone wants to do great work. A fulfilling, rewarding, and fast progressing career brings a lot of joy and a sense of purpose in our lives. But many a time we feel stuck in our careers and don’t see much growth.

I have written my first ever ebook to address this exact pain point all engineers face in their career trajectories. I have combined my experience of 10+ years and my learnings from engineers who nail the game of getting recognized for their work to curate 10 actionable insights that young engineers will find useful to do great work, get credit for it and get promoted quicker in their careers.

You can download the PDF version of the ebook or read it (in the form of a long post) below.


Part 1: Doing effective work

Step 1: Know what is effective work

Effective work means working on the right problems and getting the desired results. Often our first reaction to encountering a problem is to start solving it. We don’t pause to ask whether the problem at hand is even the right one to solve or not. We don’t take the time to truly understand it. We quickly try to optimize the solution instead.

We can be super-efficient and still get the wrong results. No optimization works if you are optimizing the wrong thing, to begin with. Having a focus on doing effective work forces us to look for the right problems to solve.

The chart below that explains what a focus on effectiveness and efficiency can do to organizations also applies well to professionals. The takeaway is simple: to thrive in your career, identify what’s effective work first and then optimize for efficiency later.

“The main thing is to keep the main thing the main thing.” - Stephen Covey

Step 2: Define your priorities

A precondition to doing effective work is having clear daily priorities to focus on. Break down your big sprints and large monthly/weekly goals into smaller pieces that can be daily priorities. Adopt any system that works best for you to write these down: a handwritten to-do list, a web app, scheduling tasks on your calendar, etc. To make sure you don’t get distracted from your priority to-dos, also make a not-to-do list to remind you what you shouldn’t be doing.

Another benefit of knowing your own priorities is that it helps you communicate your plans and progress clearly during all team updates. This helps build trust and respect for you among your team members.

This framework (based on the Eisenhower Matrix) from Atlassian's Prioritization Playbook for teams is a wonderful resource to refer to while defining your work priorities.

“In order to improve for good, you need to solve problems at the systems level. Fix the inputs and the outputs will fix themselves.” - James Clear

Step 3: Deliver on time

Working only on your priorities sounds quite simple, but it can be difficult to practice. If planning is equivalent to coding in a development environment, sticking to your plan every day is like fixing bugs in a production environment.

Things will break. Unplanned activities will demand your time & attention. You may get stuck with a silly bug that will take a humongous amount of your time. You may fall sick.

Four suggestions that will help you stick to your deadlines:

  • Be realistic about the time a task may take you. Always allow for some buffer time when committing to a deadline.
  • Under-committing and over-delivering are better than running late on deadlines. Remember you can always take on more tasks if you have time left in your day or week.
  • Don’t be shy about asking for help. Once you have searched for solutions online, tried to resolve your problem but still find yourself stuck, ask for help right away & unblock yourself. It will save you a lot of time.
  • If you foresee a delay in your delivery, communicate it to your entire team as soon as you know it.

Delivering on time gives your manager confidence in your consistency and reliability - two traits that are highly valuable in a team member.

“We are what we repeatedly do. Excellence, therefore, is not an act, but a habit.” - Will Durant

Part 2: Growing as a professional

Step 4: Assess yourself honestly

If you were your boss, would you be happy with your performance?
What about your work ethic and attitude? What are some areas that you would like to see improvements in? Are you being a good team member? Are you proud of your work? What new skills should you learn to grow in your career?

We all ask ourselves such questions but most of us don’t answer these honestly. We either judge ourselves too harshly or too leniently. Being objective about ourselves doesn’t come easy. Start developing the habit of being honest & objective with yourself about yourself.

Regular self-assessment is a free and constant source of feedback that can help you improve your work tremendously. Constantly bettering yourself doesn’t go unnoticed.

Schedule ten minutes in your calendar every week to have an honest chat with yourself. Writing your self-assessment is a great idea too. It brings a lot of clarity in thought.

"Who looks outside, dreams; who looks inside, awakes." - Carl Jung

Step 5: Help your peers

Being a good helpful person goes a long way. If you see a co-worker stuck at something, offer to help them. If you know how to solve a problem that they need help with, don’t just give them a solution; work with them to solve it so they understand the process.

Collaborate with your team on different projects. Partake in peer programming sessions. Help out a new team member settle in and navigate their first few weeks. When you learn something new, share it with your peers. Give constructive feedback and help other engineers improve their craft. You will end up learning a lot yourself while helping your peers.

Everyone looks up to people who set up others for success. Be that person who genuinely helps their peers.

“Cooperation is the thorough conviction that nobody can get there unless everybody gets there.” - Virginia Burden

Step 6: Understand your manager’s priorities

Look at your manager as your ally. Learn to understand and empathize with them. Know their priorities. Know what they expect from you. Know how your contribution helps them in fulfilling their priorities. Understand how your work goals align with theirs and adjust for any mismatches.

Share with them what areas you want to learn more about. Tell them where you are stuck and can’t make progress, and ask them for advice. Ask them what they think you need to focus more on to grow to the next level of your career.

Don’t feel any bit of strangeness discussing any of this with your manager. Know that when you grow, your manager gets the credit for helping you grow as well. It is literally a part of their job. And you can do your job well as well as help them do their job well by taking the initiative to develop an open and understanding relationship with them.

“Things which matter most must never be at the mercy of things which matter least." - Johann Wolfgang von Goethe

Step 7: Get a mentor

Having a mentor can help you grow a lot in your career. Someone who is a decade ahead of you in the same profession, but not on your team, would make for a great mentor.

Look around in your company, in your professional network or just among people whom you admire for their professional success and ask them to be your mentor. It’s surprisingly easy to find a mentor because most people love giving advice. Tell them what kind of guidance you are looking for and assure them that you are willing to put in the work needed to make their time worthwhile.

Mentors encourage you and pick you up on bad days. They challenge you and give you the advice to help you grow as a professional. They help you see a situation from a fresh and objective perspective. They can keep you focused and accountable. As they have gone through a similar career journey as yours, they can help you with practical and actionable advice.

Great mentors accelerate your career growth tremendously. Go find yourself one.

“If I have seen further it is by standing on the shoulders of giants.” - Isaac Newton

Part 3: Making your work visible

Step 8: Document what you do

If your work isn’t visible to your team, your manager and your organization - you are in the soup. Getting your work visible is your responsibility. Regularly document what you are working on. We all do a lot at work but we don’t remember it all.

Most companies have formal review and recognition processes quarterly, semi-annually or annually. There are high chances that just in a few weeks, let alone after six or twelve months, you will not remember everything you did.

Your work needs to be visible for it to be recognized. Every week, take out fifteen minutes to write about all that you worked on. The daily priority list you made will help you while writing this.

Julia Evans’ brag document template is a great resource. Here are six key points from the template to help you start writing:

  • List your goals for this quarter/year and next quarter/year.
  • For each project, document your contribution to the project and the overall impact of the project. Quantify it as much as you can.
  • Write about all the fuzzy work you do. Simply list things done when you can’t quantify.
  • Jot down any work done in collaboration with a peer or another team and any team/company building efforts.
  • Include any design, documentation & code review efforts.
  • Document your learnings and new skills gained.
"Writing is thinking. To write well is to think clearly. That's why it's so hard." - David McCullough

Step 9: Ask for explicit feedback

Asking for feedback from your manager and your peers is a great way to not only showcase your work but also significantly improve it.
Getting explicit feedback is as much about being open in asking for it as it is about being comfortable receiving it. Develop a mindset to handle criticism positively.

Good communication plays a big role while asking for explicit feedback. Tell people that you want truthfulness and not niceness. Let them know that they are doing you a favor by sharing their honest thoughts. Help them help you give precise feedback by asking direct questions such as “What three things you think went great?”, “What can I improve in future projects?” or “What about my working style do you like and what concerns you?”

When people start talking, listen attentively and without judgment. Don’t explain yourself. Don’t get defensive. This is about you hearing honest thoughts and impressions of your work from your colleagues.

When you ask for feedback and then improve based on that feedback, you not only make your work visible to your team but you also tell them that you are open to learning and improving.

"True intuitive expertise is learned from prolonged experience with good feedback on mistakes.” - Daniel Kahneman

Step 10: Talk to your manager regularly

You need to communicate with your manager constantly. You must keep them updated about everything you are working on.

If it is not already a practice at your workplace, set up at least one one-on-one meeting with your manager every fortnight. 30-min catchups are great. Use this time to update them on your current work priorities, progress on important projects, your wins and misses, and your current challenges. Ask them how they think you did in the last fortnight.

The weekly documents that you write about what you are working on will come in handy in utilizing this time well.

These regular catch-ups will help you build great visibility for your work on an ongoing basis. It will also help develop a great working relationship with your manager.

"Good communication is the bridge between confusion and clarity." - Nat Turner

This is it. These 10 simple steps will help you leapfrog in your career. Go get started with some of these right away. May we all do more and more fulfilling & rewarding work in the next year.


Why I wrote this ebook?

I wrote it to answer some of the questions about career growth that every engineer faces at some point in their careers:

  • What can I do to get my due recognition in the engineering team?
  • Why do some engineers get promoted quicker in their careers as compared to others?
  • How do some engineers manage to get salary hikes more regularly than others?
  • Why am I not getting to work on impactful projects?
  • Am I stuck with the wrong manager?
  • How can I make my work more visible to others in my team and in my organization?

I have been a CTO and co-founder of three venture-funded startups. I have been an individual contributor at large and small engineering companies. I have had the chance to work with engineers who nailed the game of getting recognized for their work and got promoted quicker than everyone else. I have also met with many engineering leaders and discussed what makes them pick one engineer over the other for rewards, recognition & promotions.

So, I decided to write about all I have learned from these interactions and my own experience of ten plus years in the software engineering field. There are, of course, no magic answers. Just simple things one can do. I hope you found these learnings useful.

Let me know your thoughts & feedback on this. I am reachable on email at arpit@insnippets.com and on Twitter @mohanarpit

Functional lessons learnt

Respect the purity of the functions. Focus on the order of parameters to increase the readability of your code.
Read more

Functional lessons learnt

  • Respect the purity of the functions. Keeping your code pure makes it easier to test and overall more predictable. A function is pure when it doesn’t create side effects and only affect the context within the function itself, not outside.
  • Focus on the order of parameters to increase the readability of your code. Go with either horizontal or vertical functions. Avoid mixing them as much as possible. Start by keeping the function heads consistent in the order of parameters.
  • Applying transformations to your data structures and always making sure you return that same data structure can help endlessly pipe your reducers, and achieve vertical functions.
  • Keep your data private and your behaviour public. That way, modifying the underlying implementation of your behaviour will never affect the users of your API.

Full post here, 11 mins read

Software development speed vs. quality: a tech shop conundrum

Achieving both speed and quality together is nearly impossible. Startups and smaller companies often lean towards speed, since they need to be disruptive to succeed.
Read more

Software development speed vs. quality: a tech shop conundrum

  • Achieving both speed and quality together is nearly impossible. A tech shop can operate in speed mode, or quality mode, or somewhere in the middle.
  • Developers, quality engineers, and quality assurance folks, who define their success in terms of quality, are the advocates for it.
  • Executives, product managers, sales & marketing people who are driven by deadlines that impact growth and revenues push for speed.
  • Startups and smaller companies often lean towards speed, since they need to be disruptive to succeed.
  • Within a single product release schedule, there can be a shift from quality mode early on in development to speed as there is more pressure to deliver.
  • Towards the end of the release cycle, you may need to sacrifice scope to hot deadlines while maintaining quality.

Full post here, 5 mins read

Practical advice for new software engineers

Get feedback early. Don’t let writing the perfect abstraction slow you down.
Read more

Practical advice for new software engineers

  • Get feedback early. While working on a pull request, start with a trivial change just to open it up for discussion. Or offer mockups, whiteboard wireframes or sketches, before you start writing code.
  • Thinking out loud can lend enough clarity for the solution to emerge readily.
  • Automate your most tedious or more frequently run processes.
  • Don’t let writing the perfect abstraction slow you down.
  • Read ahead to get more context when struggling to comprehend code, documentation or technical articles.
  • Keep detailed daily/weekly notes of what you worked on, problems you encountered, and how you solved them.

Full post here, 6 mins read

Why consistency is one of the top indicators of good code

Consistency in code allows you to make accurate assumptions and predictions about its behaviour and implementation.
Read more

Why consistency is one of the top indicators of good code

  • Consistency can be defined as both conformity and uniformity.
  • Consistency in code allows you to make accurate assumptions and predictions about its behaviour and implementation.
  • Small continuous improvements in the approach of doing things can introduce a great inconsistency in the overall code over time. Try to ensure complete adoption of the new approach, phasing out the old one entirely.
  • Where both approaches must remain, at least preserve consistency within verticals or modules.
  • Name things consistently (so that similar objects sound similar and dissimilar ones sound different) and let the name reveal context, behavior, and intent.

Full post here, 6 mins read

Finding the time to refactor

Make refactoring integral to every work schedule. Take a few minutes to clean up code, as soon as tests pass, with better names and extracting private methods and classes, etc.
Read more

Finding the time to refactor

  • Think of programming as writing code - that works, is easily readable and easy for other developers to modify and extend in the future.
  • In test-driven development, get used to thinking of a 'red-green-refactor' cycle. The green state ensures code passes tests, but the refactor ensures it stays clear and maintainable.
  • Make refactoring integral to every work schedule. Take a few minutes to clean up code, as soon as tests pass, with better names and extracting private methods and classes, etc.
  • Whenever adding a feature or fixing a bug, if you have to modify any piece of code that was hard to understand, refactor it right there and then.
  • When you try to introduce something new and the existing design does not work, refactor the design so the new addition is easier to make.
Make the change easy, then make the easy change. - Kent Beck

Full post here, 4 mins read

How to do good code reviews

Set measurable goals and capture metrics. Look for code that is repeated, non-modular, or flouting standard conventions.
Read more

How to do good code reviews

  • Set measurable goals and capture metrics, but do not set too many. Good code must work as intended, have high readability, and perform optimally.
  • Ask deep questions and confirm your understanding at each step, until your knowledge of the code is as good as the developer’s.
  • Address everything you may think relevant, not just what you were told.
  • Look for code that is repeated, non-modular, or flouting standard conventions.
  • Avoid reviewing code for more than 60 minutes or more than 400 lines at a time. Increase the frequency of reviews so you can take time to identify the best solutions.

Full post here, 6 mins read

The big bad guide on database testing

Check for data mapping, ACID properties and data integrity of your DB, and ensure they implement your business logic accurately.
Read more

The big bad guide on database testing

  • Check for data mapping, ACID properties and data integrity of your DB, and ensure they implement your business logic accurately.
  • The most common test techniques are transactions for the ACID properties, checks of keys and indices, parameters and results of stored procedures, evaluation of triggers and field constraints, etc.
  • Stress testing and performance testing are critical too.
  • SQL queries are the most reliable way to qualitatively test apps with low or medium complexity.
  • Use a database testing tool that considers the business, data access and UI as well as the database itself.

Full post here, 8 mins read

Four steps to creating effective game day tests

List all potential failure scenarios. Create a series of experiments to anticipate how things will break. Test your human systems. Address the gaps and patch any holes you find.
Read more

Four steps to creating effective game day tests

Game Day tests deliberately trigger failure modes in production systems to practice response to unpredictable situations.

  • List all potential failure scenarios. Consider which parts of your infrastructure are completely safe, what are your blind spots, what happens if a server runs out of space or in case of a DNS outage or DDOS attack.
  • Create a series of experiments to anticipate how things will break - what side effects may be triggered, whether alerts will be correctly dispatched, whether downstream systems may be affected.
  • Test your human systems. Consider how team members need to interact when an incident unfolds.
  • Address the gaps and patch any holes you find. Check which hypotheses held up in practice and which ones did not. Establish a plan to correct these and run a new Game Day test to check whether your hypotheses are now valid.

Full post here, 6 mins read

7 debugging techniques to speed up troubleshooting in production

Remove or automate all the configuration needed to run the app. Don’t fall into the tech stack soup trap. Use 80% of your logging for 20% of your most important code.
Read more

7 debugging techniques to speed up troubleshooting in production

  • Remove or automate all the configuration needed to run the app by taking advantage of containerization and aiming for zero configuration.
  • Don’t fall into the tech stack soup trap. The fewer technologies or ‘right tools’ you use, the better, to avoid a pile of dependencies.
  • Use 80% of your logging for 20% of your most important code (the parts used the most).
  • Make it simple and quick to replicate customer issues. Use a tool to import only the records needed from the production database to your machine.
  • Place breakpoints in obvious places in the application, with one easily locatable method per UI event.

Full post here, 7 mins read

Learning DevOps as a software engineer

Monitoring/visibility, reliability & software delivery - focus on these three things that help in improving the quality of production.
Read more

Learning DevOps as a software engineer

  • Monitoring/visibility, reliability & software delivery - focus on these three things that help in improving the quality of production.
  • Monitoring four signals - latency, request rate, saturation, and error & success rate - is helpful in catching potential problems.
  • Analyzing which components can fail and how their failure can affect the system should be an important step in building new services or refactoring current ones.
  • Running end-to-end tests on staging and production is crucial.
  • Continuous delivery workflow is extremely important to reduce operational overheads and to enable faster delivery.

Full post here, 4 mins read

Dogfooding in product development

Dogfooding is excellent to ensure great UX. Blogging or documenting the API puts you in the position of a first time user of a specific API. Creating significant new features is another way of dogfooding.
Read more

Dogfooding in product development

  • Dogfooding is the practice of using your own product. It is a great approach to test it with real-world usage and it helps with quality control.
  • When it comes to APIs, dogfooding is excellent to ensure great UX. The more you use your own API, the more usable you make it for your customers.
  • Dogfood APIs via testing because it will force you to use the API for the first time & find out first usability issues.
  • Blogging or documenting the API puts you in the position of a first time user of a specific API. Creating significant new features is another way of dogfooding.
  • It best to write APIs from the user’s point of view, and dogfooding your API is one easy way to understand this point of view.

Full post here, 8 mins read

What makes code bad?

Remove unreachable code, code that doesn’t do anything and code that was put to set up for future features that never materialised.
Read more

What makes code bad?

  • Remove unreachable code, code that doesn’t do anything and code that was put to set up for future features that never materialised.
  • Fix hard coding by creating a dynamic interface to allow the value to be changed.
  • Overuse of inheritance creates tightly coupled, non-flexible code. Focus on composition to solve this.
  • Refactor overly complex comments by extracting methods or variables.
  • Refactor data clumps by creating a new parameter object or extracting the class.

Full post here, 5 mins read

Happy customers, quality code: the new trends in software development

It takes an average of 3.3 different tools to know the real status of the project and teams use an average of 4.3 tools to move code from development to production. 57% developers reported fewer bugs or outages by adopting CI/CD solutions.
Read more

Happy customers, quality code: the new trends in software development

Results from Atlassian’s research with 500 software developers & IT professionals, conducted at the beginning of 2019.

  • It takes an average of 3.3 different tools to know the real status of the project and teams use an average of 4.3 tools to move code from development to production.
  • 71% of software & IT teams who use a microservices structure believe it’s easier to test or deploy features.
  • 57% developers reported fewer bugs or outages by adopting CI/CD solutions.
  • Feature flagging reduces risks while rolling out features to customers. 63% developers who use feature flagging reported better testing of features or higher quality software.
  • Outcome-driven development is shifting the focus away from feature delivery speed to the customer value features creates.

Full post here, 4 mins read

Refactoring is about features

Always refactor in the service of a feature. Find code that is frequently being worked on. Try to refactor that code.
Read more

Refactoring is about features

  • Always refactor in the service of a feature.
  • Find code that is frequently being worked on. Try to refactor that code.
  • It seems faster to write a new feature in a complex system than to refactor the old system first and then add the new feature. But the overall time that you would spend debugging, rolling back releases, sending out bug fixes, writing tests for complex systems will be lesser of you refactor first.
  • Pick a feature that you want to implement, and figure out what you could refactor that would make it easier to implement it.
  • Set boundaries around your code. Eg: “I’m not going to refactor anything outside of my project to get this feature done.”
  • “There is no perfect design, there is only a better design.” So, avoid over-engineering or spending too much time on figuring out how to refactor something.

Full post here, 10 mins read

Five habits that help code quality

Keep coupling to a minimum. Apply the Principle of Least Astonishment. Minimise cyclomatic complexity
Read more

Five habits that help code quality

  • Write unit tests to save you from regression bugs. Unit tests also force you to write code that is less tightly coupled and more logically factored.
  • Keep coupling to a minimum.
  • Apply the Principle of Least Astonishment - design components of your system in a way that they behave how people using your system expect them to behave.
  • Minimise cyclomatic complexity - number of independent paths through a given piece of code.
  • Write clear, unambiguous, self-explanatory names to minimise confusion.

Full post here, 6 mins read

Secure databases in complex backend systems with these 5 best practices

Keep application and database servers on different physical machines, with a high-performance host for the apps & high-level security for databases. Encrypt data residing on servers with a private key and also encrypt before transit.
Read more

Secure databases in complex backend systems with these 5 best practices

  • Keep application and database servers on different physical machines, with a high-performance host for the apps & high-level security for databases.
  • Set up web application firewalls, and anti-malware & anti-ransomware solutions for the database server and review them regularly. Turn off any services not frequently used.
  • Encrypt data residing on servers with a private key and also encrypt before transit.
  • Limit the number of users accessing the database. Allow access only when required. Maintain and monitor activity logs. Keep database credentials hashed and salted.
  • Patch the OS and third-party software, APIs and plug-ins using the latest versions. Remove or deactivate unused apps.
  • Schedule regular backups and use a database proxy to accept requests only from trusted sources.

Full post here, 6 mins read

Five strategies to remove single points of DNS failure

Stay aware of trends that can compromise the 13 root name servers. Keep track of expiration dates of domains and SSL certificates.
Read more

Five strategies to remove single points of DNS failure

  • Stay aware of trends that can compromise the 13 root name servers.
  • Choose a top-level domain more likely to stay up under large-scale attacks or software faults, unlikely to change hands and with significant investment in infrastructure.
  • Choose a DNS provider that uses Anycast and is large and scalable; use a different company to service your endpoints.
  • Keep track of expiration dates of domains and SSL certificates.
  • Don’t couple your endpoints and DNS zone control in one provider.

Full post here, 11 mins read

3 steps toward improving container security

Focus on how you build access rules and permissions. Understand the level of granularity needed right from day one to build this. Harden the container host with policies to prevent resource abuse.
Read more

3 steps toward improving container security

  • Vet the use of code from online sources. Use discovery tools to manage and scale up containers securely with runtime protection.
  • Focus on how you build access rules and permissions. Understand the level of granularity needed right from day one to build this.
  • Harden the container host with policies to prevent resource abuse. Use access control groups, and run containers with read-only images.
  • Secure content inside containers by limiting Linux OS features running within it.
  • Enforce image source integrity protection to track content changes and determine who made them.

Full post here, 5 mins read

Rust performance pitfalls

Rust compiles in debug mode by default. It results in faster compilations, but does next to no optimizations, and slows down the code. It uses unbuffered File IO. So, when you write files, wrap them in a BufWriter/BufReader.
Read more

Rust performance pitfalls

  • Rust compiles in debug mode by default. It results in faster compilations, but does next to no optimizations, and slows down the code.
  • It uses unbuffered File IO. So, when you write files, wrap them in a BufWriter/BufReader.
  • Read::lines() iterator is easy to use, but it allocates a String for each line. Manually allocate and reuse a String to reduce memory churn to gain a bit of performance.
  • In simple cases, use an iterator instead of an index loop.
  • Avoid needles collect() and allocations.

Full post here, 7 mins read

Why developers like GraphQL?

Multiple teams can work independently and in parallel, giving developers a pleasant experience without stalling their development work. There is no versioning of APIs.
Read more

Why developers like GraphQL?

  • Superior developer experience in comparison to alternatives.
  • Multiple teams can work independently and in parallel, giving developers a pleasant experience without stalling their development work.
  • There is no versioning of APIs. Adding new fields has no effect on the current client’s call to the APIs.- no pain of maintaining multiple versions of the API.
  • Declarative data fetching lets you ask for exactly what you need and get it.
  • GraphQL schema has several advantages including predictable code, schema acting as a contract between client and server, independent teams and early detection of errors.

Full post here, 6 mins read

How to sleep at night having a cloud service: common architecture do's

Have a way of deploying your entire infrastructure as you deploy code. Build a CI/CD pipeline. Configure a load balancer.
Read more

How to sleep at night having a cloud service: common architecture do's

  • Have a way of deploying your entire infrastructure as you deploy code.
  • Build a CI/CD pipeline.
  • Configure a load balancer.
  • Use unique identifiers that allow you to trace a request through its lifecycle, and allows someone to see the entire path of the request in the logs. This is highly useful when things go down.
  • Have a log collection and build searchability in it. This comes in handy when searching for one unexpected log.
  • Have monitoring agents to check if your service is up.
  • Automatic autoscaling based on load is great for being elastic under load.
  • Create a way to test out things with 1% of your users for an hour. It is a good way to deploy changes safely.

Full post here, 7 mins read

Back-end performance, those metrics we should care about

There is a strong correlation between throughput and latency in a performance test. Latency increases with the growth of throughput.
Read more

Back-end performance, those metrics we should care about

  • The latency requirement should correspond to the specific service type.
  • There is a strong correlation between throughput and latency in a performance test. Latency increases with the growth of throughput.
  • Normally network issues like congestion-caused errors should not exceed 5% of the total requests, and application-caused errors should not exceed 1%.
  • As the CPU determines a server’s performance, a high sy means the server switches between user mode and kernel mode too often, which is bad for overall performance.
  • Frequent reading or writing the disk could cause long latency and low throughput.

Full post here, 10 mins read

Learnings from the journey to continuous deployment

Incremental changes result in easily maintainable products. Releasing with smaller changes at regular intervals brings value to customers faster and provides early feedback on future tasks.
Read more

Learnings from the journey to continuous deployment

  • Incremental changes result in easily maintainable products.
  • Releasing with smaller changes at regular intervals brings value to customers faster and provides early feedback on future tasks.
  • Improve code quality by writing quality tests and setting up comprehensive test strategies for the entire build and deploy pipeline.
  • Improve integration testing in the staging environment to detect issues related to dependencies.
  • Monitoring critical parameters such as system load, API latency, and throughput are vital to assess the health of the software.

Full post here, 5 mins read

From API craftsmanship to API landscaping

Moat your APIs with a robust, organization-wide security strategy. Allow your APIs to be discovered depending on whether they’re public, partner-facing, or private.
Read more

From API craftsmanship to API landscaping

  • Don’t let a fear of having too many APIs limit you. Some APIs will die while others will flourish with natural selection.
  • The effectiveness of your APIs should be felt and not seen. Changes in how consumers use APIs should be invisible to producers and vice versa.
  • Moat your APIs with a robust, organization-wide security strategy.
  • Allow your APIs to be discovered depending on whether they’re public, partner-facing, or private.
  • Use a sound versioning strategy.
  • Build your API ecosystem in a way that it can still work even if one is broken.

Full post here, 5 mins read

The programmer mindset: main debug loop

What the author calls a ‘main debug loop’ is a natural tendency most programmers develop over time: Write a small piece of code. Run the code. Fix what’s not working. Repeat.
Read more

The programmer mindset: main debug loop

  • What the author calls a ‘main debug loop’ is a natural tendency most programmers develop over time: Write a small piece of code. Run the code. Fix what’s not working. Repeat.
  • Validating small pieces of code you write while you write them (in-application validation) is better for code quality & for speed of the overall project than using only testing as a validation method.
  • However, in many cases this approach may consume a lot of developer time due to the latency in the file system, the runtime loading the change you just made, and your own time interacting with the newly updated application.
  • There is a correlation between large codebases, service architecture, and a retreat to test validation as the primary debug loop.
  • Staging environments can help solve these local machine resource problems, if any, and also alleviate the burden of maintaining a local data set for testing while writing code.

Full post here, 9 mins read

Prototyping vs. production development: how to avoid creating a monster

The ability to rapidly iterate, receive quick feedback, and keep costs relatively low are the three main priorities during the prototype phase. In the production phase, it is all about keeping the user, their needs and their environment in mind.
Read more

Prototyping vs. production development: how to avoid creating a monster

  • The ability to rapidly iterate, receive quick feedback, and keep costs relatively low are the three main priorities during the prototype phase.
  • Even in the prototype phase, write tests for vital pieces of code.
  • If your prototype starts turning too buggy, slow down and tighten your code. If you are constantly missing deadlines, simplify your code to improve the pace.
  • In the production phase, it is all about keeping the user, their needs and their environment in mind.
  • Users want products to be flawless and fast. Have well-defined code standards, review processes, and quality assurance testing process.
  • Be thorough with your documentation if you don’t want considerable code rewrites.

Full post here, 16 mins read

Staging environments are too important to be overlooked: here's why

Staging environments can reduce the errors occurring due to unmet dependencies. They reduce the impact or number of errors in your product and result in indirect cost savings.
Read more

Staging environments are too important to be overlooked: here's why

  • Data sets tested locally are usually an unrealistic representation of what is in production and can expose users to potentially breaking changes.
  • Staging environments can reduce the errors occurring due to unmet dependencies.
  • They reduce the chances of incorrectly merged changes getting deployed to production and save you from potentially rolling changes back or hotfixes.
  • They reduce the impact or number of errors in your product and result in indirect cost savings.
  • Using staging environments can result in a higher degree of quality assurance.

Full post here, 7 mins read

Don’t just check errors, handle them gracefully

Best option to use is an opaque error strategy that requires the least coupling between code and caller. The caller only knows an error happened, but they can’t see inside the error.
Read more

Don’t just check errors, handle them gracefully

  • There are three core strategies for error handling in Go.
  • Sentinel errors return a specific value. In error type handling, you create a type that implements the error interface. Error types are better than sentinel errors because they capture more context about what went wrong.
  • But both sentinel & error types error handling become part of your public API. And they create source code dependency between the caller and the package that implements the error interface. Both ate best avoided
  • Best option to use is an opaque error strategy that requires the least coupling between code and caller. The caller only knows an error happened, but they can’t see inside the error.
  • Consider using an error package with two main functions - ‘wrap’ to take an error & a message to produce a new error; the second is ‘cause’ which takes the possibly wrapped error and unwraps it to discover the original issue.
  • Only handle an error once. Inspect the error value and make a decision. No decision means the error is not handled.

Full post here, 11 mins read

We crashed and lost all essential data logs. Where did we go wrong?

Enforce a 7-day-timeframe complete log check. Mandate daily monitoring of logs at the end of each day.
Read more

We crashed and lost all essential data logs. Where did we go wrong?

How to prevent such a loss?

  • Enforce a 7-day-timeframe complete log check.
  • Mandate daily monitoring of logs at the end of each day. Team members can rotate through this role for a daily check and a 2-week sprint.
  • Require a minimum of two approvals per pull request.
  • Use a refactoring approach for writing tests - if a test fails, reverse your last change and implement it in a way that does not break the test, changing the code only one line at a time.
  • For flows of code that are harder to cover with unit tests, you may need a hybrid of unit &integration tests.

Full post here, 7 mins read

The traits of serverless architecture

The initial learning curve is low. Being hostless, it reduces operational overhead on server maintenance. Serverless architecture is stateless and helps you scale horizontally and reduces errors.
Read more

The traits of serverless architecture

  • The initial learning curve is low and hence there is low barrier-to-entry. It lets you on-board quickly without needing to develop server management skills.
  • Being hostless, it reduces operational overhead on server maintenance. However, you need to learn different monitoring metrics, non-traditional security issues and the specific limitations of each service.
  • Serverless architecture is stateless and helps you scale horizontally and reduces errors. But it makes it hard to use stateful technology such as HTTP sessions or WebSockets.
  • You need to learn distributed message delivery methods and the behavior of distributed transactions.
  • High availability is offset by less consistency, and each serverless service has its own consistency model.

Full post here, 11 mins read

Serverless security risks

Event data injections are really hard to identify & block in serverless architecture. Broken authentication is a big risk.
Read more

Serverless security risks

  • Event data injections are really hard to identify & block in serverless architecture.
  • Broken authentication is a big risk. There are hundreds of distinct functions, triggers & events that you must provide with the right access control and protection.
  • High degree of settings customization offered in serverless can lead to insecure deployment configurations. Make functions stateless at the design stages to avoid exposing sensitive data.
  • Over privileged functions are huge security risks.
  • Poor function monitoring and logging. Collect real-time logs from serverless functions and services, and push them to a remote SIEM system.
  • Third-party dependencies on web services (through API calls), software packages and open-source libraries.

Full post here, 4 mins read

Serverless best practices

Don’t let functions call other functions. Learn to use messages and queues to keep functions asynchronous.
Read more

Serverless best practices

  • Make each function do only one thing. Avoid switch statements that make for large, complex functions that don’t scale well.
  • Don’t let functions call other functions.
  • Learn to use messages and queues to keep functions asynchronous.
  • Use as few libraries as possible (ideally none), to avoid slowing down cold starts and to avoid adding security risks.
  • One function per route (using HTTP). Avoid the single function proxy as it does not scale well and cannot isolate issues.
  • Treat data as flows and not ‘lakes’ at rest. Avoid querying from a lake; you need to rethink your data layer to avoid scaling issues and rigidity of data structures.

Full post here, 7 mins read

Just starting out with test automation? Don't make this mistake

Don’t wait for the perfect tool, perfect use case, perfect resources. Just start with small automation.
Read more

Just starting out with test automation? Don't make this mistake

  • Whittle down big tests into smaller, shorter ones.
  • Don’t wait for the perfect tool, perfect use case, perfect resources. Just start with small automation.
  • Smaller tests let you learn faster, contribute sooner, create forward momentum, and get more frequent feedback.
  • Let teams focus on learning test automation first before you ask them to focus on complex business logic.
  • Automate in small sprints so you can gauge progress, iterate and gather feedback on them from testers, developers and product owners.

Full post here, 5 mins read

“Don’t deploy on Friday” and 3 other “unwritten rules” of software engineering

Even if you have continuous deployment, Fridays are the worst day to push to master. Wait for complete specs before you begin a build.
Read more

“Don’t deploy on Friday” and 3 other “unwritten rules” of software engineering

  • Even if you have continuous deployment, Fridays are the worst day to push to master. You only get half a day to fix bugs.
  • Keep a couple of backups (for redundancy) of your database, cryptographic keys, configuration files, VM images, images and videos, even imported packages. Git is not enough.
  • Wait for complete specs before you begin a build. Avoid assumptions and ask lots of questions, to pinpoint requirements as precisely as possible. Especially, probe corners and edge cases.
  • Try to gently stop or prevent unproductive discussions. It is okay to ask for a longwinded discussion to be shelved for more productive work.

Full post here, 4 mins read

10 rules for good API design

Make the API modular so it is easy to separate experimental pieces from stable ones. Also, make it extensible.
Read more

10 rules for good API design

  • Make the API modular so it is easy to separate experimental pieces from stable ones. Also, make it extensible.
  • Use the same style and conventions for each class. Document those conventions and impose them as a required standard for contributors.
  • Grow your API by layering new APIs on top of it. Avoid exceeding the current one’s scope.
  • Minimize the visible surface area of the API.
  • Keep your API portable across OSes and don’t let system concepts leak into it.

Full post here, 4 mins read

5 tips for building apps with the Serverless framework and AWS Lambda

Serverless works well with a microservice-style architecture. You should limit the scope of services and functions you use. Lambda functions shouldn’t persist any data or session information in the environment beyond the lifetime of a single request.
Read more

5 tips for building apps with the Serverless framework and AWS Lambda

  • Serverless works well with a microservice-style architecture. You should limit the scope of services and functions you use.
  • Lambda functions shouldn’t persist any data or session information in the environment beyond the lifetime of a single request.
  • However, Lambda might reuse your function instances to make performance optimizations. So, you should optimise for your functions for reuse.
  • Cold starts are a problem with AWS Lambda. Reduce latency by keeping containers warm.
  • Use dependency injection to make your functions easily testable. Write integration tests, both locally and on deployments.

Full post here, 6 mins read

6 things I’ve learned in my first 6 months using serverless

Ditch Python, switch over to Node. It makes everything much more maintainable and logical. The middle layer has to go. It acts as a web server on Lambda, which is both wrong and terrible.
Read more

6 things I’ve learned in my first 6 months using serverless

  • Ditch Python, switch over to Node. It makes everything much more maintainable and logical.
  • The middle layer has to go. It acts as a web server on Lambda, which is both wrong and terrible.
  • Try Vue when dealing with messy code. Vue compiles all your goodness into an index.html and bundle.js files, primed for uploading to S3.
  • Learn to love DynamoDB. When you get it right, the NoSQL database provides blistering performance, massive scale, and practically no administrative overheads.
  • Serverless Frameworks are awesome. A simple sls deploy wields enormous power, bundling up your code and shipping it directly to AWS Lambda.
  • Authorization is king and JWT makes all other types of auth look overcomplicated.

Full post here, 10 mins read

Lessons learned — a year of going “fully serverless” in production

API server on serverless leads to automatic scalability, high availability and reduces costs dramatically. Deploying a Lambda function has a 52Mb limitation.
Read more

Lessons learned — a year of going “fully serverless” in production

  • API server on serverless leads to automatic scalability, high availability and reduces costs dramatically.
  • Deploying a Lambda function has a 52Mb limitation. Mitigate this by including only the required dependencies and trimming their size by excluding unused files.
  • For background jobs such as file processing, keep a set of dedicated Lambda functions that are not part of the API server.
  • A good approach to logging is to stream the Lambda logs into a dedicated Lambda that is responsible for sending it to the 3rd party logging service.
  • When it comes to environment variables, don’t commit your secrets to source control.

Full post here, 6 mins read

The most common types of ATO attacks

ATO (account takeover) attacks are dangerous because when your system thinks the attacker is a legitimate user, your security safeguards won’t be able to protect your system.
Read more

The most common types of ATO attacks

  • ATO (account takeover) attacks are dangerous because when your system thinks the attacker is a legitimate user, your security safeguards won’t be able to protect your system.
  • Credential stuffing uses lists of common passwords & email addresses/usernames in random pairs to ‘stuff’ the website.
  • In brute-force attacks, the attacker tries a variety of passwords for a given username, usually attempting to compromise specific valuable accounts, such as admin accounts.
  • In a dictionary attack, attackers precompute information about commonly used passwords and then try to obtain an encrypted password by using a large set of words from the dictionary to generate potential passwords.
  • Phishing is when an attacker poses as you to get the user to disclose their credentials. The best way to prevent phishing is customer education.

Full post here, 6 mins read

Your system is not a sports team

Don’t be obsessed with a system that you have built or worked on for many months/years. Don’t focus only on improving the system you are working on.
Read more

Your system is not a sports team

  • If you are aligned to a mission, rather than being aligned to a specific system, you will work better for the success of the company.
  • Don’t be obsessed with a system that you have built or worked on for many months/years.
  • Don’t focus only on improving the system you are working on. Look at the larger goal your company is working towards and find the best utilization of your time.
  • Get your team aligned on the problem at hand and not around the tools & technologies to use to solve the problems.
  • Empower all engineers to focus on the impact of their decisions on the overall company by avoiding silos.

Full post here, 4 mins read

Slow down to go faster

Invest time to think about what you want to achieve while things are still simple. This way, you will not be thrown off track by complexity later.
Read more

Slow down to go faster

  • Take time to write automated tests instead of focusing on developing features alone. It will save you manual testing time later and avoid regressions as the code grows.
  • Take time when naming variables, classes, etc, so they are meaningful and self-explanatory. This will ensure other developers can easily grasp the contexts easily from the names.
  • Document your code as you write it. Structure it to start with a brief summary of multi-line functions, inline warnings, and explanations of tricky bits. Record intent rather than implementation.
  • Invest time to think about what you want to achieve while things are still simple. This way, you will not be thrown off track by complexity later.

Full post here, 4 mins read

11 rules of effective programming

Leave your code better than you found it. Look for repeatable patterns from references or projects around you or online that have implemented a feature with similar requirements.
Read more

11 rules of effective programming

  • Leave your code better than you found it.
  • Think about the total cost of ownership: cutting corners, skipping tests for later or creating temporary fixes have costly long term repercussions.
  • Look for repeatable patterns from references or projects around you or online that have implemented a feature with similar requirements.
  • Micro-optimization can easily make your code a mess and does not bring much value to users.
  • The cost of fixing bugs grows exponentially over time. Discovering problems early makes them easier to solve too.
  • Avoid multitasking. Studies show that it has a negative impact on performance and productivity.

Full post here, 8 mins read

Code reviews at Medium

When making a change that affects the UI, include a screenshot, and preempt questions. Add a description of why the change you made was needed.
Read more

Code reviews at Medium

  • When making a change that affects the UI, include a screenshot, and preempt questions.
  • Add a description of why the change you made was needed.
  • Encourage quick reviews (at least one person responding within 4 hours).
  • Build in small increments and request small PRs to move faster.
  • Promote a ‘safe to try’ culture where developers feel free to make a call on which approach of solving a problem they take.
  • Code reviewers don’t act as gatekeepers. They act as enablers.

Full post here, 5 mins read

Just keep coding! - A letter to junior developers

Develop the willpower, voraciousness, and ambition to learn more and the willingness to go the extra mile. Enjoy the process, rather than focusing on the results.
Read more

Just keep coding! - A letter to junior developers

  • Develop the willpower, voraciousness, and ambition to learn more and the willingness to go the extra mile.
  • Building a solid developer career is not easy or quick but the three most important factors are in your control: self-motivation, self-discipline, and focus.
  • The beginner stage is hard in terms of getting, retaining and understanding lots of information every day.
  • Enjoy the process, rather than focusing on the results.
  • Plan first, then code. When working on a problem, think of the different ways to solve it and don’t just go with the first solution you think of.

Full post here, 5 mins read

How to be a better code reviewee

Write tests before committing the code. Submit code and then test it together for review. Use descriptive commit messages. Group similar changes with a description for each group.
Read more

How to be a better code reviewee

  • Write tests before committing the code. Submit code and then test it together for review.
  • Use descriptive commit messages. Group similar changes with a description for each group.
  • Limit the code to review so that your reviewers are not too overwhelmed and have time & patience to consider the logic & depth of your code.
  • Don’t take comments personally. Provide resources and arguments to defend your choice if you believe you are right.
  • Take difficult problems or conflicting views offline. You will achieve consensus faster by discussing in person than over comments.

Full post here, 5 mins read

Musings on software architecture: monoliths to microservices

Microservices architecture may not be suitable for a new project from the start. It adds huge complexity overheads on your infrastructure. As a developer, you take on a lot of communication and coordination in addition to coding.
Read more

Musings on software architecture: monoliths to microservices

  • Microservices architecture adds huge complexity overheads on your infrastructure & may not be suitable for a new project from the start.
  • As a developer, you take on a lot of communication and coordination in addition to coding.
  • Even successful companies using microservices today typically start as monoliths.
  • When you start with a single team and a single product, it is logical to continue with a monolithic application.
  • Later, teams can split to be responsible for single services. Microservices may make better sense after that growth and when necessary experience and expertise is gained.

Full post here, 4 mins read

3 easy things to do to make your microservices more resilient

Test your system using chaos strategies. Have a plan to at least partially fulfill your service promise in case of a fault, whether it is a canned message or calling a different service as a backup.
Read more

3 easy things to do to make your microservices more resilient

  • Test your system using chaos strategies.
  • Have a plan to at least partially fulfill your service promise in case of a fault, whether it is a canned message or calling a different service as a backup.
  • Be conservative in what you send to a service and liberal in what you accept. Your unmarshalling logic should do just enough validation of responses and pull out just the data you need rather than executing a full validation.
  • When services fail, multiple iterations of the same message should not add inconsistencies to your users’ systems.
  • Use infrastructure that filters out duplicates. Or, track unique identifiers in the messages and discard those that are already processed successfully.

Full post here, 7 mins read

9 tips for a painless microservices migration

Document your URL route domains and ensure everyone follows the one convention. Be explicit about routes and methods. Avoid wildcard routes and wildcard verbs or HTTP methods.
Read more

9 tips for a painless microservices migration

  • Draw domain lines to define and document your business entities early on. Be mindful of how you cross the boundaries between these entities.
  • Document your URL route domains and ensure everyone follows the one convention.
  • Be explicit about routes and methods. Avoid wildcard routes and wildcard verbs or HTTP methods.
  • Assign URL endpoint ownership for clean formation of teams in the future.
  • Monitor URL usage by instrumenting the endpoints - at least graph the request rate, if not the error rate and performance of every HTTP endpoint you expose.
  • Kill dead code - delete it, not just comment on it. Have source code control for history, if needed.
  • Document the environment variables a service, class or module uses.

Full post here, 8 mins read

What’s in a name: Java naming conventions

Make methods and functions verbs, implying what they do in 2-3 words in camelCase. Use ‘get’ & ‘set’ to start the names of data fetching and setting functions.
Read more

What’s in a name: Java naming conventions

  • In the base package name, put your company’s domain in reverse order & then add the project name & maybe version - all in lower case.
  • Use nouns, written in CamelCase (with first letter capital), for class names. Class names should say what function or variable to expect from it as well.
  • Choose short, meaningful nouns for variables and fields, saying what values or variables they hold, in camelCase.
  • Avoid single character variables. Avoid underscore & dollar as first letters. For boolean values, start with ‘is’ or ‘has’, since they are yes/no questions.
  • Put constants in all-caps, with underscores to separate words.
  • Make methods and functions verbs, implying what they do in 2-3 words in camelCase. Use ‘get’ & ‘set’ to start the names of data fetching and setting functions.
  • Use similar conventions as classes and interfaces for enums and annotations, respectively, with enums in all-caps.

Full post here, 5 mins read

Python code optimization tips for developers

Optimize the slow code first. In the case of Python, PyPy helps you use less space and work faster than CPython’s typical bulk allows for.
Read more

Python code optimization tips for developers

  • Optimize the slow code first. In the case of Python, PyPy helps you use less space and work faster than CPython’s typical bulk allows for.
  • Profile codes (using CProfile or PyCallGraph, say) to analyze how they work in different situations and estimate the time taken.
  • Python strings tend to be immutable and slow. Concatenate them with the .join() method rather than relying on the memory-hungry (+) operator alone.
  • Use list comprehension rather than loops for faster coding and execution.
  • For memory optimization, prefer xrange over the range function to speed up the creation of integer lists.

Full post here, 4 mins read

5 things Rob Pike attributes Go’s success to

Writing a formal specification of the language. Making Go attractive for app developers to use. Establishing a strong open-source community.
Read more

5 things Rob Pike attributes Go’s success to

  • Writing a formal specification of the language.
  • Making Go attractive for app developers to use. Having key software written in Go created confidence in it.
  • Establishing a strong open-source community that supported Go. Being prepared for a tricky balancing act while listening and implementing.
  • Counterintuitive, but making the language hard to change. Yes, it creates rigidity but also makes it harder for old code to break.
  • Constantly listening to the community, but sticking to the things Go team believed are important from their specs.  


Full post here, 4 mins read

Why all engineers must understand management: the view from both ladders

You need to understand technical matters to manage a technical team well. Similarly, an effective engineer who wants to grow in a technical team needs to understand management too.
Read more

Why all engineers must understand management: the view from both ladders

  • Growing in technical & management ladders require different skill sets.
  • You need to understand technical matters to manage a technical team well. Similarly, an effective engineer who wants to grow in a technical team needs to understand management too.
  • You need management skills for your career growth as an individual contributor (IC).
  • When you grow in an IC role, you need these management skills to help you effectively collaborate with people on and outside your team, influence others as well as coach and mentor other engineers.
  • Understand why & how some processes in your company designed, executed and evaluated - for ex: recruitment or performance management process - to get an idea of how management systems work.

Full post here, 9 mins read

Making time for the good stuff

When you’re really busy, it is easy to get into reactive mode & you feel productive. But ensure a long term proactive focus on achieving significant goals too. Realize that your biggest potential impact comes from doing creative work that sets up future success.
Read more

Making time for the good stuff

  • When you’re really busy, it is easy to get into reactive mode & you feel productive. But ensure a long term proactive focus on achieving significant goals too.
  • Realize that your biggest potential impact comes from doing creative work that sets up future success.
  • Creativity needs time and space in your schedule.
  • Avoid interruptions & repeated context switching. Block 2-3 hour slots of time for deep work.
  • Make a note of any idea or inspiration that strikes you right when it does. If you can’t spend some time exploring it at right away, add enough context to be able to pick it up later.

Full post here, 5 mins read

Conquering impostor syndrome

Little wins are by far the most effective way to gain momentum that can stave off impostor syndrome. Submit a code fix even if it's tiny. Tweak the refactor code
Read more

Conquering impostor syndrome

  • Little wins are by far the most effective way to gain momentum that can stave off impostor syndrome.
  • Submit a code fix even if it's tiny. Tweak the refactor code. Do code reviews - they are a good way to think about how you would have completed a task without needing to complete it.
  • Bug filing also gets you thinking about ways a project can be improved, which may nudge your mind into other ways to make the project better.
  • Commit to accomplishing a task in front of your team.
  • Talk to your manager & colleagues when you feel stuck or not good enough. They will help you find a starting point to dive into coding.
  • Do a pair programming session to help yourself find the motivation to start even if you are feeling like an impostor.

Full post here, 6 mins read

Scalability problems: Hidden challenges of growing a system

Two main challenges of scaling distributed systems: centralization and synchronization. When scaling up, the system can run into computational limitations, storage limitations, and network limitations.
Read more

Scalability problems: Hidden challenges of growing a system

  • Two main challenges of scaling distributed systems: centralization and synchronization.
  • When one node has too much control, the main source’s capacity/capability limits the entire system in terms of resources it can handle or users it can serve.
  • When scaling up, the system can run into computational limitations, storage limitations, and network limitations.
  • Synchronous communication over a WAN is not only slower, but also less reliable compared to a LAN.
  • Synchronous communication across larger geographies can be an obstacle to scaling.

Full post here, 8 mins read

How to avoid data breaches in the cloud

Draft a good data loss prevention (DLP) policy. Build a solution against breaches as well as unauthorized extraction & deletion. Implement encryption in transit as well as at rest: TLS/SSL connections are a must, as are IPsec VPN tunnels.
Read more

How to avoid data breaches in the cloud

  • Draft a good data loss prevention (DLP) policy. Build a solution against breaches as well as unauthorized extraction & deletion.
  • Implement encryption in transit as well as at rest: TLS/SSL connections are a must, as are IPsec VPN tunnels.
  • Deploy your own advanced network monitoring tools. Use intruder detection tools to watch your entire ecosystem of applications.
  • Beware of a too-complicated ecosystem. Its layers can create blind spots.
  • Consider using API-based cloud access security brokers (CASBs).
  • Use micro-segmentation to restrict access privileges to those who need them, for only the timeframe they need them and only to the level of access they need.

Full post here, 4 mins read

Security assessment techniques for Go projects

Static analysis tools like gosec, go-vet, and staticcheck can help catch low hanging fruits not included in compiler errors & warnings. Dynamic analysis techniques like fuzzing, property testing & fault injection should be used for deeper results.
Read more

Security assessment techniques for Go projects

  • Static analysis tools like gosec, go-vet, and staticcheck can help catch low hanging fruits not included in compiler errors & warnings.
  • Dynamic analysis techniques like fuzzing, property testing & fault injection should be used for deeper results.
  • Dynamic testing tools like dvyukov/go-fuzz let you quickly & effectively implement mutational fuzzing.
  • google/gofuzz can help by initializing structures with random value.
  • For property testing, the leanovate/gopter framework addresses the shortcomings of other testers.
  • The build directives of the compiler can be used to perform name linking, and avoid renaming while getting testable access to desired functions.

Full post here, 15 mins read

Mitigating serverless lock-in fears

Deploy existing tools such as serverless framework, apex, claudia.js & be as cloud-native as possible using the backend service provided by your cloud vendor. choose a programming language that's supported by multiple vendors.
Read more

Mitigating serverless lock-in fears

  • Think lock-in cost = migration cost - opportunity gain from the migration. Maximize opportunity gain and minimize migration costs.
  • To maximize opportunity gain, deploy existing tools such as serverless framework, apex, claudia.js & be as cloud-native as possible using the backend service provided by your cloud vendor.
  • To minimize migration costs, choose a programming language that's supported by multiple vendors. Separate application domain from the platform and invest in a good architecture pattern.
  • Avoid integration tests heavily dependent on the cloud vendor and think of reusable abstractions instead.
  • Use standardized technology such as HTTP and SQL.

Full post here, 6 mins read

9 serverless security best practices

Map your application - consider the data involved, its value and services that access it. Keep using your WAF and API Gateway but apply perimeter security at the function level too.
Read more

9 serverless security best practices

  • Map your application - consider the data involved, its value and services that access it.
  • Keep using your WAF and API Gateway but apply perimeter security at the function level too.
  • Secure application dependencies to prevent new vulnerable packages from being used.
  • Look out for bad code that can trigger a self-inflicted denial-of-service attack from within your application.
  • Add tests for service configuration to CI/CD & PROD.
  • Make FaaS containers refresh to limit the lifetime of function instances.

Full post here, 4 mins read

The hidden costs of serverless

API Gateways tend to be a huge chunk of your serverless costs when you connect to a lot of APIs. The switch to serverless may not be worth it if data storage and networking are the largest chunks of your application’s costs.
Read more

The hidden costs of serverless

  • API Gateways tend to be a huge chunk of your serverless costs when you connect to a lot of APIs.
  • The switch to serverless may not be worth it if data storage and networking are the largest chunks of your application’s costs.
  • Two unknown costs of moving to serverless come in the shape of code maintenance and cold starts.
  • Assess the cost of extra code maintenance and the extra time spent switching to serverless.
  • Look for the pricing advantages of serverless providers that suit you best.
  • Utilize the free tiers from vendors. Sometimes they will be enough for you to run smaller workloads.

Full post here, 6 mins read

Will Kubernetes fall into the “shiny things” trap?

New & shiny can also mean immature. Developers must be cautious about excessive reliance on new technologies. Do not ask simply how to leverage Kubernetes at scale, ask how to use a single abstraction to cover Kubernetes.
Read more

Will Kubernetes fall into the “shiny things” trap?

  • New & shiny can also mean immature.
  • Developers must be cautious about excessive reliance on new technologies.
  • Do not ask simply how to leverage Kubernetes at scale, ask how to use a single abstraction to cover Kubernetes, on-premises visualization and the entire IT landscape.
  • To be cloud-native, you may need to rewrite your existing tech as containerized microservices.
  • Build your version for full compatibility with other vendors instead of complete portability and abstraction across environments.

Full post here, 6 mins read

How and why we switched from Erlang to Python

Mixpanel had coded one of their servers using Erlang. After 2 years, it became hard for them to debug downtime & performance issues. They switched to their de-facto language, Python. Having more code clarity & maintainability were the two main reasons for this move.
Read more

How and why we switched from Erlang to Python