Authorjackson

Do you need strong mental math to pass an engineering interview?

I got a great question from a viewer of the Intro to Architecture and Systems Design Interviews video I created (https://youtu.be/ZgdS0EUmn70). The question is: If my mental math is really weak, is it OK to whip out a calculator app?

Below is my answer, republished here so everyone can (I hope) benefit from it:

For mental math vs. busting out a calculator, I think it’s probably inconsistent from one interviewer to the next. In no cases do I think it alone could possibly cost you the interview unless you’re interviewing at some extremely mathsy place (like an algorithmic trading company, for instance).

I’ve seen a spectrum in terms of judgement towards lack of mental math. One end has people like me, who couldn’t care less if you use a calculator. I would probably award you points for self knowledge and for using tools to make you more effective.

The other end of the spectrum would be someone who is very strong in maths and who doesn’t think the problems you’re tasked with are of sufficient complexity to warrant a calculator. With an interviewer on that end of the spectrum, you might lose some love, but it wouldn’t counterbalance an overall strong performance. For instance, in hundreds of decision-making discussions, I’ve never seen lack of mental math come up as a deal breaker.

There is one caveat to all of this. If you’re using a calculator for numbers that engineers *should* know, that could hurt you*. For instance, if 2^5 comes up and you have to bang it out on your TI-83, you’re probably going to lose real points. Even as a more math-lenient interviewer, I would have some serious questions about someone if powers of two don’t seem familiar. Likewise powers of two on the big end. 2^16 and 2^32 are both important numbers that should be in your mind as a programmer.

Also sums and differences of common powers of two. If you need a calculator to sum 4096 and 4096, I would knock you down a rung in my estimation.

Hope that helps!

 

* Re: Numbers engineers *should* know, here are some helpful links:

This site is now available only via SSL

After much gnashing of teeth and furious Googling of obscure SSL related Apache error log messages, this site is now available via SSL exclusively. Huzzah.

Architecture and Systems Design Interviews

Welcome back for Episode 06 of The Unqualified Engineer! I wanted to switch things up a bit this time. On an earlier episode, one of our viewers Vahid Noormofidi asked about system design interviews, so today we’re going to go there.

We’ve talked a lot about coding skills on this channel so far. We’ve walked through a bunch of examples of coding questions you might face in a coding interview. Some good, some bad. Some completely shit and unfair. While coding interviews are super important to succeed at in order to get a job offer, a less well-known detail of Silicon Valley style interviews is that your ‘level’ comes primarily from your performance in a design and architecture interview.

For those who don’t already know, Silicon Valley interviews have about five or six common forms, with three being ubiquitous. There’s the coding interview, which we’ve covered a lot. There’s the background/behaviour interview, which tries to determine if you’re a good person to work with and someone who will be a good addition to the team. There’s also the design & architecture interview, which focuses on your ability to take a big fuzzy problem and come up with a broad, detailed plan for solving it.

Broad and detailed? WTF?

If it feels weird to hear ‘broad *and* detailed,’ it should. Design and architecture interviews are impossibly big problems that definitely cannot be solved in 45 minutes. The goal isn’t to come up with a bullet-proof, 100% complete solution to a massive problem. Rather, it’s designed to give you the chance to show the interviewer what aspects of the problem you think about, what solutions you can come up with, and how much technical depth and diversity you’re bringing to the table. This is why it so strongly influences what ‘level’ you get hired at.

If you’re wondering what I mean about “levels,” it’s probably because you haven’t worked in a company that is as structured as a Google or a Facebook. The basic idea is that engineers (well, all employees actually) get broken into numbered groups that map coarsely to a scales of a person’s ability to contribute value to the company.

For instance, at Facebook, a new graduate from university might get hired in at Level 3. Why Level 3? Fuck if I know. I think it’s probably just self importance — we’re all just *too* special and *too* awesome to start at Level 1… Anyway, that’s how it works. Your level determines your compensation, it determines what equity stake you might get in the company, and it determines what amount of value you have to add to the company in order to keep your job. Brutal, yes, but also somewhat reasonable in practice.

So anyway, back to design and architecture interviews. They have a few subforms like product design interviews, database/data storage design interviews, etc.. The most common type is a generic systems design interview.

A typical question for an interview like this has a really common form. You’ll be presented with a big problem that has only a few concrete details. For instance, in a Facebook interview, you might get asked a question like “Design a mobile app logging infrastructure that can handle a user base of 500 million monthly active users. The system needs to handle any sort of logs from mobile devices like application start, stop, errors, etc..”

Breadth

If you don’t come from a systems background, you might initially think an interview question like this is grossly unfair. Aand, well, you’re kind right to feel that way. A question like this is much easier for someone with experience designing systems like this, at that scale. It’s harder for someone who hasn’t. Before you self-cycle into existential rage, try to remember that’s exactly the point of the interview.

On top of that, bear in mind that there’s no correct answer to a question like this.

There are certainly incorrect answers (i.e. don’t say “We can solve this with Mongo DB, because it’s web scale.”). However, the universe of good answers is vast. Good interviewers are going to look for you to use your experience to give the strongest performance in the domain you should be strongest in.

For instance, given the question above, let’s say you’re a mobile product engineer. The interviewer is going to be looking for you to think about the product impact of a system like this. When should you send logs from a device? What will the performance impact be of collecting logs on the device? What about supporting iOS and Android and mobile web? Will application engineers be able to log arbitrary data or is it a strictly defined log set? Those are the kinds of details your interviewer should expect you to be strong with.

On the other if you’re a distributed filesystem engineer, your interviewer is going to expect you to be amazingly good at describing how to handle the scale of the problem on the server side and to think about strategies for reducing the amount of time it takes for new log data to become available. The interviewer probably wouldn’t expect you to think about the battery life implications in the same detail.

If you can deliver awesome answers to both the client and the server side of the problem, all the better. Some people can.

The important part is to play to your strengths while also showing reasonable technical breadth. If a mobile app engineer answered this question for me and kicked ass with the client-side aspects but literally didn’t address the server side at all, it would be tough for me to feel confident in hiring her. On the other hand, if she thought through as much as detail as she could on the server and gave me clear signals about what she does and don’t know, that’s better. Maybe she wouldn’t invent a server side solution as well as a distributed file system engineer, but that’s OK. That makes sense given her skills and specialisation as a mobile engineer.

Break the problem down

One of the most critical things for you to do in this interview is to break the problem down even more coherently than the interviewer presented it. Going back to the example problem I proposed, you might have noticed that some of the details aren’t in a usable form. If you did, good. If you didn’t, you’ve got some work to do.

For instance, I said “500 million monthly active users.” What does that even mean? Can you use a *monthly* active number to design a real-time system? The answer is yes, but not directly. You need to break it down.

The rookie might do this by taking 500 million and dividing it by 30 days in a month and then divide that numbers by 86400* to figure out the concurrent users. The reason this is a naive way to approach the problem is that people live near each other and live life in daily cycles. That means that you can’t just evenly split the user base by seconds in a month as though all people are evenly spread across the world and active, using your app evenly 24 hours a day.

So how do you capacity plan? If you don’t have an immediate answer, you should start by interacting with the interviewer. Ask about the geographic distribution of users. Ask about the biggest markets for the app. What timezones are most of the users in?

You should be able to arrive at the notion that (assuming the app is doing well!), some large fraction of the users will be active every single day and mostly during specific times of day. You can reasonably smoke up these numbers. Maybe you would estimate that 70% of the monthly active users are also daily actives and that 70% of those people are active at roughly the same time.

Why? Well, it’s very likely that night time in the big population centers of the world is going to be much quiter than the day time. A key insight you need to have is that to handle ‘the user base,’ you really need to worry about the peak-time traffic. So, if 70% of the users are going to be using your app every day and 70% of that 70% will be using the app all at once during peak times, your 500 million users is actually only 245 million at peak times. If we assume that means 245 million people in an hour, then we can start doing even finer-grained estimation. 245M / 60 minutes / 60 seconds nets out to about 68K second-to-second active users. That number is much, much more reasonable to plan for than a hazy “500 million.” *How many servers do you need to handle 500 million people?* is almost meaningless compared to the real question — *How many servers do you need to handle 70K concurrent users during peak hours? *

Meta point about breaking the problem down

Did I just make up a bunch of numbers based on no data? Yes. Could they be “wrong” numbers? Well yes, in fact they probably are. Does that matter? Not as much as you might think.

The interview is not trying to figure out if you can psychically derive the exact user stats and behaviours of an imaginary, complex system. Rather, it’s designed to see if you can handle a big fuzzy need in a reasonable way. Can you take a big, insane requirement and grind through it to figure out what sort of actual technical problem it poses.

Veteran systems engineers, devops engineers, and people who have had the chance to work on large scale problems before will have a leg up in this domain. That might seem unfair, but it’s really not. Remember, we’re not talking about school where you can study the hardest and get the best grade. This is real life. Valuable skills are valuable and who has them and who doesn’t is not “fair,” it’s reality. If you’re expecting it to be fair, you’re going spend a lot of time being frustrated.

Breaking the problem down continued

So, back to the problem, — we’ve decided we’re talking about 70K concurrent users. Now we have to think about what that means in terms of actual throughput. If you were trying to solve this problem in the real world, your bottom line for the server side will be *How much log data are we actually talking about here?*

Right now, you might be thinking — it’s impossible to know! If you are, you’re either not thinking critically about mobile use cases or you’re not experienced enough in this domain to have an intuition about this. The second is better than the first. Let’s think about some real-world bounds. *How much network bandwidth does a phone have?* *How much storage space?* If we assume that the logs are going to be generated by user actions — remember the problem details “application start, application end, errors, etc.” — then we have an excellent frame of reference for breaking it down further. How many actions per minute can a person do on their phone? Maybe the average person could send and receive fifteen messages. Or maybe they could consume twenty photos on Instagram. Maybe they can switch apps roughly four times. In any of those cases, we’re not looking at a massive amount of data here.

The novice will assume that we just need to guess some reasonable average number and stick with that (E.g. “half a megabyte, tops.”). The better engineer will grind through some concrete estimations based on the size of data. Maybe we’re talking about 20+ 32-bit integers that refer to entity IDs (photo IDs, user IDs, etc.) at least, probably some overhead for a data encoding like JSON, probably some strings for things like event types, and in the error case hopefully something like a stack trace to aid in debugging. So, at least a few hundred bytes per minute, but with an upper bound that could be pretty big in error cases (them stack traces, yo).

The best way to answer here — in my opinion — is to have an opinion and to make intentional, reasonable tradeoffs. Burning through hundreds of bytes of data per minute is a guaranteed shitty and expensive experience for someone using your product. So, be a empathetic system designer. Come up with a guideline and set some numbers based on giving a shit about the user experience. Perhaps that number is 5KB of log data per minute as a maximum, anything more gets discarded. That means that if a person uses your product for an hour, they’ll only rack up 300KB of log data that they’re paying for out of their own hard earned money. That’s like asking them to download an extra image every hour or so in order to give your company the data you need to make sure the app is working and to understand why it’s not. A reasonable trade off.

And again, yes, this is a made up number. The specific number is not as important as why you chose it and whether or not that choice was reasonable. I could have said 500KB per minute (I wouldn’t because not even Facebook’s bloated apps use that much bandwidth for metadata), but the most important part is *why* that number.

The reason I think taking a strong stance towards how a system should work is the better option is because it’s show experience, leadership, and ownership. Sure, I could just let the users’ activity dictate some reasonable number of logs per minute but what if my estimation leads me to some big number like 5MB per hour? My inner nurturer needs to kick in and tell me that logging that aggressively is abusive of user trust. My inner data analyst should be telling me that 5MB of data per hour per user is a glut of data that will mostly be giving redundant signal. User empathy, experience and technical leadership should be the guiding light here over a raw calculation.

In a real company doing real work, that’s what actually happens, after all. Product decisions are made by people trying to make the smartest tradeoffs. There are no right answers. The only wrong answers are ones that drive away users or lead the company to fail. The right answers are many and varied. This is why design and architecture interviews are so important for determining people’s levels.

Keep Going

This discussion is already massive and ranging, yet we haven’t even talked about the concrete details of a client implementation, a server implementation. We haven’t talked about client-side caching. About mobile networks versus WiFi delivery of logs. We haven’t talked about data-saving strategies like user sampling. We haven’t talked about how to collect log data from the server side, storing it long-term. We haven’t talked about how many people it would take to build a system like this. We haven’t talked about how many servers we’ll need to handle the peak traffic. We haven’t talked about how much that will cost. We haven’t talked about countless absolutely critical aspects of the problem. Nor could we in 45 minutes. That’s why you, as the interviewee, must keep going.

At any point if you’re looking to your interviewer for guidance about how to proceed, you’re losing points. Now, don’t get me wrong on this point. Needing to bounce ideas off the interviewer or get clarification is fine. Also, you might be legitimately stuck on the problem. If so, by god man — ask for a pointer. I’ve seen many interviews that resulted in a job offer include feedback like “The candidate started off strong but needed a small pointer on X. After that, she did really well.” Don’t be afraid to ask for help. Still, you should bear in mind that the more help you need, the more likely it is that you’re showing lack of experience, creativity, and/or technical leadership.

I don’t know anything about image processing pipelines, for instance. But, if you give me a problem related to image processing pipelines at scale, I have high confidence that I can keep exploring the problem space making meaningful progress for 45 minutes. In all honesty, I love these kinds of challenges and find them really energising. Not everyone does, but everyone who is a strong technical leader *can* do these kinds of explorations.

Failing this interview

One interesting thing to consider on this point is that Facebook, at least, don’t even do design/architecture interviews for new graduates. They used to, but consistently found that the candidates just didn’t have enough experience with applied systems problems to even begin solving the problem.

Not having experience enough to be able to digest a big problem like this doesn’t always mean you’re fucked. It is an important signal though.

For instance, I was once on an interview loop where we all decided to hire the candidate even though he faired poorly in the architecture interview. His coding skills were strong and he seemed passionate about our company as well as a good person to work with. We didn’t hire him though.

When the interview feedback made it up to the director level, the director stopped us and rejected the candidate. I was confused. Turns out the director did some mental math that I didn’t have the foresight to do. Yes, the coding skills were good and the candidate was a reasonably good communicator, team player, etc.. However, he was lacking in design/architecture ability. This on it’s own is no failure, but the candidate had 8 years of industry experience. He had worked in a strongly technical company for that long without ever taking on enough leadership to get good at reasoning about large scale systems. That is a red flag.

Like Bob Dylan says, you’re either busy being born or busy dying. In this case, our candidate had plateaued in his career — so, he was busy dying. It could have been for a million reasons, but to the director making the call it means making a tough decision about whether or not we can expect this candidate to advance in his career or not.

At Facebook at least, you have to keep advancing at least to level 5, which is roughly equivalent to “senior engineer” or “tech lead” in other environments. After that, you’re doing valuable enough work to stick around without getting promoted again. This candidate would not have gotten a level 5 offer and if he’s already 8 years into his career, it’s unlikely he ever would. So, we would be sentencing him to a short-term career at Facebook at best. It was definitely the right call.

Final points

Architecture interviews are formidable, open-ended problems that you definitely cannot exhaustively solve in the time allotted. If you have no idea how to solve these kinds of problems, you might start by checking out the engineering blogs of companies like Google, Apple, Dropbox, and others. The amazing thing about architecture is that most of the best companies are sharing all their work.

Even if you have no background in the work, you can familiarise yourself with the common patterns of system design by reading diversely from the blogs on the topic, watching YouTube videos of tech talks from conferences, etc.. If that feels like cheating, it shouldn’t. After all, the reason engineers at big tech companies are good at solving these kinds of problems isn’t usually because they do it all day, every day. Rather, it’s because they get exposure to the solutions in internal tech talks and write-ups. The information is available. Go turn it into knowledge.

Largest Rectangle in a Histogram Coding Interview Problem

Here’s the full text of the code from Episode 05. This is coded in JavaScript and uses the common approach of using a stack to keep track of the open rectangles.

Permutation Generator Coding Interview Question

Episode 04 of the series is available now on my YouTube channel.

This problem revolves around generating permutations of a sequence incrementally. Rather than pouring out a huge vector of output, this problem asks for a generator that can output the next permutation of a vector with every iteration.

For this video, I code in C++ and uses a functor to create the generator.

Calendar Conflicts Coding Interview Question

Here’s the video and code for the Calendar Conflicts video which walks through a linear complexity solution to a common coding interview problem. The idea is that you’re given a list of calendar events and you must find any events in the calendar which conflict.

There is an easy brute force solution to this problem, but the optimal solution is linear. The code here is written in vanilla PHP. If you’re interviewing at a company like Google, Facebook, Apple, etc., this is exactly the kind of coding interview question you might have to face.

Dinner Party Coding Interview Problem

You’ll find the text-form code from the second episode here. Following some very good critical feedback I got from friends and viewers, this episode is much, much shorter and focuses entirely on a coding challenge. The full video is here:

With this coding problem, you’re main challenge is generating combinations. There are some really fancy ways to achieve this. My favourite approach involves using bitmasks and Hamming Weights. Such an approach would just count up from 0 to 2^n looking for any number with a Hamming Weight of table_size. While that’s super snazzy, it’s also not super representative of what a person not familiar with these types of problems might come up with, so I didn’t take that approach for this video.

Instead, this video focuses on recursion. Reasoning about recursion can be a real challenge for our poor human brains. To ease this, in the video I draw the recursion chart shown here:

A diagram of a 4 choose 3 combination result created via a recursive function call.

A diagram of a 4 choose 3 combination result created via a recursive function call.

From this, you can get a basic idea of how a recursive approach to this problem might be solved. The really tricky thing for someone tackling such a problem for the first time is that you have to recurse twice in every function execution. Many people think of recursion as an approach where the function calls itself. The exciting thing about this algorithm is that the function calls itself not once, but twice!

One flaw with this code I noticed only after finishing the video and uploading it is that my groups argument is actually a bug. Because the default arguments are static across all calls to a function, this list will continue to grow and grow every time the find_dinner_parties function is invoked. It’s an easy thing to fix, but I ran out of whiteboard anyway. For those playing along at home, please add a list for groups in the call to combine_friends inside find_dinner_parties.

Least Disruptive Subrange Coding Interview Problem

Here’s the code from the first episode. This is a basic coding interview question that you might be asked in an interview at a tech company. You can see the video associated with this code here:

The problem here can be stated pretty simply. Imagine that you need a function that can take two inputs: 1) a list of integers and 2) another list of integers. The first list could be thousands of integers long. It can contain positive and negative numbers. It’s not sorted in any way. Any integer could be at any position. The second list is similar except that it’s equal in length to the first list or shorter.

What we want to do with these lists is find where in the first list we could substitute the second list, integer for integer, that would create the least amount of change in each integer from the original list. For this problem, we consider change to be measured in number line distance (i.e. absolute value). So, you can’t use some negative distance to offset some positive distance. If you substitute -2 for 2, that’s a change of 4.

An example would be something like this:

original =    [1, 2, 3, 4, 5]
replacement = [3, 5, 3] 

In this example, the “disruption” created by each possible substitution looks like this:

0th position swapping
 0  1  2  3  4
---------------
[1, 2, 3, 4, 5]
[3, 5, 3] 
 2, 3, 0 -- total disruption of 5

1st position swapping
 0  1  2  3  4
---------------
[1, 2, 3, 4, 5]
   [3, 5, 3] 
    1, 2, 1 -- total disruption of 4

2nd position swapping
 0  1  2  3  4
---------------
[1, 2, 3, 4, 5]
      [3, 5, 3] 
       0, 1, 2 -- total disruption of 3

You can see from this, that the best replacement choice here would be the 2nd index, which would create a subrange disruption of just 3, compared to all the other options.

So how might you solve this? Well, here’s a bit of JavaScript that aims to tackle the problem. This algorithm runs in O(n*m) time, where n refers to the length of the first input and m is the length of the second input. Interestingly, the longer the second input is, the shorter the run of the algorithm will be. So, the worst case is something like the length of replacement being half the length of original. In that case, the algorithm will do something along the lines of m*m work. It’s a constant memory problem in that it uses no additional arrays or objects to store state. I guess you could achieve this with a hash table if you just felt like wasting RAM. 😀

While this algorithm (as far as I know) is correct, it does leave many details unserved. For instance, I don’t address the potential to integer underflow by subtracting from the minimum integer value in JavaScript. Likewise, I could integer overflow by adding to distance until it bubbles over the maximum integer value in JavaScript. My test cases are also fairly limited and don’t test for cases like empty list inputs. Also, because JavaScript, I should be checking for null inputs and handling that case reasonably. I’m also not checking for the case where replacement could be longer than original. I’m sure there are like a dozen other defects here.

The point is not to create a bullet-proof library function. Rather, I was aiming to simulate a real coding interview focusing on what you’d have time to accomplish. Let me know what you think. Especially let me know if I got it all wrong!

Thinking About Knee Jerk Reactions

Original post here: https://www.facebook.com/jg/posts/10100265608855158

While I was running tonight, I had a thought about the extremely negative reaction so many privileged people have to being called sexist or racist or <insert thing here>-ist. It occurred to me that this group of people probably hates being unfairly labeled as something they don’t see themselves as and don’t want to be.

Then I thought about every black person I know who has been pulled over for driving while black. Or every woman I know who has been mansplained by someone who just assumed a woman wouldn’t know something. Or every gay person I know who has had to deal with homophobes who are convinced the evil gayness is going to rub off them and their children. People in this group constantly have to deal with people labelling them and applying a set of expectations to them that may not have anything to do with their identity.

Everyone dislikes having someone assume something of them unfairly. One curious thing about people in the second group is that most of the people I know who would fall into the second group actually have some compassion for the people in the first group. They don’t expect the people in the first group not to put labels on them. They deal with dozens of small instance of this every single day. It’s as inevitable as breathing.

Interestingly, the people in the first group can’t stand the idea of anyone putting labels on them. To them, it’s a hateful and unfair dismissal of some or all of their humanity. It’s bigotry and ignorance. An outrage! Maybe when you don’t regularly face it, you don’t build up any thick skin towards it. I still find it fascinating that so many people (and if I’m being real, I mainly mean white men here) don’t see how similar the natural emotions are from group A to group B or how dissimilar the contexts of those emotions are.

I’m guilty of this left and right. I complained relentlessly about how terrible it was getting into and out of the Tel Aviv airport because I was treated badly. They singled me out as a young(ish) guy traveling alone and grilled me. I griped relentlessly about what a shit show it was trying to get my visa to go to China. In both cases, a friend of mine who happens to have relatively darker skin just laughed at my frustration because he faces that kind of treatment every time he flies. He also comes from a country that doesn’t have a great political status relative to the US, so he has to play the “please can I have a visa” game for almost every country he visits.

For him, it’s a day to day pain in the ass. He reminds me of this every time I get indignant about the injustice. To me, it’s unthinkable. It’s outrageous. I suppose really, it’s just new to me. Now, I can understand where he’s coming from in a way that I couldn’t before.

The same applies when being called out for being sexist or racist or anything-ist in a way that doesn’t feel fair. It might be, it might not be — I’m not trying to answer that question. However accurate it is or isn’t, if you’re a privileged person, you might be feeling that sting for the first time. Rather than knee jerking away from it, take a minute to consider that it’s a day to day reality for people around you. How much shittier would it feel if that was the way people treated you all the time?

Birthday Question, Age 31

Original Post: https://www.facebook.com/notes/jackson-gabbard/birthday-question-age-31/10152781770934836

So the 21st was the day of the Birthday Question. It’s the 2014 edition and roughly the 4th year of asking it. I think for me, this is a fairly easy thing to decide on. Last year was a big year and one that I spent a lot of time reflecting about. I feel a lot more in touch with what’s actually important and where I’ve grown the most. I think the biggest difference between the me of today and the me of last year is that I can understand the gap between what I want for other people and what they need for themselves.

I’m kind of a steamroller. I usually have a strong sense of how things should be. I usually know what steps to take to get there. I’ve learned that if I’m acting alone or in some context where the outcome is objective and there are no strong feelings, my tendency to impart order onto chaos is a strength. Sometimes the grand future I see requires change in other people. In that case, this style of… let’s call it ‘assertive problem solving’ is actually problematic. I’ve learned why this year.

Last year, I learned to accept my flaws more than I ever had before. I learned that doing so makes me stronger rather than weaker like I had previously thought. This year, I learned that extending that love and acceptance to the people around me works exactly the same way. I learned that it was actually fear that kept me from loving and accepting the people around me in the first place. When someone has a major character flaw, I felt I had two options: push them away or hold a strong line about that issue and never give an inch.

On some level it’s probably good not to condone bad behaviours. So, in some small way, yay me for that. In reality though, my reaction to these flaws wasn’t based in a desire to help the person. No, it was to keep myself from catching the cooties. To keep me free from falling into that same flaw pit and being worse off for it. When I was young, this was a real risk and avoiding it, a valuable skill. This year I learned that now, it’s a mostly bogus vestige of being young and surrounded by people I didn’t want to end up like.

For instance, let’s say someone has a flaw that makes them a bad decision maker. It turns out that it’s pretty unlikely that I’ll absorb that flaw through unconscious osmosis. The very fact that I see the flaw means I’m probably insulated from it. It’s still in me to try to fix the problem. Importantly though, if I really want to make things better, there are much better things I can do than throw their flaws in their face or push them away. In fact, letting people know that there’s something about them that should be improved mostly has the opposite effect of making things better. At least, the way I was doing it — at arm’s length, trying my best not to let any part of them touch me lest I become the worse for it.

This year I learned that the fear of being bad is a really strong, growth-inhibiting fear. I learned that people are usually doing their best. That whatever we should be doing differently we probably would be doing if we could. Someone who comes along and happens to see a better way isn’t really offering much by just telling the person about how things could be.

It’s kind of like seeing a person who is straining to live life in a scary world. They’re wearing a suit of armour for protection. Old me would see the suit of armour and say, “Hey, if you weren’t wearing that silly helmet, you’d be way better off!” At best I sound like a complete dick. At worst, I only make the person pile on more armour — to guard themselves against me and other people who would criticise them for being guarded in the first place. The reality is that the person is already doing the very best they can, struggling to feel good. They aren’t armoured up for no reason. That’s the gap I used to miss. Or maybe wilfully ignore is more accurate — a sort of self-protection in its own right.

It’s interesting that it was so hard to see this. It was hard work to realise that the way I kick myself for not being perfect is actually unhelpful. It’s been just as hard to generalise that acceptance to everyone around me. At least, it’s certainly much easier to just have a simple pass-fail test and cut off things that I’m nervous about and can’t use force of will to change. The problem here is that this makes me a very prickly person. Someone for whom you either pass or fail. If you fail, you experience a very different, compassionless side of me. Not because I want to be that way, but because it’s the only way I can definitely keep you from making me something I’m afraid of being (rightly or wrongly). At least, so I thought. This has been such a useful growth strategy, it’s been really hard to let it go where it doesn’t actually work.

At the same time, I can see now that almost everyone I know can think of at least one thing they would improve about themselves. Most of the time, they can think of lots of things. So, it’s not as if they’re just fundamentally flawed people who might drag me down in blissful ignorance of their toxicity. In fact, if they could get to a better place, they would. In all likelihood, they will in time anyway. But what if I see something that trips the ‘fix it or GTFO’ alarm in my head? How do I fix it?

Well, the biggest lesson I’ve learned this year is that love helps. Acceptance helps. It turns out that I and so many people I know do weird shit because we’re armoured up for conditions that aren’t obvious. Life is stressful. The world is dark and terrible at times. No one I know carries around protective gear just for funsies. The thing that has helped me need less armour was chancing to trust people more, going against some very well-trained instincts. Trusting that, probably, everything will just be okay. That the moments where things aren’t okay also aren’t the end of the world. I’ve learned that if I want to help people, it’s not a hard push for a grand and beautiful future they need. Probably, they need some love and some acceptance. With more goodness, they’ll probably get to a good place on their own. It’s pretty likely it might be a place even better than what my purview included in the first place.