“Why are manhole covers round?”: The Software Interview Has Changed.

Comment

“Why are manhole covers round?”: The Software Interview Has Changed.

During the 1990’s, the tech giant Microsoft lived famously for a signature step in their interview process where they asked the head scratching brain teaser, “Why are manhole covers round?”. The question was asked as a creative problem-solving question aimed at identifying how a person approaches an unexpected obstacle with creative thinking and adaptability. 

Of course there is more than one possible answer. Manhole covers are round so that they never fall into the hole they are covering, so that they are easier to relocate by rolling, and so can be easily placed over a round hole without tedious repositioning.

In a similar sense, there is more than one way to crack the coding interview today.

It’s unlikely that a top FANG company in today’s market will decide your fate based on a simple brain teaser, but they are still searching for the same qualities in their interview process. Are you creative? Are you smart? How do you handle a problem that has seemingly infinite (or no) solutions? 

The typical interview for a tech company can span the course of several weeks and includes many tiers:

Phone Screen

A typical technical interview will start with an initial phone screen. This is a low intensity conversation. You can expect questions that are behavioral in nature, or perhaps pertain to your work history. The interviewer is likely a recruiter that is feeling out your general experience before sending you on to the next step.



Technical Questions

This next step will be much more technical and will likely include a member or members of your potential team. There might not be any coding involved just yet, but you can expect the interviewer to ask you technical questions that will be relevant to the job at hand. Be prepared to discuss version control, life cycle development, and workflow management. Don’t be unnerved by these questions, trust your experience. If you find that you were unprepared, use this encounter as an opportunity to prepare for your next interview by asking informed questions aimed at learning. The interviewer will respect your honesty and can give you invaluable advice.

Coding Interview

If you make it past this round you can expect another interview that digs into your live problem solving ability. This may be structured using a whiteboard, live coding, or a take home project. This is probably the highest intensity chapter of your interview journey and the time you took to prepare for this round will be fully transparent. You should be able to articulate your thought process during the interview. Do this by dictating your actions as you complete them or vocalize your need to gather your thoughts. Don’t be afraid to ask questions, especially if you are not familiar with the language being used. Remember that this assessment is meant to gauge your problem solving ability and may not require 100% completion. Remember, just like the problem of the manhole cover, there may be more than one correct solution to the problem you are facing. Make sure your solution is creative, but not overly simplified.

Best Fit

If you’ve conquered these challenges then likely your employer will be making their selection based on best fit. They'll do this by scheduling peer interviews or 1:1 interviews with higher ups. Your honesty through the process up to this point will be your greatest weapon. 

Be sure to never misrepresent yourself. The real you might be exactly what their team needs! If the company interviewing you finds that you are not the best fit, this isn’t your fault, the perfect role is right around the corner. All you have to do is be prepared to greet it.

The modern engineering interview is a marathon, not a sprint. It takes practice to master the individual chapters of each interview. Outco has helped ~2,600 engineers come closer to an average base salary increase of 37%. Join one of our info sessions to see if our tools can upgrade you skill set and take your interviewing skills to the next level!

Comment

Using A Pattern Based Approach To Nail Behavioral Questions

Comment

Using A Pattern Based Approach To Nail Behavioral Questions

Most developers have learned by now that when we approach a system-based problem programmatically, we are looking for identifiable patterns that lead us to simplified conclusions. This is something we take very seriously at Outco, but not just when we are met with a code-based problem. When software engineers come to know this pattern-based approach taught at Outco, that same mindset can be used to help answer behavioral questions as well.

For example: if the interviewer is trying to figure how self-aware you are about your weaknesses, they might ask -

1) What are your biggest weaknesses? 

Or

2) Tell me about a time you failed? 

Or

3) What feedback have your managers given on improvement? 

Or

4) What are your T3B3? (Top 3 and bottom 3 qualities) 

Or

5) I talked to your last 3 managers. They told me what your weaknesses are, and I want to see if you can tell me what they said.


These five unique questions are all aimed at acquiring the same information about you: How well do you know yourself? 

Instead of drilling a mountain of questions and preparing responses for each of them,  try to figure out what your interviewer is actually trying to learn about you with each behavioral question. By understanding the motive behind each question, you can easily nail your response by knowing how to represent yourself in the best context.

The majority of the behavioral questions can be divided into the following three patterns:

Icebreakers

Example-- Tell me about yourself.

Trying to start a conversation and find ammunition for follow-up questions.

a) Keep your response around a one minute pitch. This is never the time to ramble.

b) Sell yourself by focusing on specific projects and accomplishments. If they were to follow-up, it would allow you to give evidence of your work ethic, organizational skills, and curiosity.

c) Start with the most recent gig, and go chronologically backwards. It’s always best to end with what you’re looking for in your next role.


Situational

Use the S.T.A.R method to identify and respond to questions that fit this pattern. “S.T.A.R” is an acronym that can help you remember exactly how to answer a situation based behavioral question. Just spell it out:

Example -- You're working on a program where some aspects of the features designed were completed with errors. What do you do?

a) Situation: Give context and background info.

b) Task: What you had to do (Not what your team did - but what you did).

c) Action: What are the details to your role and how you completed the task? This will be the longest part of your answer.

d) Result: What you learned and what you would do differently. This answer should be positive and quantifiable.

At Outco, we’ve learned the best way to get better at mastering these techniques is through practice. We have professional coaches who give you feedback in real-time as you practice through mock interviews. If you’re not ready to try Outco’s program, try to find a friend or colleague whom you think might be able to give you good feedback as you work through this type of pattern.

Philosophy

Example — “How would you approach a disorganized engineer on your team given their exceptional performance?”

This one should be familiar for folks looking at leadership positions, and typically takes the frame of “how would you approach XYZ…” Your interviewer wants to be sure that you will be a great fit and share common values held by the team. Its is always best to be as honest as possible when answering these types of questions. A good fit works both ways!

Identifying patterns and executing effectively is one of the most important tenets of the Outco strategy. By knowing what to expect and how to respond, you will find that you are better able to accurately represent your best qualities and make serious inroads to the role you’ve been searching for.

Attend our Info Session to be better prepared for your next technical interview:

https://www.outco.io/info-session-signup



Comment

How I Became a Successful Software Engineer

Comment

How I Became a Successful Software Engineer

Preface

An important part of Outco’s program is being able to learn from other people’s experiences in the community. 

Whatever circumstances or background you come from, our experiences are rarely completely unique. A lot of folks who are entering the tech industry, or looking to pivot within it, probably have something in common with you. Whether it’s a passion for a particular sector, similar majors, shared hometowns or universities, usually you’ll be able to find something in common with your peers.

To me, this has two potential major impacts. The first is that it can help provide practical advice for navigating the job search. People who’ve had to walk a mile in your shoes can give you tips for how to travel the road ahead. And while some of the value comes from being able to answer questions you have, the real value comes from them being able to answer questions you haven’t even thought of yet.

The second impact of listening to others’ stories is that it helps humanize the industry and the process of finding a job. These are your peers. They are potential co-workers, managers, interviewers, competitors, mentors and friends. But most importantly, they are people like you and me. They have their individual hopes and struggles like anyone else, and the sum of their experiences is what shapes the community and culture of tech. How you personally fit into this fast-paced and ever-changing ecosystem is up to you to figure out. 

But if I had one piece of advice to pass on for how to think about that question it’d be this:

“People are the ends, not a means”

The rest of this post is organized as a recap/summary of a panel of Outco alumni that highlights some of the main questions and advice they had to share. Enjoy!

Succeed in Tech through Curiosity

This section applies both to the job search but also throughout your whole career. Folks on the panel gave a wide range of answers to how they got interested in working in tech and what motivated them personally, but there were a few recurring themes throughout the talk.

A lot of folks started out in some kind of tech-adjacent field and ended up gravitating towards software engineering over time. Usually they were pursuing some kind of math, engineering or science degree and found that they needed some kind of foundation in computer science or programming to continue moving forward.

From there, the combination of career opportunities and their natural affinity for software engineering work is generally why folks moved into the tech industry.

It’s hard to overstate the importance of that second part as it pertains to being successful in this industry. Technology changes very quickly, and the systems you’ll be working with are complex and require the ability to learn rapidly. You have to become familiar with the unknown very quickly, and solve problems today that you didn’t know existed yesterday, and don’t fully understand today. Oftentimes under tight deadlines or market conditions that you exist outside of your control.

What most panelists seemed to agree on was that thriving under those conditions comes down to having a natural curiosity about the world. Being able to step outside of your comfort zone and perform requires a certain level of focus and immersion into the task at hand. You need to be able to go down the rabbit hole and play with the problem in question until it makes sense. You’ll need to go through the list of possible solutions and systematically start ruling options out by considering the tradeoffs of each one. 

The way to do all this without it becoming overworked or exhausted is to find a rhythm you are able to enjoy. Solving problems doesn’t need to be stressful. People solve jigsaw puzzles, crossword puzzles, and sudokus all the time to relax. 

Something that I remember distinctly early on when I had just started solving algorithm problems was the feeling of everything clicking when I understood how to convert numbers from base 10 into binary. It gave me this profound realization about the world and how the number system we use is somewhat arbitrary, and there are other, potentially more useful ways of thinking about them. There’s a certain sense of accomplishment when you solve, discover and create. Like you’ve had a real impact on things and that your work had a purpose. 

Curiosity and focus is a powerful mindset that can give your job search, and later on your career, greater longevity and meaning. Understanding why you’re doing something is key to being able to lose yourself in your work and not need to constantly question what it’s all for. There’s actually a great book about this called Deep Work:

https://www.amazon.com/Deep-Work-Focused-Success-Distracted/dp/1455586692

Coding is important work that will continue to be needed in the next five years and into the foreseeable future. Schools these days are starting to teach children as early as 6 years old in certain countries to give them a head start. Politicians are pushing people towards this field all over the world with incentives and programs to help underrepresented groups in the industry. And while certain things have gotten easier and been automated or commodified in the last few years like web or app design, we’ve barely scratched the surface on what we can do with more advanced technologies like machine learning.

Keep in mind that not everyone who is reading this and just getting into programming as a career will actually still be doing it in 5 years. People’s interests change. 10 years ago I thought I’d be doing biotech research. 5 years ago I thought I’d be doing some type of finance. 5 years from now I might be a full-time content creator. Who knows? There are a lot of ways to contribute to and profit from this technology boom we are all living through. 

Succeeding in this environment is both easy and challenging at the same time because we’re in a rising tide that’s lifting all boats at the same time. And yet, things can be disrupted very suddenly and we can be left scrambling to catch up on the latest tools, languages, companies and industries.

But if you go in with the right mindset and long term plan, you can carve out a fairly large piece of this growing pie for yourself.

Finding a Supporting Community

Having a good mindset is key, but it alone isn’t enough. Who you actually surround yourself with to support you and your goals is equally if not more important. Here’s why.

When I was working at Outco, most of the time things ran smoothly, but I also learned that given the sheer volume of people we were serving and classes we were teaching that the unexpected was expected. 

There were times I had to deal with people crying, people being disruptive in class, or just straight up leaving because of something they carried within themselves and then something that happened while there that set them off. 

Any time you mix a group of N people together, there are 2^N possible subsets, each with their own unique dynamics. People with different backgrounds, cultures, or personality types that didn’t necessarily mix well with one another. Sometimes someone might just be having a bad day, or got laid off or dealt with a painful rejection that they hadn’t told anyone about yet. 

It was a controlled kind of chaos that all made sense. After all there were tens of thousands of dollars on the line and people needed to be learning abstract concepts in a compressed timeframe while solving problems under pressure. It can feel like a very chaotic and stressful environment to operate in at times. Which is why it’s important to have systems in place.

I highlighted some of the chaos and challenges of accelerated learning environments, but the pros definitely outweigh the cons. 

Having a community to go through similar struggles with is key to succeeding. As the line in Game of Thrones goes:

“When the snows fall and the white winds blow, the lone wolf dies, but the pack survives”

Everyone on the panel agreed on the value of community. We’re social creatures by nature. We learn from watching each other and seeing things from each other’s perspectives. You can bounce ideas off one another, share notes, provide guidance, or consolation or motivation. All of which are important when dealing with rejection, frustration and failure. 

Specifically in this job search, a lot of folks are interviewing at the same companies and can provide insights into their hiring processes, and sometimes even the exact questions that will have been asked in the past and will be reused in the future. When watching someone else solve a problem you might find a completely novel approach to thinking or visualizing it. Even if they don’t get the right answer, or it’s a dead end, there’s still value in seeing what not to do. My advice there is to always approach those practice sessions with a dose of humility because your time in the hot-seat is never too far off.

Most of us suffer from some degree of Impostor Syndrome and/or Dunning-Kruger Effect, so having people around us who can help us see things more clearly than we’re able to on our own. 

We all need role models, but I mean that in a slightly different way than I think it’s commonly used. I’ve never met someone who I wanted to be EXACTLY like. But I’ve met a lot of people who I admired some aspect of and that I hoped to emulate to some degree. 

The thing that can be tricky though is knowing what it is that you want to emulate. Sometimes it’s one of those “you’ll know it when you see it” kind of thing. But that’s one of the benefits of the chaos of community: You end up surrounded by like-minded and not-so-like-minded people. 

And sometimes the not-so-like-minded people are even more valuable to be around because none of us are perfect.

Practical Advice for Optimizing Interview Prep

This section is organized more into a set of shorter  points with practical advice people on the panel had about what helped them throughout their job search journeys.

The Power of Reflection

https://www.kevincsnyder.com/what-success-really-looks-like/

It’s important to always keep yourself moving forward, even in the face of setbacks. You gotta find ways of getting up in the morning and staying motivated. This isn’t a smooth process most of the time, and that’s okay. You’ll have hyper-productive days, and then days where you don’t get much done. But regardless, you need to keep going. And one thing I’ve learned is that if you can see the trajectory, it will help you keep going.

A key to being able to do this is create a practice of reflecting on what you’ve learned, how you’re feeling and what’s on your mind. I do this personally through a daily meditation, some people do it through journaling, others do it through positive affirmations. 

So experiment with ways of drowning out the noise of modern life and focusing in on what’s important and letting go of what isn’t. It’s really about finding what works for you. 

The key is comparing yourself to who you were yesterday, not who someone else is today. Not just because appearances can be deceiving; everyone has a lot going on under the surface. But because the present will always be your point of origin. 

And remember, sometimes you just need to sleep on stuff.

Don’t focus too much on Titles

Unlike being a doctor, or lawyer, being a software engineer isn’t really a “legal” title. It’s more about a mindset or lifestyle. This may be changing, but for now, things are still the wild west out in tech. 

There isn’t a point where you learn a certain language, or tool where you get a certificate that says you are an engineer. It’s the process of you building things and improving your understanding of the field over time. It’s designing, trying new things, failing, rebuilding and repeating. 

And then one day you wake up, and you’re just there.

Learning how to Learn

Being able to learn new skills is a meta-skill that I’ve talked about previously. These are just some tips on how to become more efficient at it.

You gotta know when to take breaks and when to power through. Usually the 30 minute rule is plenty for most problems. If you are completely stuck for more than 30 minutes look for the solution or find a coach to help you through the problem.

You’ll also learn a lot more about a problem by then teaching the solution to others. The key lies in the process of figuring out how to deliver the material in a digestible and communicable way. Others will thank you for doing this, and you’ll really solidify your own understanding. 

This is also where soft skills come in handy. Being able to articulate exactly what you’re thinking was up to the point where you got stuck can help you solve the problem and help others be more efficient with the help they are offering. 

You should also try different ways of solving the same problem, and occasionally revisit problems you’ve solved in the past. You’ll find more efficient ways of solving it, ways of solving it in fewer lines of code and even find clearer ways of naming variables.

Always track your progress, whether that’s in a spreadsheet of jobs you’ve applied for, or a github repo storing all the problems you’ve solved. It’ll help you build self-awareness and confidence of how much work you’ve put into things. 

And recognize that the skill you’re trying to build is the ability to solve a general category of problem rather than memorizing specific instances of problems.

Interview Advice

Always remember you are talking to other human beings. You are trying to see things from other people’s perspectives and those aren’t always clear. That’s why there’s value in reverse recruiting. Reach out to people on linkedin and other social media sites. Pick their brains, learn about their stories, see what resonates. 

Then when deciding on whether to accept an offer or when deciding between two companies you should always evaluate the people on your team, since you’ll be spending a lot of time with them. You should also see if the company’s values align with your personal values and goals. And of course you should evaluate the financial aspect of the salary and the stock they are offering you. 

Remember your worth, and that the ultimate bargaining tool is being able to walk away from an offer. Interviewing is a marathon and a momentum game. So be persistent, and try to get as many as possible.

Conclusion

Hopefully you found some value in this article, I know I had a lot of fun writing it and participating in the panel. 

There will be plenty of other events and talks in the future, so feel free to sign up for them at Outco.io if you’re interested in learning more about the program and accelerating your career in tech





Comment

An Overview of Networks

Comment

An Overview of Networks

Preface

Before diving further into how to decipher extraterrestrial languages, we need to take a step back and make sure we have a solid understanding of the main tool we have at our disposal for arriving at a solution.

And though the title of these articles gives things away a bit, the connection between this problem and graph data structures isn’t immediately obvious. However these data structures have a broad range of applications in the real world, and mastering them is going to be the key to cracking this problem, and similar ones during technical interviews.

The reason for taking the scenic route towards a solution is to help you develop a deeper understanding of the core concepts this problem leverages, rather than just helping you memorize one particular approach. The goal here, as always, is to be able to see all problems like this as just variations of a larger pattern that shows up again and again in interviews.

And if I’m lucky, you’ll also walk away with a greater appreciation for the elegance and beauty behind graphs, both conceptually and in the real world.

So with that said, let’s jump in.

What are Graphs?

The simplest description of a graph is just that it’s a collection of relationships between things.

Which I want to acknowledge isn’t a very helpful definition on its own, but I do think most of us have some intuition about them.

They’re more commonly called networks or webs, and they appear in a lot of real-world physical structures like the brain, road systems, spider webs (duh), underground fungal mycelium networks, molecular bonds, or galactic supercluster filaments. But they can also be used more abstractly to model things energy flows in ecosystems, flight routes between airports, trade between countries, or links between sites on the internet.

They have two basic components: nodes and edges.

Screen Shot 2020-12-07 at 8.48.16 PM.png

The nodes, also called vertices, represent the collection of things, and the edges are the relationships between those things.

Both nodes and edges contain some information within them about the things or relationships they are modeling.

So using the airport hub example, each airport would be represented by a node that contained the airport name, the three-letter code, the number of terminals and gates, and the list of airlines that it services.

The routes available between different airports would be the edges, and those would have some information about which airlines fly that route, the time/distance between those airports, and what times those flights run.

Screen Shot 2020-12-07 at 8.50.08 PM.png

There are a ton of real-world business and software engineering applications for graphs, with everything from databases, to server architecture, to UI/UX design, to data modeling.

Graph database

In computing, a graph database ( GDB) is a database that uses graph structures for semantic queries with nodes, edges…en.wikipedia.org

What Are User Flows In User Experience (UX) Design?

The concept of flow in UX design was first coined by the psychologist Mihaly Csikszentmihalyi. He deemed it a highly…careerfoundry.com

They are so prevalent that most people don’t tend to think about the fact that all social networks and the internet itself are built on top of the idea of graphs.

Which shouldn’t be surprising.

To paraphrase the late Steve Jobs:

“Great technology is invisible.”

What are the properties of Graphs?

In the context of graphs as data structures, they exist at the top of the hierarchy, where most other data structures exist as some more constrained version of them.

For example, a linked list is just a graph that can only have one connection between nodes. A binary tree is a graph that can only have two connections. And an n-ary tree, like a trie, is just a graph that can’t contain cycles.

Screen Shot 2020-12-07 at 8.51.50 PM.png
Screen Shot 2020-12-07 at 8.52.45 PM.png

This makes them both highly flexible in what they can be used for, but also more complicated to learn because constraints tend to simplify things. They allow you to ignore more potential edge cases that can arise in general graphs.

This is also why I think it makes sense to learn graphs after learning the others because they require some more considerations when performing the usual operations associated with building and traversing them.

Graphs themselves come in a variety of different flavors, which again hinge upon relaxing or tightening certain constraints.

Let’s start by looking at one of the more basic kinds, which are unweighted, and undirected. An example of this would be friendships on Facebook.

These model symmetrical relationships, meaning if you are my friend, then I am necessarily your friend.

And they also have no distinctions between different relationships. Meaning there is no additional qualitative information between Alice and Bob’s friendship than there is between Alice and Charlie’s friendship.

The next, broader variety are unweighted and directed graphs. Some examples of this kind of graph are followers on Twitter or Instagram.

I don’t necessarily need to follow you, in order for you to follow me.

This allows you to end up with situations where a few people have millions of followers and then most people who have a few hundred or a few thousand followers. There are some interesting real-world implications to having this dynamic.

Screen Shot 2020-12-07 at 8.53.58 PM.png

Just to name one example, it means that the architecture of your systems have to handle posts differently, depending on the number of followers that someone has because of the difference in relative volume. This is because it takes far fewer system resources and design considerations to handle a post going out to a few hundred people and then handling all the responses than it does to handle a post potentially going out to millions of followers.

And as a heads up, this is the type of question that is commonly asked on system design interviews.

And then the last kind I’ll cover here are weighted, directed graphs.

Screen Shot 2020-12-07 at 8.55.48 PM.png

These are graphs where the relationships between nodes have some kind of quality to them. Using the airport example, this would be the distance between two hubs.

You’ll see the idea of weights pop up quite a bit in things like machine learning, where neural networks use weights between nodes to perform computations and make decisions.

And there is even an element of weighting between friendships/followers on social networks themself, though it isn’t captured in the relationship itself.

The way to think about this is in the frequency in which you are shown different friend’s posts.

If you Alice and Charlie send each other messages every day, and constantly like and comment on each other’s posts, then there is an implicit understanding that they are more closely connected than Alice and Bob, who may not interact much at all. Though everyone is still friends, Alice and Charlie’s posts will pop up more frequently in each other’s feeds, because the algorithm is prioritizing their posts more highly to each other. This is an implicit weight between two nodes, though that information does have to actually tangibly live somewhere.

And this is all with the goal of trying to maximize the time a user spends on the site.

This kind of weighting is powerful and has a variety of uses. If the goal of the company is to maximize profits, and the algorithm achieves this by maximizing the amount of time people spend on the site, which in turn maximizes the likelihood of them seeing ads.

Hopefully, you can see the positive feedback loop at work here.

The more posts you see that you like, the more you stay on the site interacting, the more those weights between connections get reinforced, and the more likely you are to see posts you are likely to interact with.

There are other types of graphs with tighter or looser constraints, like negative weights, or a maximum number of edges between nodes (grids), or multiple kinds of weights per edge, or allowing for multiple connections between the same nodes. I consider these to be a little too deep down the rabbit hole for the purposes of this series, but it’s worth knowing that they are there and they all have their own quirks and nuances.

But there is one more property of graphs that I want to touch on before moving on because it provides an important constraint and allows us to categorize graphs in important ways.

This has to do with if a graph contains a cycle or not.

An idea that is central to graphs is that you can “travel” from one node to another along any edges they are connected by. This is like being able to take a flight between two airports.

This travel has directionality, in the same way, that whenever you fly you have two airports, with one being the origin and the other being the destination.

Now usually when you are able to fly directly from one airport to another, you are able to take a flight back, but with graphs, this isn’t necessarily the case.

This makes a little more sense in the context of directed graphs than in undirected ones because all undirected graphs can be represented as directed graphs in a relatively simple way.

Whenever you want to make a directional connection between node A to node B, you just have to make it from node B to node A too.

And in fact, this is a common implementation for undirected graphs: just use a directed class, but modify it slightly so any time you make one connection, you also make the reciprocal one.

Screen Shot 2020-12-07 at 8.57.34 PM.png

However, this creates the problem that you are always creating cycles between nodes since you always have a connection back to where you came from. A simple way around this is just to say that cycles only count if they have more than two nodes in them.

But for our purposes, we care about whether we are looking at directed, acyclic graphs, usually abbreviated just as DAG.

So for example, a binary tree would be a special case of a DAG because there is no way to end back up where you started after traversing from one node to another.

So all binary trees, and all trees in general, are DAGs. But not necessarily all DAGs are trees.

One thing that special about all trees is that there is always a unique path to every node. There are never two ways to arrive at the same node.

This isn’t necessarily the case with all DAGs, and here’s an example:

Screen Shot 2020-12-07 at 9.03.27 PM.png
Screen Shot 2020-12-07 at 9.03.09 PM.png

Because of this lack of cycles, you can establish an ordering to these nodes that somewhat mimics the idea of a root node and leaf nodes in trees. There are certain nodes that are at the “top” and others that are at the “bottom.”

You can think about this as like an ordering algorithm for putting the nodes into a list that boils down to this one idea:

“A node can only go in the list when all nodes above it are in the list.”

So running through a quick example, try to come up with the ordering for this graph:

Screen Shot 2020-12-07 at 9.06.00 PM.png

Now depending on how your mind works, you might get one of several possible lists, all of which are valid. It all depends on where you chose to start and how you added your nodes to the list.

Screen Shot 2020-12-07 at 9.09.53 PM.png

Because that description of the algorithm doesn’t enforce a strong enough constraint to guarantee a particular ordering.

But it turns out this ordering algorithm is going to be key for solving the problem of the alien dictionary. Hopefully labeling the nodes with letters didn’t make it too obvious.

But before we can need to figure out two things first:

  1. How to model the problem as a graph problem.

  2. How to traverse that graph so we get the ordering we want.

And for that, we’ll need to talk a little bit about how to actually implement different kinds of graphs and discuss some of the benefits and tradeoffs of each implementation.

Conclusion

The key takeaway I want you to have from all the is that solving problems really comes down to finding the right tool for the job and being able to think flexibly in terms of those tools. I’m personally a very visual learner, but find the right framework that meshes with your way of thinking.

There’s a difference between solving the problem at a conceptual level, and actually implementing a solution in code. I think that’s one of the biggest paradigm shifts that happen to coders as they start getting better at algorithm problems. You need to be able to solve them in your head first using the correct mental model. Then you have to be able to make the right conceptual connections to actually implement that solution in code.

Because there always have been and always will be layers of abstraction between our human way of thinking and how computers execute instructions to solve problems that we care about. It’s just part of the game of being a software engineer. 

And graphs are some of the most powerful abstractions you can master.

Comment

Neuro-Logical Levels of Change: How to Create Change in Your Life

Comment

Neuro-Logical Levels of Change: How to Create Change in Your Life

Screen Shot 2020-12-07 at 8.32.20 PM.png

The last mental model I wanted to share to improve your learning rate has to do with how a person’s life setup influences who they are, and vice versa. 

To quickly summarize what this model is, is a hierarchy of “contexts” in which we operate. These being your:

  • Environment: your physical surroundings and who you interact with.

  • Behaviors: what you do with said people and the environment.

  • Capabilities: what you could do in that context, but don’t necessarily do.

  • Beliefs: the things you hold to be true, and assumptions you make.

  • Identity: who you believe you are, and what you stand for.

  • Mission: what you were created to do or give.

These contexts live on a spectrum from more concrete to more abstract, and they all influence one another in both directions. 

For instance, what kind of food you have in your kitchen (your environment), will determine what you end up eating (your behavior), which affects what kind of shape you are in and what activities you can perform (your capabilities).

Conversely, if you set out to fix the problem of homelessness (your mission), that may make you think of yourself as a more compassionate, helpful person (your identity), and change how you think about people who have lost their homes (your beliefs).

This model is important because it provides a framework for defining and organizing life. And it’s useful because it can help you identify what areas are working in your favor, and which ones are holding you back. Once you identify those areas, it becomes easier to target the aspects of them that need to change to get the result you want.

I also want to highlight some of the ways that Outco played a role in helping me in the different contexts so that if you’re thinking about joining the program you can get the most out of the experience too. 

So with all that said, let’s jump in.

Environment

You are what you eat.

This is the most concrete, and physical context in which we operate, and to me, the easiest one to understand. 

It’s everything from where you live, to what your commute looks like, to what food is in your fridge, to what apps are on your phone, to what kind of computer you do your work on. 

Not only that, but it’s also the people in your life. Your friends, family, coworkers, acquaintances, significant others, etc.

We’re physical beings that live in a physical world, and therefore have to abide by the constraints of that world. This goes without saying, but it’s important to remember, especially now with everything going on with the Covid19 lockdowns. 

A stressful commute or unhealthy breakfast can impact your productivity throughout the day. Taking up a regular workout routine, or meditation practice will likely have a positive impact on your overall mood and outlook. 

Now that a lot of us are working from home, it’s important to make adjustments to our setups, like getting a comfortable chair, an ergonomic keyboard/mouse, or a monitor for extra screen real estate. 

That’s one of the biggest value adds that intensive learning environments like Outco provide. Being in that space, whether it be physically or virtually, immediately helps because you’re surrounded by other people that have similar goals and skills as yours. 

You end up learning stuff without even trying just by being exposed to a new problem, or by watching someone solve a problem you know in a different way, or overhearing a conversation about something that piques your interest.

You are what you eat, both literally and metaphorically. You constantly draw energy and get important feedback from your environment. How you grow depends largely on what kind of soil you are planted in. 

Behaviors

80% of life is just showing up. The other 20% is performing.

Your environment is only part of the equation. What you actually do in that environment also matters tremendously. 

As an example, about 63% of gym memberships go unused. Just because people actually sign up to get in shape, and have access to those facilities, they still have to go there and put in the work. 

Who you surround yourself with can make a big difference on what kinds of behaviors you engage in.

For instance, if you have roommates that stay up late and like to go out drinking, you’ll likely end up doing the same more often than not. However, if you are living with other programmers, you’ll end up talking about programming concepts and you’ll likely end up absorbing new ideas just through osmosis.

At a certain point too, there are diminishing returns to having nicer things. Having the latest and greatest laptop with all the newest specs won’t actually make you a better coder by itself. That all lies in how you actually use the machine. Are you procrastinating on social media all day? Or are you using your time effectively by doing practice problems and applying to companies?

So what kinds of behaviors are worth engaging in if you want to see a significant change? One big distinction that is worth making here is the difference between action and motion

Actions are behaviors that actually move you closer to your goals. They are the things that have the biggest impact on what you are trying to accomplish, and it’s important to always be clear on what those are. These would be things like doing practice problems, ore sending out resumes. 

Motions are things that are really just busywork. They don’t get you any closer to your goals, but the insidious thing about them is that they feel like they are. These can be tricky to identify but are often things that hold some value, but are ultimately lower priority than your core work. So for instance, learning a new framework, or language, or redoing the CSS on your personal site.

Screen Shot 2020-12-07 at 8.33.32 PM.png

A good analogy I’ve heard for this is trying to fill a jar with golfballs, sand, salt, and beer. You want to focus on the biggest things first, and then work your way down if you have time.

Again, this is where having a program like Outco’s helps by providing structure and guidance on the most important aspects of the job search to focus on.

Capabilities

When you’re a hammer, every problem looks like a nail.

Your capabilities are not necessarily what you do on a daily basis, but what you could theoretically do if necessary. 

I don’t ride a bike every day. Nor do I surf or play the piano. This is partially because I don’t have them in my environment, or if I do, I have no need to do them every day. However, I know how to do all those things.

Learning new skills is a big part of growth, both personally and in your career. New frameworks are constantly coming in and out of fashion. Different jobs will use different internal toolsets that may be familiar or completely novel. And new people you meet will have different communication styles and individual quirks that you’ll have to adapt to. 

There are certain skills associated with job search which you may not possess, and it’s important to identify what those are so you can learn them. This is more meta-skill: the ability to learn how to learn, which can also be developed. 

That way, you’ll be able to identify what kinds of practice problems you need to focus on. What kinds of companies you will be the strongest candidate to apply for will depend on the skills you have developed and can demonstrate. And understanding how to communicate with recruiters, interviewers, and hiring managers will be crucial to your success. 

Once again, you may not need to use all these skills. 

But the bigger your toolbox, the greater the variety of problems you can solve.

Beliefs

Whether you think you can or you can’t, you’re right. 

What you believe to be true has a tremendous influence over your life. 

The assumptions we make about the world around us, shape what kinds of actions we take, and what we believe to be possible. They are the foundation upon which we build our model of the world. And like any foundation, it’s strength will determine how sturdy whatever structure grows out of it. 

This context is even more abstract than the last because beliefs can be hard to define. Often times we aren’t even aware of our beliefs and operate under them implicitly. Typically we don’t question our assumptions and simply take the conclusions we derive from them for granted.

But questioning assumptions is a good habit to get into, at least from time-to-time. A lot of conflict and disagreement between people stems from a mismatch in beliefs. This can either be because one side is willfully ignoring facts, but often it’s because they are simply unaware.

An important thing to remember is that we are all operating with incomplete information when we make decisions, and being able to identify where our assumptions are shakiest so we can address them and look for new evidence to support or replace them 

I’ve seen a lot of folks struggle with negative beliefs about their ability to get a job in the tech industry or doubt their ability to solve certain problems or pass technical interviews. 

But again, this is where that interplay between layers comes in. As you start to see your skills and capabilities grow, you might start to believe that you’ll be able to pass the interview. As you start developing new habits and behaviors, things will get easier, and you’ll begin to optimize how you do things. You’ll begin to believe things that used to be hard, are now easy, and that in itself will remove some of the anxiety, stress, and fear from the process. 

Developing a strong belief system is an important part of life, and plays a big role in being successful in your career. 

Identity

Be yourself, everyone else is already taken. 

Identity is an even trickier thing to pin down and define than individual beliefs, but most people would agree that it is a real, and important thing.

We’re all shaped by our past experiences and background. We have individual identities, but we also have cultural identities, both of which influence one another. 

Because identity is such a hard concept to define, we tend to describe ourselves then in terms of our roles and relationships relative to others. We are parents, siblings, children. We are also defined by our heritage, professions, hobbies, or activities. 

She is a soccer player. He is a singer. They are American. I am an Outcoder. 

We use phrases like those to show where we are in different hierarchies and webs of relationships. They have practical utility because they help others quickly gain meaningful information about us.

But the flip side of that is when we overgeneralize and make too many assumptions about identity. This is where negative stereotypes and biases creep in. It’s something that is always worth being careful about and to keep in the back of one’s mind. 

Because identity isn’t just something we showcase externally. It’s also deeply personal and changes over time. It took me a long time to actually see myself as a software engineer but Outco helped me do it. And once that became part of my identity, it shifted my beliefs on what I thought I could do and build. 

Everyone is on a voyage of self-discovery, and as we find out more things about ourselves, such as our likes/dislikes, interests, passions, aversions, curiosities… we can make better decisions. It allows us to focus our efforts, build the appropriate skills, and place ourselves in the correct environments. 

Mission

Those who say it can’t be done should not interrupt the ones doing it.

This last layer also has to do with what you find valuable, which to me is something that is incredibly personal and impossible to ever fully define. 

Value is something that is very much contextual and prone to change over time. 

What you value at 10 years old will likely not be the same as what you value at 20. Which will be different at 40, and then again at 80. 

It also depends on what situation we find ourselves in. If we’re hungry we value food. If we’re in danger we’ll value safety. If we’re lonely we’ll look for companionship. These shifts in values can be subtle and depend on what our needs are at that moment. 

But ultimately, it’s important to make the distinction between instrumental values, and final values. 

Instrumental values (or goals) can be thought of as stepping stones. They help us move towards some greater ends, and derive their value from how well they do their job of getting us closer to the thing we really want.

For instance, a car has instrumental value in that it can get us from point A to point B in a certain amount of time. How quickly it gets us there, how efficiently, or in what kind of luxury it does so increases its instrumental value. 

But the final value is ultimately getting us to our destination. The destination is the thing that we’ve ascribed inherent value to and decided that it’s worth pursuing. 

This is where it gets tricky. What we decide is a final goal, is somewhat arbitrary, but also very profound. It might be something as big and broad as seeing the value in preserving the environment, enjoying art for its own sake, or ending poverty across the world. But it could also be narrower, like valuing code cleanliness or enjoying helping other aspiring engineers climb their career ladder. 

The point is, that we all get to decide our value system which then informs our priorities. This is the deepest level because our mission transcends our individual identity and can live on through our legacy. 

It goes without saying that having a strong sense of purpose is extremely important when it comes to having a successful career. It helps keep you going in the face of adversity and you only need to look at the success stories of leaders and pioneers across any industry to see the power of having a strong mission and purpose. 

Conclusion

Hopefully, this was a useful model for thinking about life in terms of different layers. It’s best used as a tool for reflecting on what’s working in your life and what isn’t. It allows you to understand how the different pieces of your life fit together and feed off one another so that you can play around with them to find which configurations work best.

Outco does a great job at addressing all the different layers in different ways, through structured curriculum, practice problems, community, and coaching. We all have roadblocks, and having good mental models and support systems are the key to overcoming them. 

Comment

How To Solve Power Set Using Recursion

Comment

How To Solve Power Set Using Recursion

Screen Shot 2020-08-16 at 1.28.42 PM.png

Introduction

Finding the Power Set of a String can be tricky if you are unfamiliar with solving recursive problems.

However, this also makes it a good opportunity to learn about how to identify recursive problems in the wild, and how to break them down so that they are easier to solve.

A Primer in Combinatorics

This problem lends itself to being solved recursively because it’s related to a field of math called combinatorics. As the name implies, this is all about mixing and matching things. Usually, these are physical things, like colored balls, and it’s typically taught in relation to the field of statistics and probability, where it has the most practical implications.

So before we dive into the problem, it’s worth defining just what the Power Set is:

“It is the set of all subsets.”

Since we’re talking about strings, this means it’s the set of all substrings. But before going into more definitions, I think it’s useful to start with an example so you can get an intuitive understanding of what’s going on.

Let’s take the Power Set of the string “ABC.” The result we get is:

Screen Shot 2020-08-16 at 1.30.49 PM.png

There’s probably a few things you’ll notice right off the bat about the result, and just doing this and taking notes about what you see is a good idea.

You want to notice that output is a list of strings. You might notice that there are 8 strings in this list and that these strings are of various different lengths. And just in doing this, you’ll probably have some follow up questions about the problem.

To list a few:

  • Does the order of strings in the list matter?

  • Does the order of characters in each string matter?

  • What’s the relationship between the length of the input string, and the number of strings in the output?

To answer these questions we’ll need to know about what sets are and some of their properties.

As an aside, most languages have some kind of native Set data structure, that behaves in exactly this way. It’s similar to how a hash table works, and essentially only has keys without values.

For our purposes, a set is simply an unordered collection of items. This is a pretty vague definition, but the keywords are “unordered collection.”

Since the power set is itself a set, that means the order of its items does not matter. This means that the order of elements in the array we return does not matter.

Screen Shot 2020-08-16 at 1.32.12 PM.png

And since what we’re returning is a set of sets, it also means the order of the characters in the strings doesn’t matter, since we’re considering each string a set.

What this means is that we can return any permutation of a string that would appear in the final result and that all permutations are treated equally.

Screen Shot 2020-08-16 at 1.33.25 PM.png

But the word permutation is worth pinning down, because I’ve heard it used by engineers interchangeably with the word combination, and this can often be a source of confusion since technically they mean different things.

In the context of strings, when talking about permutations, we’re talking about any shuffling of the order of their characters. All permutations are of the same length, and they contain the same characters. Two permutations are only equivalent if they have the same characters in the same positions. The number of unique permutations you can create from a string of N unique characters is N factorial, which is probably one of the fastest-growing complexities you’ll have to deal with.

Now when we’re talking about combinations, we’re talking about unique subsets, where the order doesn’t matter. We always need to specify the size of the subsets we’re creating. But how you order the items in each of those sets isn’t important.

So a question you could ask in the context of combinations might be “how many unique sets of 2 items can you create from this set of 10 items?” Put another way, “from N items how many ways can you choosing K of them?”

Screen Shot 2020-08-16 at 1.34.44 PM.png

Calculating how many combinations you can make then depends on two factors: N, the total number of starting items, and K, the number of them that you are “choosing.” The formula isn’t quite as straightforward as the one for permutations, but it does involve factorials.

It’s called the Binomial Distribution Formula and it’s relevant in statistics and probability.

Screen Shot 2020-08-16 at 1.35.46 PM.png

Combinations can never have more items in them than the set they are drawing from. But you can have combinations with no elements in them. This is kind of a weird notion, but every set has exactly 1 combination with no elements in it. We call this the empty set.

A funny thing about combinations is that if you take all the combinations of all the different sizes, then you actually end up with the Power Set of that original set. Those two notions are equivalent.

Screen Shot 2020-08-16 at 1.36.44 PM.png

Seeing the Recursion

Screen Shot 2020-08-16 at 1.38.06 PM.png

At this point, you’re probably wondering where recursion fits into this whole picture. If you’re at all familiar with the pattern of recursive functions, you know that we need a base-case and one or more recursive cases. You might also be familiar with helper-method recursion and the pattern of storing state variables outside of the helper function and then modifying those throughout the recursion to be returned at the end.

However, even though the solution to this problem follows a fairly standard pattern, knowing how to fit those pieces fit together might not be apparent at first. So the best way to get started is just by trying a few examples and then look for patterns. 

Screen Shot 2020-08-16 at 1.39.04 PM.png

Here is a list of some easy, intuitive ones to start with. A key thing to notice here is that there are a few ways to organize the outputs. I’ve chosen one in particular to highlight the pattern we’re going to leverage during the recursion. Can you see it?

Screen Shot 2020-08-16 at 1.40.05 PM.png

Let’s try one more example, by adding another letter to the end. Trying to find patterns by incrementally changing the input is a good strategy for discovering the relationships between larger and smaller inputs, and how to go from one to another.

 I’ve color-coded the new letter and arranged the output in a particular way to highlight the pattern.

Screen Shot 2020-08-16 at 1.41.10 PM.png

Notice what’s happening. This is the pivotal point in the problem where we establish the key insights. Ideally, we can summarize our solution in a sentence or two of high-level pseudocode. 

So if you had to describe this solution to your interviewer you might say something like:

Take the power set of the string up to the next character, make a copy of that result with that new character at the end of each string, and then merge those two sets.

If you were to express this a little more abstractly as a formula for this example, that might look like this:

Screen Shot 2020-08-16 at 1.42.02 PM.png

And more generally:

Screen Shot 2020-08-16 at 1.42.58 PM.png

So let’s try to analyze the complexity of this solution. In some cases, the interviewer will give you this as a constraint at the beginning, but in many cases, they’ll just leave it open and tell you to make it as efficient as possible. 

Luckily, the power set, by definition, has an easy mathematical way of figuring out the number of elements in the output from an input of a given size. But we can derive that formula just by looking at the above formulas.

For every additional letter we add to our starting set, we need to make a copy of the power set up to that point, and then merge the two sets. 

Another way of putting this is that when we increment the input size by one we automatically double the size of the output. We multiply by two. 

Which means the power set of n elements will always have 2 to the power of n elements:

Screen Shot 2020-08-16 at 1.45.42 PM.png

Implementing a Solution

The next question we need to answer is how to actually implement a program that solves this problem in code. I’ve mentioned in previous posts that we want to find something called a “unit of recursion.” Usually, if we’re returning something like an array, this corresponds to each element in the array. 

Knowing the unit of recursion is useful because it helps us know what we will actually “return” or “append” at the end of our calculation. In this case, it’s each string in the result array. We just need to figure out how we’re actually building each one up.

Going back to our formula, we want a way of building on the solutions to power sets with fewer characters. Another way of thinking of this is that if we stopped our recursion early, our solution would still return a valid power set. 

As such, whatever string we’re building up currently, needs to be copied, and then the character we want to add, needs to be added to one of those copies. Therefore we need two recursive calls, which corresponds to our intuition that this solution doubles in size for every additional character we add to our input:

Screen Shot 2020-08-16 at 1.46.54 PM.png

As for our base case, we want to perform this task on all our characters before adding a string to our result array. Therefore:

Screen Shot 2020-08-16 at 1.47.50 PM.png

We’ll be using helper-method recursion since this will allow us to keep track of more variables in our recursive calls and allows us to keep track of the array outside of our recursive function’s scope. 

Since we’re building up strings, we’ll want to track the string we’ve built up so far as one of our parameters to the recursive function. And we’ll also want to keep track of what the next character we want to add from the set is. A good way to do this is just by keeping track of the index of that character.

Screen Shot 2020-08-16 at 1.48.42 PM.png

So, if we were to diagram the recursive tree for this problem we would first start with an empty string as the root node. This makes sense because the power set of the empty set is just the empty set itself. We’ll also diagram the index of the next character to add as the “layer” of the tree we are currently on. 

Screen Shot 2020-08-16 at 1.54.25 PM.png

Since the letter a is at the 0 index, it’s the first one to be added. The way we diagram this is as two branches. On one branch, we add the “a” and on the other, we skip over it. 

We now have layer 1, and additionally, this is the power set of just the letter “a.”

Screen Shot 2020-08-16 at 1.55.31 PM.png

We repeat this process for the next letter, “b”. Again, for each node in layer 1, we need to make a copy with the letter “b” and a copy without it. This will give us:

Screen Shot 2020-08-16 at 1.56.32 PM.png

Which, again, is the power set of the string “ab”.

Repeating this whole process one last time for the letter “c”, we finally get the power set of “abc”.

Screen Shot 2020-08-16 at 1.57.33 PM.png

Now that we’re at the end of the process, let’s discuss the base case. Layer 3, corresponds to the length of the input string. It also corresponds to an index that is outside of the bounds of the string, so we won’t be able to add any characters from it. This means our base case is when the character index we want to add from equals the length of the input string.

One important thing to remember here is that we want to add the string we’ve built up so far in the recursion, and then return out of it. If we don’t, the code will try to execute the recursive calls after the base case and end up breaking. 

As a final note, a couple of common small mistakes folks make are forgetting to actually invoke their helper method within their outer function. You actually have to kick-off the recursion at some point. You also have to return the array you’ve built up at the end since you won’t be returning anything directly from your helper method. 

And that’s the whole problem. I’ve linked to the code below in a gist. Hopefully what’s happening at each step will be fairly easy to follow.

https://gist.github.com/spiterman/059600437f6e0c6f559a212266bf3062

Conclusion

Recursive problems can be tricky, but they're all about finding the patterns between larger and smaller inputs. Like most problems, this problem can actually be solved in a number of ways, and if you’re up for a challenge, I’d suggest trying to solve it without using any kind of recursion whatsoever. 

And if you’re interested in Outco’s immersive accelerator program checkout outco.io. It’s a great way for engineers to speed up their job search and make it makes jumping through all the interview hoops less painful. 

If you want to connect with me on social media feel free on any of these links:

If you want to check out some other popular posts:

The Algorithm of an Algorithm

Working at Outco for the better part of a year now, I’ve noticed some patterns in how engineers learn the material and…medium.com

How to Merge K Sorted Arrays

With a Min-Heapmedium.com

How to Solve the House Robber Problem

Imagine you are a thief trying to steal as much gold from a neighborhood as possible.medium.com

Comment

Bloom’s Taxonomy: How To Gauge Your Learning Progress

Comment

Bloom’s Taxonomy: How To Gauge Your Learning Progress

Screen Shot 2020-08-07 at 2.13.55 PM.png

The second model is all about being able to gauge your own progress in learning a new subject. As I mentioned in the previous post, how confident you feel in a subject isn’t necessarily a reliable metric, for various reasons. We want to move away from assessing ourselves using only our gut feelings. And Bloom’s taxonomy provides a framework to do just that:

Bloom's taxonomy

Bloom's taxonomy is a set of three hierarchical models used to classify educational learning objectives into levels of…en.wikipedia.org

It’s a hierarchy that consists of different levels of mastery over a subject. To move up, or operate within a certain level, you need to be able to perform certain tasks or solve certain kinds of problems. As you move up to higher levels, those tasks become more complex, not just because they build on mastery over the previous levels, but because they involve “phase-shifts”.

These phase-shifts are the “aha!” moments we all experience when learning a new subject. Where stuff just clicks and all the pieces seem to come together. Where there’s a distinct “before” and “after.” A one-directional paradigm-shift, where you take a step back and can no longer see the world the same way. One nice thing about this process is that as you move up to higher vantage points, you’ll be able to reflect back and see the limitations of past perspectives. And if you can communicate how you navigated the climb up the Bloom’s pyramid, then you’ll be able to help others walk the path too. Which in turn, helps your own learning.

Recursion is a recurring theme that I write about (some pun intended). Being able to take a step back and analyze a previous state can be valuable, whether that’s while learning, or in a computer program. And at the risk of becoming a little too meta, I’ve decided that recursion would be a great example to use for this blog post to illustrate the different phases of the climb.

Remember

The first step in learning something new means being able to memorize, define, repeat, and recite. It’s how most of us learned our multiplication tables growing up, and why we used flashcards to study from multiple-choice tests. It’s basically just pattern-matching, and though it’s a shallow form of learning a subject, it’s still a necessary first step.

At this level, you’re learning basic terminology. So using our recursion example, this would be knowing that a recursive function is a function that invokes itself in its own body. It’s knowing that such a function is made up of a base and recursive cases. And it’s knowing that it’s often used in iterating through branched data structures, like trees and graphs.

Memorizing these kinds of succinct definitions can be useful in interviews in case the interviewer feels like throwing a few trivia questions your way. You want to be able to rattle off answers quickly and concisely to show your understanding. But just memorizing information isn’t enough to pass coding interviews, and that’s one of the things that make them so challenging. You have to actually know how different topics are connected to one another.

Understand

Knowing is not the same as understanding. This is more than just a semantic difference. For starters, you might look at this problem statement and know what every word means, but not understand what the problem is asking:

Program for Fibonacci numbers - GeeksforGeeks

The Fibonacci numbers are the numbers in the following integer sequence. 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144…www.geeksforgeeks.org

And if you don’t understand what the interviewer is asking you, there’s almost no chance of you accidentally stumbling across the solution. It’s one of the first things I stressed to engineers while I was an instructor at Outco. And it’s not always a trivial matter to figure out. Sure, the first step is understanding inputs and outputs. But then you have to understand the roadmap of how to get where you want to go. You have to understand why it might be a challenging problem, or what inputs might break your assumptions, or why the interviewer wanted to ask it. There’s always more to unpack about problems when trying to understand them than what’s given in the problem statement.

If you want to go a little deeper down the rabbit hole, Vsauce has a good video where he breaks down the meaning of the word “understand”: He relates understanding to being inside of and surrounded by something. That something could be a set of topics, ideas, or concepts. Defining understanding this way helps explain why we use the words “immersive” to describe Outco’s interview prep program or we say we’re “diving into” a topic like recursion or dynamic programming.

So if I gave you some code to solve a recursive problem like the Nth Fibonacci Number, mastery over this level means you’d be able to identify which part of it is the base case, and which part is the recursive case. You understand why the base case goes first, and why you don’t need an else clause to your if statement. And most crucially, you understand why you might want to set this problem up as recursive function: it comes down to solving smaller versions of the same problem and combining those solutions.

To me, understanding is all about drawing connections between facts. It’s “connecting the dots.” It’s seeing how all the different pieces of the puzzle fit together. And it’s using different lenses to see the world. But understanding how the pieces fit together isn’t enough. You have to actually solve the puzzle. 

Apply

In coding interviews, this is probably the most crucial step that you are being tested for. Being able to apply what you know is pretty self-explanatory. But, how can you tell if you’re actually ready to apply your knowledge and understanding? What is a clear test you can give yourself? Being able to look at the solution to a problem and identify what each part of the code does and how it works is a good indicator of being at the previous level of understanding. Being able to look at a new problem statement in a given domain and getting to a solution that can pass a set of predefined test cases is a good indicator of being at the level of applying.

It’s a tricky thing because understanding the code someone else wrote can give a false sense of mastery. It can give you the false belief that you’d be able to come up with that same solution on your own after reviewing the answer once. While it’s good to review other people’s code and to try to understand it deeply, the only way to really know if you’ve mastered a subject is to try applying it to new problems. You don’t want to just know how to solve the Nth Fibonacci number, you want to be able to solve any recursion problem that you encounter in the wild.

This creates the challenge of needing to then find new problems, that have been pre-sorted into a particular category you’re interested in. Just understanding that there even are different categories of problems presupposes a certain level of mastery. This is where the structure of a curriculum comes in handy. A good one organizes the set of all available problems into a progression of topics that build on and reinforce one another. It’s something I spent a lot of time working and iterating on while at Outco.

To some extent, mastering this level just requires doing and seeing a lot of different problems, and in different contexts: whiteboarding, timed challenges, longer-form homework problems, etc. But I think it’s valuable to note that what’s actually happening when you learn how to apply a concept like recursion, is that you’re simplifying down the essential components of that problem. You’re trying to turn it into a game of plug and play, where you have some blueprint of how to solve the problem readily available in your mind, and now it’s just a matter of filling in the blanks and accounting for the quirks of that particular problem.

All recursion problems have a base case and recursive cases. What are the conditions for each? And are we aggregating some return values at the end of the recursion or are we picking some optimal choice of return value? Does this follow a pure recursion pattern, or a helper method recursion pattern? When you’re able to apply what you know, new problems start to become instances of a single pattern with small variations. And the chaos of the world gets reduced down to a set of blueprints.

However, just because you can arrive at a solution, doesn’t mean you can’t arrive at a better solution.

Analyze

What makes one approach better than another? What are the factors that we need to consider to make that determination? Is it the number of lines of code we used? Is it the number of external libraries we reference? How do we take into account code reusability and readability? How important are things like variable names or code cleanliness and indentation? There are definite tradeoffs between cleverness and clarity:

Clear is better than clever | Hacker News

The hard parts of real-world software development are generally in the "wicked" bucket. Schoolwork and puzzle questions…news.ycombinator.com

Sometimes a solution to a problem can be written in one line of code. That code will work, but is that good code? A lot of that analysis depends on the context in which that code is used. The runtime of this is the same as the first solution above, but it’s definitely not as easy to read. Someone who isn’t familiar with ternary operators or javascript arrow functions might have a hard time parsing what the hell is going on. So if I were to use this as the first solution to teach a topic like recursion, there’s a better chance of more people remaining confused and not learning the topic.

To me, analysis is all about being able to translate one way of looking at information into another useful way of looking at it. For recursive problems, it’s knowing how to diagram and extract useful meaning out of the diagram.

Screen Shot 2020-08-07 at 2.14.17 PM.png

It’s knowing what each of the branches in the diagram represents: a function call. It’s knowing how to interpret the diagram and understanding how the call stack behaves in that context. In this case, one source of confusion people often have is that these operations are all being run in parallel, when in fact there is a sequence to them, that follows a pre-order depth-first traversal of that tree.

You’ll be expected to do some level of analysis in most of your interviews. Usually, this takes the form of analyzing the time and space complexity of your solution, or the different parts of your solution. For system design questions, it might take the shape of analyzing performance, or scalability, like how many requests per second can be handled, or what the maximum load a system will be able to take.

On the job, you’ll be expected to analyze the impact a change has on a product, through additional clickthrough rate, or revenue, or users or any other meaningful metric. But once you know how to analyze and break things down into their fundamental components, how do you use those pieces to make decisions?

Evaluate

This step is all about being able to compare different possibilities and then deciding on the best path forward. It’s all about being able to make judgments based on constraints with the goal of achieving a particular outcome.

In the context of an interview, this level of mastery helps inform your decision on which approach to take when solving a problem. Often you have multiple potential avenues to a solution, and you need to pick the best one. Not only that, but you also have to describe tradeoffs, analyze differences, weigh the impact of potential drawbacks or edge cases, and assess how all of that feeds into your decision-making. You may only have to comment on your approach briefly at the beginning and/or the end, but your response can tell the interviewer a lot.

Which is why it’s difficult to bullshit this level of mastery. Being able to evaluate requires a very deep level of awareness of the particular domain. You have to see how all the dots are connected, and navigate that web of information, to extract the usefulness out of it. Value literally comes out of the evaluation.

Which language, or framework, or backend, or database should we use? What the best architecture, or pod structure, or meeting schedule? How should we prioritize which features to build, which we support and which we decide to deprecate? And how do we justify those decisions? What are the important factors?

Do we factor in what technologies the team is already aware of? Do we spend time upfront to invest in hiring and training, or do we just make a push with the resources we have? Do we grow the team, or outsource part of this work? How much time will we save by automating feature X, vs feature Y? How much room for error or system failure do we need to tolerate? What languages should we support? What other companies should we partner with?

All of these are valuable questions, that don’t necessarily have clear answers because of our lack of omniscience. We might not accurately measure the probability of an unlikely event happening. For instance, the 2008 housing bubble or the 2001 dotcom bubble. We also might not ascribe the correct value to said event or action. For example, Kodak underestimated the value of Instagram, and Newscorp overestimated the value of MySpace. There’s a cognitive bias that explains why this happens, known as the Planning Fallacy, but it can be boiled down to this simple statement:

We tend to overestimate the benefits and underestimate the costs.

Planning fallacy

The planning fallacy is a phenomenon in which predictions about how much time will be needed to complete a future task…en.wikipedia.org

And to make matters worse, factors we didn’t account for can come out of nowhere and make an evaluation completely irrelevant. Again, we have a bias towards underestimating the chances of such events occurring and the impact they will have on us. See the Black Swan Theory:

Black swan theory

The black swan theory or theory of black swan events is a metaphor that describes an event that comes as a surprise…en.wikipedia.org

Going back to our original example of trying to solve the Nth Fibonacci Number, we should be able to rule out the brute force recursive approach because of its exponential runtime from our previous analysis. If we understand how to implement a dynamic programming solution like memoization, we should be able to improve our solution to run in linear time. Here’s a blog post that goes into some more detail about that solution:

How to implement Memoization in 3 Simple Steps

Memoization is one of those things that often throws engineers for a loop (some pun intended), especially when they are…medium.com

However, there is another approach that completely does away with the recursive solution and uses tabulation to achieve the same linear runtime. Here’s what the code for that looks like:

https://gist.github.com/spiterman/33033a45e5bdfb758cd909a28d3c4431

So which one should we choose? On the surface, they seem like they would be equivalent since they have the same time and space complexity. But we have to consider some additional overhead that comes with recursive solutions, namely the call stack.

The table in the tabulation approach takes the place of the call stack, and this makes a big difference for the maximum input size your function can handle. How many function calls your machine can keep track of is something you don’t necessarily have control over and is typically capped at something less than the maximum array size you can store in memory.

Generally, if there is an iterative approach you can use over a recursive approach, you should use it. And during times you have to use recursion, you should try to optimize it with tail recursion wherever possible. Below are some resources on the subject:

Recursion (computer science)

In computer science, recursion is a method of solving a problem where the solution depends on solutions to smaller…en.wikipedia.org

The key takeaway is this: to be able to evaluate between different competing options or solutions requires a very deep mastery over the subject. It may take time to develop this mastery, but at least some level of it is required during the interview and it is essential for progressing further in your career.

Create

And at last, we‘ve reached the top of the pyramid, which Bloom considered to be the apex of mastery: creating new works. As engineers, we build things. Tools, platforms, systems, programs, frontends, backends. They all need architects, designers, and visionaries to implement. It’s hard to say where creativity comes from exactly, but it requires imagination. Specifically, the ability to imagine a world meaningfully different from the one we live in: A world with the thing you created in it.

It also requires will power to carry out the necessary steps to bring that thing into the world. Good ideas don’t just manifest themselves, they require execution. This is the importance of a portfolio during the job interview process. It’s the answer to the question, “what have you created?” They want to see, what are you capable of imagining and then willing into existence?

I’ve found that when developing creativity, it’s good to start small and simple. Because eventually creativity snowballs. Your first work most likely won’t be your best work, but most people give up too early in the process to see what their best could be. I think the biggest determining factor in whether someone will stick with something long enough to master it is whether that person finds meaning in what they are doing. It’s a much stronger motivation than material incentives:

Instrumental and intrinsic value

In moral philosophy, instrumental and intrinsic value are the distinction between what is a means to an end and what is…en.wikipedia.org

And to me, meaningful work is something that creates “value.” Which is a tricky concept to pin down because it extends beyond just the dollar amount someone is willing to pay for something. It can be entertainment value, or educational value or personal value, or even spiritual value. It could be writing a blog post about learning and recursion to help others understand both topics better. I think of value like energy. It can take many different shapes, but in the end, it’s all basically the same thing.

I have another post about how creativity can be further categorized based on its impact, but essentially it boils down to three levels:

  1. Creating Something at All

  2. Creating Something People Value

  3. Creating Something People Use to Create Things of Value

Why Creating Things is Hard

The Creation Hierarchymedium.com

Which brings us to the end of the post, because now we’ve gotten to the point of peak meta-recursiveness, where we’re talking about creativity creating more creativity. But that’s the progression Bloom saw, and hopefully, this hierarchy can help you achieve a better awareness of your skills and your blind spots. 

Hopefully, you enjoyed this post, be sure to check out the Outco program at outco.io if you’re interested in accelerating your career in software engineering, and stay tuned for the next post!

And FYI, here’s a hacky constant time workaround for finding the nth Fibonacci number:

Fibonacci Number Formula

The Fibonacci numbers are generated by setting F 0 = 0, F 1 = 1, and then using the recursive formulaF n = F n-1 + F…math.hmc.edu

Because sometimes the most creative thing you can do is free up time to create something else 😜.

Comment

Recap: 3 Pieces of Advice to Become a Successful Software Engineer

Comment

Recap: 3 Pieces of Advice to Become a Successful Software Engineer

First of all, I wanted to thank everyone who attended today’s session. I know there’s a lot going on in the world right now, but it was good to see so many people still engaged in learning and moving forward in their careers. 

Hopefully, we were able to share some valuable tips and insights from our experiences and if you’re still interested in learning more about the program feel free to hop in on a free info session:

Sign up for our next Online Info Session - Outco Interview Prep | Career Accelerator for Software…

All classes M-Th Computer Science Fundamentals Pacific Timezone 6-9 pm PST Jul 13, Online Only* App Deadline: Jul 6…www.outco.io

We covered a lot of questions today but I thought I’d just recap some of the main points I mentioned for anyone looking to review them.

Enjoy!

How Do I Get Better at Problem-Solving?

The generic answer to this question is to do as many practice problems as possible. Practice, practice, practice because practice makes perfect, after all. 

But to me, this always raised more questions than it answered. How do I practice? How often? What kinds of problems? How do I know when I’ve mastered a subject? How do I track my progress?

This advice then starts to get very personalized, based on what you know already, what kind of interviews you need to prep for, what your strengths and weaknesses are…

Now, if you’re looking for a guide on how to breakdown the approach solving algorithm problems specifically, I’d suggest taking a look at this comprehensive post we have on the subject:

The Algorithm of an Algorithm

Working at Outco for the better part of a year now, I’ve noticed some patterns in how engineers learn the material and…medium.com

But if you’re looking for a single, overarching principle, for how to approach improving your problem-solving skills, I’d say this:

Learn with the objective of teaching.

Teaching others is the best way I’ve found at mastering a subject. Working as an engineer and an instructor for Outco was the single, most critical reason why I got good at problem-solving.

There are a few reasons why, to me, this is the best method of learning:

First, to teach someone else how to solve a problem, you have to know how to solve it yourself. There’s no way to fake it. You can’t just look up the answer, or pass some unit tests, and trick yourself into thinking you understand the problem. Your only metric is whether or not someone else can solve the problem after you’ve taught them. 

Second, your understanding will be far more solid than if you just do a single pass at the problem. You’re forced to fill in the gaps, transcend roadblocks, handle edge cases. You’ll need to make sure you are able to answer your own questions about the problem and anticipate new questions that might arise. Teaching requires, time, effort, and preparation. The result is that you end up with a much more solid foundation.

Third, you get new insights into how others think. It acts as a mirror for you to reflect on some of your own dead-ends that you might have run into along the way. You also might get new perspectives on how to approach a problem. This might be a different way to diagram it, or a new example to test, or a way of looking at the problem you might not have thought of, and ultimately that will just be one more tool in your arsenal.

Fourth, you develop your communication skills. If you can teach a problem to someone else, you’ll be able to explain your solution to an interviewer. When I first started at Outco I thought I was a good teacher, but one year into the job I looked back and realized how far I had come and how much more I still needed to learn. You can always more succinct ways of explaining something.

And finally, it’s an awesome way to make new connections by helping others. Silicon Valley is small. You never know who you might cross paths with again in the industry. And you’ll always have co-workers, teammates, bosses or clients. I’ve run into former students everywhere from the subway, to the gym at Google, to other tech company’s cafeterias, to having them as interviewers. So it pays to build up some good karma.

How do I Create Systems to Support My Success?

The job search is a marathon, not a sprint. Individual interviews always have a non-negligible amount of luck associated with their outcome, regardless of how prepared you are. But that’s not where your focus should be. 

Focus on what you can control: how you prepare for interviews, how you network, how you do practice problems, how you handle rejections, and how you recharge. 

You can build systems to support your success in all those domains. I like to think about in terms of layers:

Your Environment

This layer is all about your immediate, physical surroundings. 

Do you have the right tools to help you study? Whiteboards, markers, laptops, monitors, comfortable desks and chairs, etc.

Are you surrounded by other people working towards the same goal as you? Do you have colleagues, mentors, and/or mentees?

Do you have nutritious and comfort foods/snacks to keep you energized? Do you have ways of staying hydrated and caffeinated?

Do you have a way of limiting distractions, and places to decompress?

Your Behaviors

This layer is all about what you actually do in that environment. 

Have you actually put in the hours? Coding, sending out applications, working on side projects, doing interviews, taking calls…

Are you eating right? 

Are you sleeping enough? 

Are you getting enough exercise?

Are you taking breaks, and doing activities you enjoy to take your mind off coding?

Your Capabilities

These are the actual new skills you are building.

Ask yourself, what are the new kinds of problems or topics you need to learn?

Can you solve recursion problems? What about graph and tree problems? How about dynamic programming? 

How quickly can you solve these problems? Can you do it on a laptop as well as you can on a whiteboard?

What languages or frameworks do you know? What kinds of projects or apps can you build with them? How well are those projects architected and how clean is your code? How many people can you work with?

Do you know how to craft a good reverse-recruiting message? Do you know how to do the right kind of background research on a position or person?

Do you know how to eat healthily and exercise properly? Do you know how to rest?

What’s the Right Mindset to Grow as an Engineer?

One of the most rewarding but also challenging aspects of coding is just how immersed you really have to be in what you’re doing to be able to do it. Truly making headway into any kind of meaningful problem, whether at work or in an interview requires intense focus, patience, creativity, and attention to detail. 

And no matter what, you can’t give up. You have to push through whatever obstacle or discomfort you might be faced with. To me, this can be taxing, so adopting the right mindset is crucial.

I always seem to do my best work when I’m in a mood to explore and be curious. It becomes about playing around with the problem and being immersed in solving the puzzle. It’s like detective work:

Screen Shot 2020-07-16 at 8.00.35 AM.png

Debugging is love, Debugging is life

I can’t be thinking about something else while I’m working through a tough problem. It requires my full attention.

But being present and curious isn’t something that can necessarily be turned on or off. Sometimes it takes time to get into the right rhythm and to get enough momentum going to be productive. 

But a big challenge I consistently face when trying to get into that rhythm is being scattered and feeling off-balance. 

I think this comes down to there being a lot of distractions in today’s world since I don’t remember this being an issue for me in the pre-social media days. 

It’s brain overload to the point where it all becomes useless noise. There’s too much context switching. Too many apps, messages, emails, texts, tweets, DMs, posts, pings, and popups. 

It’s information pollution. 

So what can we do about it?

Well, for me, I’ve picked up meditating and that seems to really help. I know that carries with it certain connotations because of how some people use the term, but I don’t mean anything crazy by it. 

It’s simply finding some quiet time, away from distractions, where you can just let your thoughts unfold. 

It’s nothing mystical, there’s not really a wrong way to do it, and you don’t necessarily need to think about anything specific while doing it. 

I usually just put on some light music, sit cross-legged, and set a timer. 

My friend even made a free app to help you track how frequently you’ve been doing it, and it lets you notify your friends when you finish a session:

‎Goenka Timer

‎Goenka Timer ========== A meditation timer designed for Old Students of S.N. Goenka (dhamma.org). Features --------- ·…apps.apple.com

And here’s the playlist I use when I need to get into the zone:

https://open.spotify.com/playlist/10F0A0lcAFMx470gwXbW3L?si=xOej0JdMQMeARp-ua_JUrA

My sessions typically range anywhere from 5 minutes to an hour. Usually, it’s at the end of the day when I have some time to unwind, but shorter sessions at the beginning typically help me get focused for the day so I don’t feel like I’m scrambling. 

One thing I find is that it can be tough to just do nothing. It can feel like I’m wasting my time and not being productive. 

But as the old Abraham Lincoln saying goes:

“Give me six hours to chop down a tree and I will spend the first four sharpening the axe”

The truth is that it always ends up being a productivity multiplier because it helps me address all the noise going on inside of my head. I just let them have their moment, and then I move on to more important thoughts.

Because making the most out of every day comes down to just being focused and able to perform at your best. If you can do that, I think you’ll have a very successful career as a software engineer. 

Thanks for reading, and hopefully I’ll see you in a future session!

Comment

These 3 points will help you get hired

Comment

These 3 points will help you get hired

Our CEO Joshua Encarnacion sat down with the CEO of Resource.io to discuss the current state of the job search for software developers, during shelter-in-place and social distancing because of COVID-19. There was a lot of great information shared by the two, and we encourage everyone to check out the episode when you have a chance.

Outco – These 3 points will help you get hired Header  – #1.png

We put together a list of the top 3 takeaways for best practices when applying and interviewing during this time! Check out the list below and let us know what you think.

Applying through a company's website should be your Plan Z.

  1. Build a target list of your favorite companies who are currently hiring and have a relevant open role 

  2. Cold email or InMail someone at the company, ask for 15 minutes of their time to learn about what it's like to work there. 

  3. If you like what you learn, ask "What's the best way for me to apply?" They will likely refer you to the company which will increase your odds. 

Spend 2x the time to prepare

  1. Test all your internet, audio and video equipment

  2. Do your research on the company's mission, value, and product

  3. Show up 5 minutes before the interview starts

Treat your interview as a conversation 

  1. Ask questions throughout the interview to make it a two-way conversation

  2. Prepare 1 lightweight 'opener' question to build rapport with the interviewer before your interview starts

  3. Prepare 1 lightweight 'closer' question to end the conversation on an inquisitive note.

Did we miss anything? Let us know: outreach@outco.io

Want to learn more about how we can help you with your career? Let’s talk.

 

Watch the full conversation here:

Comment

The Outco Program

Comment

The Outco Program

Landing a job as a software engineer in the Bay Area is a difficult and daunting process. Keeping up with relevant skills can be overwhelming, even when you’re a veteran…

Comment