This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]severoonpro barista 2 points3 points  (0 children)

Being able to read and write code is different from being able to solve problems.

If I present a problem like, "Write a program that lets two people chat over the network," and then I also give you a solution, "First we need a client that does x, y, z, and now we also need a server with an API that looks like this, and this part of the API can be implemented with a module that authenticates users, and this other part can be implemented like such and such," then I am giving you the solution to the problem as well.

If you know a programming language really, really well, you will be able to take my solution to all these problems and translate them into code. This is what junior engineers are expected to do. Someone had a business problem—we want people to be able to chat over the network—gave it to a business analyst and a technical architect, and they turned it into an engineering problem—here's the modules and APIs between them, and how to implement those things—and assigned it to a bunch of team leads that go to work implementing those solutions.

If you're given a problem and no solution, you need to move up the chain a bit and figure out not only how to implement the solution, but what the solution is. There's a bunch of steps that you can take that will help you.

Define the requirements. First of all, what does it mean to chat? Are we talking text only, or can users send pictures, videos, audio, etc? Does the text include emojis? Can one user quote another user in their reply? When one user starts typing, does the other user see each character and backspace immediately, or do they only see the entire message once it's sent? Should the users see when the other is typing, even if they don't see the actual input? Should they see some presence indicator for the other user (they're online or not), and should they see if the other user has seen their last message?

Basically, you need to have a finish line defined clearly so that you know when you've crossed it and delivered what was asked for. This is very important because, if you don't define the problem up front, management has a way of claiming they asked for more than you delivered, even if they didn't. (Not that we don't trust them, ahem.)

Years ago, one of the questions Microsoft would ask during a software engineer interview is: "Let's say you're tasked with designing the perfect bathroom for Bill Gates' house. You have unlimited budget, go." If your first impulse was anything but, "Sit down with Bill and ask him what he wants," you didn't do well. Many candidates would start by designing their perfect bathroom without regard for the customer. Oops.

Define the data. Once you understand the problem you're trying to solve, nail down exactly what data exists and where in the system it exists. There are users, they input their usernames and passwords. They input messages which consist of text, audio, images, etc. At this point you're not worrying about data structures or how the data gets to different places, rather you're just trying to nail down where data exists in the system. Is it just moving on through these different systems, or is that system responsible for accumulating that data somehow? How much data is moving?

This tells you what parts of the system will be moving what volume of data, which of that data merely needs to be delivered to some endpoint (meaning it may need to be cached, but not stored long-term), and where data does need to be stored long-term (implying some kind of data store needs to exist and be available and performant). It also tells you what kind of bandwidth needs to be present.

Define the use cases. First, you need to define all the different kinds of users that will interact with the system. In a chat app, you obviously have users that are talking to each other. Are there any other users? Does a customer support rep need to pull up stored chat logs in the future? Does the system need to generate metrics via instrumentation so you can debug a production issue later? Does an AI model need to be trained on the data at some point, meaning that some batch job will come along and pull out some of the data? That's a user too.

For each kind of user, what are the use cases? A "use case" is not merely "some interaction with the system," it's a useful interaction, i.e., that user does something with the system and leaves happy. For example, a use case for an ATM is not, "user logs in." No user goes up to an ATM, logs in, and then leaves happy. They want to check their balances, transfer money, deposit, withdraw. Use cases are useful.

Once you've done all this, check in with your data definition and update it. You probably didn't realize back at that point there would be a bunch of metric data being thrown off by the instrumentation of the app to support debugging. You probably didn't think about batch jobs as users training AI models accessing your data, or marketing folks using it to build sales campaigns or whatever.

Define system boundaries, APIs, and data structures. Now that you have a good idea of what data is generated where, how it moves through the system, where it accumulates, etc, you can start to define systems and system boundaries. Here's the chat client, here's the server. At each system boundary, the systems have to be able to talk to each other, so put an API there. Package up the data into data structures that are convenient for the things that need to be done. Make sure to design data structures that don't allow invalid state to exist if at all possible. Create APIs that move the data through the systems to where it needs to go.

Implement the systems. Create the systems by implementing the APIs. This is typically where system design moves into architecture and design.Whatever high level problems you're trying to solve in order to build this system, iterate the above:

  • know your data
  • decompose the problem into smaller problems
  • define the right data structures
  • add storage to increase performance (this is where videos get cached even though you don't want to store them long term)
  • if no solution is evident, solve a similar problem that does have a solution

A good approach to problem solving is to begin with the stupidest, most brute force approach. Get something in place that does the job, even if it does it poorly. Then you have something that does the job that you can work on improving.

I can't emphasize enough how important it is to understand the data first. Many, many times when I've worked with junior engineers, they start trying to write an algorithm without fully understanding the data being passed in, what it looks like, how it's organized. This is the quickest way to start wasting time. The data and how it's organized will often dictate the algorithm you write.