Avi Das

Home for my work, ideas and else.

Frame Code Reviews as Gift Exchanges

The best metaphor I have found for thinking about code reviews is a gift exchange. The terms pull request and code reviews will be used interchangeably in this post.

The balance of writing code vs everything else that is necessary to be a successful member of a software team is one of the key challenges of our job.

Code reviews are an interesting mix. You have to understand someone else’s point of view, their journey through solving a problem in form of code. Or you have to face up to what everyone else thinks about code that you worked hard to write. Those reviews stand in your way of getting your code up to users and getting the emotional payoff from releasing something. The engagement or catharsis from building software is not an available reward when you are in code review mode.

Code Review

Moreover, a code review must take into consideration not just the code, but the project, team and the company into consideration.

These qualities make code review a great opportunity to practice interpersonal skills alongside your programming skills. The best engineers I have worked with take code reviews and responding to feedback on their own pull requests very seriously. Specific strategies that engineers use are different. Some review pull requests first time in the day, others end of the day or anything in between.

Framing is a powerful technique we can use when summoning the energy to do code review everyday. It would be to see every request for a code review or feedback you receive on code review as a gift. Someone values your intelligence enough to ask for your review or taking their valuable time to give you feedback that can only improve you as an engineer. Everyday, you receive these gifts. But you can also offer them to others, which in itself is a meaningful and satisfying act.

Viewing pull requests this way makes them less of a transaction, and illustrates code reviews as a win-win game. So next time you are opening up a pull request, think how you can make it easier for someone else to review. Can you link to the ticket, provide a screenshot/gif, added sufficient comments and followed good coding practices? Have you considered breaking your change into smaller chunks? Can you sit down with a reviewer and go over the changes in code?

Let’s make it easier for someone else to offer us this gift.

Thoughts on Button Push Driven Development

I was in a conversation the other day when someone mentioned

“We may only be a couple Moore’s Law iterations away from all software built by pushing buttons and WYSIWYG editors.”

This made me think of the software that we write today and the direction software is going. It also made me think of why I got into software and am still in this profession.

Lately, I have been very curious about voice as a computing platform and what that will do for applications we use in future. Thankfully, as software engineers, we don’t have to hypothesize. We can build it.

Digging into Alexa skills development has been interesting. While the technical documentation and development for Alexa is quite good, I felt a fair amount of internal resistance during the project. The potential of this new computing platform and the possibilities it will bring kept me going.

Yes Code

The building blocks of working with Alexa are intents, utterances and lambda functions. After a series of thirty or so steps of wiring up buttons, copying and moving templates around, setting up attributes gives you a working voice enabled app, upload zip files, deploy it and submit for app review in the Alexa app store.

Why did I feel the resistance? Any new tool or language will bring an initial set of frustration before we achieve a minimal level of proficiency. But Alexa development felt like using a software program rather than programming. It felt challenging the way gruntwork feels challenging and as opposed to intellectually stimulating. It also felt opposite to when I have felt the most joy during programming. When I had a strong grasp of the vocabulary of the language and the meta-language (libraries, development environment,runtime, etc), leaving room for higher level product/architectural decisions where most things are a tradeoff. This meant I had to do very minimal context switching. When writing an app for Alexa, it feels driven by context switching.

Books I Read in 2018

General/Personal Development

  1. The art of living (Thich nhat hanh): This is the best Thich nhat hanh I’ve read, composing his philosophy on living an examined life into day to day practices.
  2. Thinking in systems, a primer (Donella Meadows): Really, really smart author, systems thinking should be a required course in college.
  3. Ain’t I a Woman: Black Women and Feminism (Bell Hooks): Challenges a lot of assumptions, covering black woman’s involvement with race identity and feminism.
  4. When: The Scientific Secrets of Perfect Timing (Daniel Pink): Dan Pink’s books are similar to Malcolm Gladwell’s, distilling behavioral psychology research into easy reads.
  5. The Essential Rumi (Jalal Al-Din Rumi): Lately I have started admiring how much Poetry can accomplish with so few words. There is something very calming about reading Rumi.
  6. Sex at dawn (Christopher Ryan‎, Cacilda Jethá): An incendiary/challenging investigation into human/primate sexuality, sweeping across history to construct the narrative, much like Sapiens by Yuval Noah Harari.
  7. Deep work (Cal Newport): So good, anyone doing knowledge/creative work would be benefited by this classic.
  8. The life changing Manga of Tidying Up (Marie Kondo): I have been leaning towards minimalism, and Marie Kondo offers very actionable steps to cleaning up, and why doing this is related to the life we want to have.
  9. Flow: The Psychology of Optimal Experience (Mihaly Csikszentmihalyi): There is strong evidence at this point that time spent in flow state, (an state of effortless concentration on a single task), can be correlated to contentment/happiness. I really liked the first part of the book but thought it could be much shorter.
  10. Daring Greatly: How the Courage to Be Vulnerable Transforms the Way We Live, Love, Parent, and Lead (Brene Brown)
  11. So good they can’t ignore you (Cal Newport): Much like deep work, essential reading for those looking to improve their craft.
  12. How to change your mind (Michael Pollan): Eye-opening, challenging look at the resurgence of Psychedelics in mental health research.
  13. A life in parts (Bryan Cranston)

Core Tenants of Highly Effective Software Teams

This blogpost is my thoughts only and does not necessarily represent the positions of current or past employers.

We don’t build software in a vacuum. Software involves people. Beyond organizations of a handful of people, hierarchy is beneficial. We get teams, commonly with engineering manager/lead, product manager, designers and engineers. What becomes crucial for the software and the product delivered then is the effectiveness of the team. Throughout my career in the industry and being part of many teams in different circumstances, I have started noticing some key patterns that really drives standout results in teams.

  1. Believing in a common cause: The single biggest observation is that when a team of people believe in a common mission, they produce outsized returns. The most effective teams I have worked in all had a strong belief that they was a reason for the work they were doing. This also aids inter team collaboration over inter team competition, with teams often investing in tooling that makes the whole team better.

    Engineering leaders can play a key role here to frame a compelling mission for the team. Hiring for the right role also becomes super important as a highly motivated individual in a role can be 2-10x more effective than someone unmotivated with similar ability. Having a competitor or a common enemy is great since we are predisposed to bond over defending ourselves from common enemies.

  2. Psychological Safety: Google’s Project Aristotle studied 180 teams over two years and came to the conclusion that psycological safety was the best signal for how effective a team is. How comfortable do people in the team feel to share vulnerability without fear of retribution? How comfortable do people feel asking questions without fear of asking something silly or share ideas without fear of being shut down without listening? Team’s with high levels of psychological safety can have conflicts, but can deal with them in a mature way, being able to separate disagreement about ideas from disagreement with people.

    For more senior engineers/technical leaders, this is crucially important since they are in a position to determine this culture for the team. Forming strong personal relationships with the team can be really valuable for fostering safety within the team. People like their leaders to be human, and admitting your own fallibility is a great way to form trust with team members.

  3. Diversity of Thought: Diversity is a word that is commonly heard in the tech industry, and for good reason. Having diversity of people is a proven way to achieving diversity of thought, which is just one of the reasons why we must invest in software communities of women and minorities. Inclusiveness is one of the key pillars of psychological safety in a team, building on from the last section. Moreover, when software is aimed at global audience, but the team is homogeneous, it is easy to be fooled that a wide audience will get their needs met.

    Even teams of experienced contributors can fall prey to atrophy and decay, without fresh ideas so common in upstarts. A team of really excited newer developers may not realize that in balance lies the key to long term personal, team and product success. Diversity of experience in a team helps to avoid these common traps.

    Finally, cross functional teams can be more effective than teams exclusively focusing on frontend/backend/mobile. Recognizing the individual contributor’s interest in user experience/security/governance etc and enabling space for that one of the most enabling things an engineer leader can do.

  4. Growth and Ownership: It is immensely gratifying for people to feel that they are growing, and knowing that they are playing a role in the growth of others. When team members feel confident about the path in front of them can still have challenges, they are far less likely to be unmotivated and plateau. This is big for retention, since job changes frequently are a result of people feeling stuck and needing to make a change. It is costly to replace engineers, especially ones already trained and performing well in their role.

    A key intrinsic motivator for many is the feeling of ownership. Being able to really sink their teeth into a hard problem and come up with something they are proud of. Teams where people really believed that they have strong ownership of the product also care more about the end users experience, resulting in a better product.

    As engineering leadership, one of the best signals of good management is to have clarity in career ladders and promote the right people. A bias for people who make others around them better can be healthy. It is my experience that promotions should rarely come as a surprise to the individual or the team. Demonstrated investment in people as future leaders is also a major indication of a company’s belief in their people, sending them to conferences, training and giving license for creativity.

  5. Work Environment: This is a controversial one, but I do believe that companies today have bought way too much into the open office movement. While a return to cubicles does not feel desirable, dedicated interruption free zones (both space and time) are essential for good software. A chaotic office environment can also mean chaos in your codebase.

    Debates range whether standing desk or sitting is better, however many monitors are necessary. My belief here is that the team should be colocated but individuals should be empowered to find the best working situation for the track of work they are in. I have personally found that standing keeps me on my toes, making it great for lots of small tasks, whereas sitting is best for tasks that need deep thought.

When things fall apart

We do not live in a perfect world. Recessions, unexpected downsizing, market competition and many other forces can impact access to resources which could result in ways in a group of people come in to work together and stop working together. Lot of us have all worked in a team where that magic of a great team existed, and the team achieved things together what could not be achieved by individuals. It is important for us to be thinking with intention and purpose and help each other build and find teams to discover that magic.

Jersey Half Marathon 2018: Race Report

“Gatoradeee!! Water!” The sudden enthusiastic cheer after a period of silence was hard to miss. Looking up, I saw the 10k marker. I looked at my watch and I was about to PR a 10k. Except that I was not running a 10k. I was running a half Marathon and with more than half of the race still ahead of me, this was bad news.

Post NYC marathon last November, I was happy to have run my goal race in a good time. I knew I was hitting my upper limits with the Marathon, and without focus on shorter distances, I would not get faster. I focused religiously on the Tuesday tempo and Thursday speed workouts with the Dashing Whippets central park group. It was inspiring to see the people training for Boston Marathon putting in incredible work during some difficult months.

This season’s training posed many challenges, primarily freezing temperature, snowstorms, breakups. Every time I stepped out the door and breathed in the icy air into my lunges, everything inside me wanted to get back inside and wrap myself in a blanket. But the workouts had a way of enforcing discipline into my life. For Saturdays, I made the commitment to keep showing up and sometimes challenge myself by going with a slightly faster group.

The group kept me going. If everyone else have no problems showing up and putting in the work in dark and cold, I have no excuses not to. When I was in the pain cave during the Jersey Half, that was what going though my head. I am in the deep end, but I owed my 600 mile training cycle a good performance and take responsibility for strategic mistakes early in the race.

As I realized my mess up during the Jersey half, I realized I needed a baseline pace or I would fade. My inner voice said don’t fade, every second counts. So I found couple runners putting down 7:15 miles and making it look like cakewalk. Later I learnt that they were running the marathon. Talking to them helped me get some boost. After that, I found another pace group, and hung with them all the way to the end.

The value of this race as a developing runner is that it answers some lingering questions. How fast am I? Am I capable of taking my progress in training and convert it on race day? Am I training with the right group of people or just tagging along with faster runners for dear life. That’s what this half will mean for me, that I have improved this training cycle and while my strategy and mental game needs work, I can enjoy the following week knowing I made progress. Progress where I used to think there is no way I can hold a 7:09 pace for 13 miles but there is now data to prove otherwise.

So that was the Jersey Half. I am very happy with the result having converted a 10 minute PR. However, I would like to get there next time more gracefully and not feel totally wrecked at the end.

Lower Degrees of Separation With End Users

When working in software, one way to look at our profession is to say that we take architecture docs or designs and make code out of it. After years in the industry, we are trusted to come up with the architecture docs and work with a team to deliver the software. This absolves ourselves of responsibility in a way since even if the product fails, at least our code and systems were great. Companies today, however, are starting to see the limitations of software engineers being removed from the product decision making process.

I think we should reframe the problem: it is rather our responsibility as software engineers to ask, how many degrees of separation does it exist between us and the end user? Ideally, the end user would be the person paying for our service, although this gets more complicated certainly by ad funded or venture funded software. The exercise could involve us asking, what would it take to reach 10 users of our software? Would we have to go through our product manager, who then talks to the account manager or product support? These are likely the folks currently dealing with customer calls when our software bresks and waiting for the Zendesk tickets to be picked from the queue.

Who we are “engineering” for is a question we need to frequently ask ourselves. We should strive to be in environments where we are aware of our degree of separation and look for ways to cut down that separation. Without that frame, we can only have vague ideas of what the code we write is leading to, and end of the day limits the impact we can have.

It should also not always be the product manager’s job to always acting as the liason to translate user needs to us. When we are aware of user needs, it enables us to be proactive: to avoid that shortcut when building, or deal with that performance bottleneck early before it becomes a problem. We can also free the up the product manager to pursue broader goals such as product vision, market and competitive landscape analysis, etc.

Tomorrow, when you get to work, ask yourself that question. Do you know who your users are and how they use your product? How many degrees of separation would you have to navigate to find that answer? If you are not comfortable with the answer, maybe you can think of a way to change that.

Disclaimer: Thoughts expressed in the article are mine only, and does not represent the positions of current or past employers.

NYC Marathon 2017: Training and Race Report

I ran the NYC marathon this Sunday. On my fourth marathon, I was going for 3:45, came off with a 3:38, personal best by 4 minutes. More than the time, a vanity metric, I was happier about the race execution, doing negative splits, avoiding cramps and bonks/hitting the wall. NYC marathon is a technical and challenging course, but I found it could reward patience and training. It was also an emotional roller coaster for me, NYC being a focal point during majority of my time in the US.

Training

Big part of my marathon was made during the months prior. I have ran marathons before, most recently in Feburary in Austin, so I know my body is capable of handling trials of the 26.2. But I was carrying over my adductor injury from March, and since moving to NYC, its been a slow ramp back up on the miles. Joining the Dashing Whippets in NYC was a great decision, as all my running progress can be attributed to training with groups in Austin, Austin Runner’s Club and Austin Runner’s Meetup. Post June, I had to patiently wait for my speed/endurance to catch up as I stopped running since March. Whippets are a great group, as they are both very competitive and large enough where runners of different paces can have others to run with.

Once summer turned into fall, I was beginning to get the mileage adaptation back up. Besides the Saturday long runs, I worked on Harlem hill repeats on Sundays and speed work with the Whippets on Thursdays. Putting those fast and hilly miles were instrumental to getting myself back into marathon shape. Alongside with Tuesday workout with the whippets, I was able to get my weekly mileage up to 55 early October, more than I’d ever done. However, at this point I had to cut back since the workload was triggering overuse injuries in calves and ankles.

This is what my peak weak mileage looked like

Saturday: 20m long run (Whippets)
Sunday: 8-9m Harlem Hill repeats
Monday: Rest
Tuesday: 12m (Central park Whippets)
Wednesday: 5m easy
Thursday: 10-12m (Speed work on East Side with Whippets)
Friday: Rest

Web Payments by First Principles: Data Architecture

Once you start receiving payments on your site, congratulations! You are likely building something people want. But now you are at the point of having to manage payments data. Developers are generally aware that handling payments data should be done with care, but it is not immediately obvious what the different considerations are. In this blog post, we will go over strategies that you can follow to future proof your payments stack from the point of a fledgeling startup to a mature, stable business.

With storing payments data, there are quite a few considerations. What you should store and shouldn’t. In the event of a security breach on your site, you want your users financial information to be protected. Moreover, you want to architect your data storage for any current and future stakeholder requests. When it comes to payments, there are generally many stakeholders, let’s talk about a handful of them.

You are going to have technical stakeholders: your managers and other product teams who have questions about payments. Business entities that have to report their earnings for filing taxes and reporting earnings to shareholders who will need their data from you. As someone buying/selling online, your data needs to be stored in a way to make sure you don’t break compliance (PCI/SOX etc). Support/operations will be your stakeholders when customers have problems paying and come to you for help. Let’s get into how we can address these asks.

  1. Avoid storing sensitive personal information: Any application sending payments information such as credit card numbers, cvv to their server will have to become PCI compliant. This a financial and logistics burden which you can avoid for the most part by using a gateway provider such as Braintree/Stripe/Adyen. Usually your browser/mobile app will authenticate with the gateway and get back a token, which you can relay back to your server. This removes the danger of accidentally logging payments data, since the only data your server will see is a payments token. Even if you do get data breached, these tokens would not be useful to the attacker. This also removes the need for you to be PCI compliant which is tens of thousands of dollars in yearly expenses. More data you should avoid storing include any plaintext passwords and secret keys, common web best practices.

  2. Freeze request/response from external providers: You need to store every single request/response that you are making to your external providers, ideally in an append-only data storage. One of the common requests that we get in payments is to recreate the transaction as it happened. This is hard to do without storing the data at point in time of the transaction. Moreover, the business logic related to transaction such as taxes, fees calculations also need to be versioned and stored so that you can recreate the transaction at a certain point in time.

  3. Encourage immutability and lower side effects: Similar to the point above, you should never destroy payments or charging data. There are easy ways to archive and hide the data from users. This is very useful for historical financial reporting, triaging potential inefficiencies in your charging/billing process, and dealing with any disputes with your payments provider.

  4. Denormalize and index for searchability: Payments data is generally more write heavy but needs to be stored in a way for ease of triaging. Most payments providers provide unique request ids with their calls, and you should supply your own if that is possible. That way, you can set up bidirectional tracking, so that each individual call to payments is trackable from both sides. Setting indices on those unique ids is helpful for search. If the table is growing too large, it is useful to only keep upto a certain limit in your app and store the rest in a data warehouse such as AWS Redshift or Google Bigquery. The data warehouse strategy also enables you to normalize the data if you want easier access to data in one place and avoid expensive joins.

  5. Prefer cents as units instead of dollars: You can avoid a whole class of floating point bugs by storing in cents and using integers as opposed to float for all your arithmetic. Since floats in computing are really a representation of an infinite number, the can only be approximation and lead to hideous rounding errors. This is a good read on that topic https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency. Using established tools such as the money gem for currency in ruby is also very useful.

The above strategies will be useful for both internal and external users of your payments stack and help to protect your money and time when it comes to payments data. Please reach out via comments or email with feedback!.