A good friend of mine from college has started teaching himself to code. He’s hoping to find a job at a Bay Area startup, and asked for some help getting oriented. I started writing a response, and it got a little out of hand. Figure this might be of interest for somebody else on this path. :)
I want to give you a larger context around how this field works–there’s a ton of good documentation on accomplishing specifics, but it’s hard to know how it fits together, sometimes. Might be interesting for you to skim this before we meet tomorrow, so some of the concepts will be familiar.
There are two big spheres of “technical” activity, generally referred to as “development” and “operations”. Development is about writing and refining software, and operations is about publishing and running it. In general, I think development is a little more about fluid intelligence and language, and ops is more about having broad experience and integrating disparate pieces.
In a broader sense, you’ll also have product and design roles (and there’s a lot of variance in how people fulfill these roles). “Product” is about understanding your problem, meeting with people who need it solved, understanding the tools at your disposal, and figuring out the shape of the solution without knowing the details. “Design” is about expressing that solution to a human being. Everything from the core ideas (what are the concepts involved and what do we call them?) to the visual and temporal layout of those ideas on the screen or in the product, to (at the most concrete) the specific colors, alignments, fonts, sounds, and images used.
Imagine a car race through the desert. The product team plans the route, finds the drivers, and decides what type of car to build. Developers design the engine, balance the vehicle, optimize chemistry, figure out the dimensions, and build the frame. Designers shape the skin and geometry, decide on colors, and position the controls so the driver has everything at hand. Operations is the ground team, who watches performance telemetry, puts out fires, and replaces broken parts or swaps out the tires for better performance on new terrain.
Designers and product folks communicate a lot about how to solve the problem in a way that makes sense to users. Developers and designers work closely together to shape the overall vehicle–designers conform the design to the user, and developers conform the design to the computer. Developers give feedback to product people about what’s actually buildable, and the product team pushes developers to solve a real problem. Developers help operations understand how the car is put together internally–where the weak points are, what are the temperature limits, what kind of gas to use, how to swap out the intake manifold. Operations helps developers understand how the car is performing in the field. How did it crash, what parts need reinforcement, what’s the limiting factor in speed, the oil filter is clogged with shavings, etc.
Building web sites is a great way to explore all these roles. You’ll get to try a little bit of each, and get a feel for what really clicks with you.
The backend lives on a server. It’s often broken up into several components, each solving a specific problem. One part renders the frontend and serves it to users who make requests. One part stores information in a database. One part might do work appropriate to the task, like making phone calls, computing trajectories, talking to a third-party service, etc. These folks are often called “backend engineers”.
The environment is the stuff around the backend. It’s the physical computers, the operating system, storage services, the network, monitoring, emergency response, etc. A woman who maintains these services is usually called an “operations engineer”, “network administrator”, or “sysadmin” depending on specialty.
Sometimes these teams are very isolated, other times they work closely. Sometimes each person works narrowly in a single role, other times an individual will personally shepard a feature through all these roles. Depends on how the team is organized. Startups generally have smaller teams, more tight-knit groups, and more permeable roles.
Development is a lot like academia. Your job is to understand a problem, develop a way to talk about it, and write an argument. Just like leading a reader through a chain of reasoning, you’ll lead a computer through solving the problem. The difference is mostly in specificity: computer languages are simpler, are executed faster, and aren’t as forgiving of mistakes.
First I reason about a problem. I try to phrase it in a simple way to myself. Break it into subproblems which can be solved easily. Develop a notation to talk about it, draw diagrams, walk through simple cases step by step, and look up how other people solved it. Sometimes this takes seconds, other times days.
Then I write it in code. I break it up into functions, each of which expresses a simple, individual idea. I decide on common names for the things I’m trying to discuss, and use them consistently. Then I assemble the functions together into one that solves the problem. Each function or logical group has “comments”, which explain why the solution works this way and fills in contextual gaps for humans. Code always has two readers–the computer, and the person who comes in weeks or years later to change or improve it. Your job is to express the solution clearly and efficiently to both.
Third, I test the solution. I think of example cases–if I’m testing addition, I know that 1 + 1 is 2, and -3 + 5 is 2. Good software carries with it a test suite full of these demonstrations, which verify every piece of the program.
Finally, I refine. Maybe the program wasn’t formatted correctly, or I mis-spelled a word. Maybe there was a logical error. The compiler (thing that turns the language into a running program) and your tests work together to demonstrate that the solution is correct. Maybe it’s correct, but it’s too slow. I figure out where the problems are and redesign or optimize as necessary. This tends to be the hardest part.
Writing complex software is a process of continual change. You’ll go through many drafts of an essay, discovering new sources or reorganizing, reviewing by yourself or with peers. In development, we call a draft a “version”. Version control is the software that saves all our versions and connects them in a giant web. It allows us to understand the historical evolution of a document, and more importantly, to integrate changes with others.
When many people work on software, we try to break the program up into small parts with well-defined borders. Then each person can work on a separate part and not interfere with each other, so long as the borders don’t change. There are a lot of ways to organize code, but in general they all aim to compartmentalize complexity so you can understand and change small pieces individually.
Imagine writing a paper with a friend. You might each take section and write it individually, then combine them into a single document. Then you’ll read each other’s essay and expand on it, maybe changing the wording or reordering phrases. Every time you make a distinct change you might save a new version. When your friend and you compare notes that evening, you can consider each change in isolation, deciding whether it fits with your overall theme or not. Small changes are easier to combine together, and help you understand the history of the document. When you discover a critical paragraph went missing, you can search the history to find out where it disappeared and why.
If you want to go for a career in tech I’d focus on building the most universally applicable skills first. It requires a bit of abstract, up-front investment, but they’ll help you work faster in the long run and are skills you continually reinforce. Think of this part like an intro class in finding sources, structuring an essay, etc.
First: You’ll need an operating system. Honestly, most of the tools you’ll be using just aren’t designed for Windows. It’s possible to get along but it can be clunky. Linux is probably choice #1, and Mac OS a common second. Many windows-based devs I know run Ubuntu in a virtual machine.
Second: you need an editor, something that lets you write text. Some folks start with Textmate, Sublime Text, or Notepad++, but the best programmers I know use Emacs or (my preference) Vim. They’re both powerful, but will feel awkward while training muscle memory. You can always switch later, but folks tend to stick with their early choices. It’s like driving stick vs auto. Some languages like Objective C or Java need a lot of contextual information–like foreign language dictionaries, proofreaders, etc, to write well. If you work in one of those languages, you’ll probably adopt a specific kind of editor, called an IDE, designed to help you.
Third: version control. There are a lot of choices, but most people and projects I work with use Git and Github. You can pick up the basics in a half hour and it’ll make your life super easy as you start working on a project.
OK here’s where I bring in personal opinions. Everyone’s got em, ask a different person and you’ll get different answers, often strongly felt. You’ll start to develop these as you explore. Whatever you’re using right now is The Best Language.
There’s another class of frontend design, and that’s for phones and tablets. The two big players are IOS (e.g. the iphone and ipad), which uses a language called Objective-C, and Android, which uses a language called Java. They’re roughly equivalent in complexity and language power, like French and German. I’d say they’re both middling in expressiveness. They’re more… finicky than writing backend code. More special cases, a little harder to get started. That said, there’s nothing like the power of making a magic thing happen in the palm of your hand, and if abstract problems aren’t as interesting this can be a great niche.
On the backend, your choices are a lot wider. Lots of folks are using Ruby or Python. Like French and Spanish, they’re both common, closely related, and roughly equal in performance and power. Because they’re widely adopted you’ll find libraries (chunks of code you can put together to solve specific problems) for almost everything.
For performance, big shops like to use Java, and to a lesser extent, C or C++. Java is reasonably fast but quite large, as a language, and slow to improve. I find it… muddy to write in. It’s like not being able to use commas, and having to break every thought into a distinct simple sentence. C and its variants are extremely fast but can be more dangerous. I’d advise these as second languages.
I would avoid PHP and Perl. They’re OK languages but suffer from… agglomerated cruft, and there’s no particular strength to recommend them. PHP lacks design restraint and ended up a bit like English: nobody can agree on what words to use.
Lisp (remember the language you learned last time we talked?) and its variants are a bit like Latin. Very old–one of the first, actually. Radically simple. Incredibly expressive. Very few speakers, although that’s changing with Clojure. Almost every other language can be viewed as a subset of Lisp. It… changes you, the way you think, in fundamental ways. Makes you a better programmer in other languages.
When you start programming, your thoughts will be small and concrete, just like in any new language. As you grow, you’ll start to solve bigger problems, more abstract problems. Every language has a sort of.. abstraction ceiling, above which you can’t express ideas directly. For instance, English will let you define new names for objects you haven’t encountered before. German will let you generate compound verbs, but in practical terms English and German are roughly equivalent in descriptive power; they just approach the problem differently. Most computer languages are like that. Lisp… lets you invent new grammar on the fly.
That said, there aren’t many folks hiring in Clojure or other Lisps, though they are out there and the jobs are cool. I recommend playing with it, if you have the time.
Most modern languages are very similar. Ruby, Python, Perl, PHP, Java, and C are all Germanic, insofar as they share close conceptual ancestors. There are whole other families of languages out there which you should be aware of, analogous to Japanese or Arabic, though not many people are using them. In particular, Haskell and OCaml are strongly typed functional languages which look quite different from any other–and have a higher abstraction ceiling. Erlang is a functional distributed language where code can live across many computers at once. If you choose to pursue these sorts of languages it can be extremely rewarding (and make you an excellent programmer), but you may have to study for longer before finding a job.
You’ll start learning a language, and gain experience with the fundamental tools. Over time you’ll build a project that drives you to learn specific libraries for a task, like drawing pictures, storing data, or serving web pages. As you gain confidence you’ll start writing code that exemplifies your style and skill. All your projects are published on Github. Nobody notices.
When you feel ready, start putting out feelers. Your portfolio has a few small projects–maybe demos, maybe libraries–which show your ability to write clear, documented, testable, code. You start sending your resume around, and link to your github account. Folks read the code, and see potential.
You land a job at a small startup, and fumble your way through a million things nobody thought to tell you. You feel useless for a bit, but start to catch on. In a month (heck, maybe your first day) your first code hits production, and something you built is on the screen for ten thousand users. The problems at your job spur you to learn new libraries, algorithms, and languages. You write some code to help talk to a natural language parsing service, and your boss says sure, throw it up on github.
From there it sort of cascades. As your open-source profile grows in quality and reach, more people will start to take notice of your code. Maybe you get a promotion internally, or move to another company. You’ll have the latitude to branch out a fair bit at a startup, and learn from your peers.
Option A: Towards frontend development.
You and I write a tiny web site together, tomorrow. Something super basic, like a notepad. We can get you started with Ruby as a language, Sinatra for a server framework, and HTML+CSS to show the page. Should only take a hundred lines or so, and you’ll have a skeleton to start exploring on your own. You’ll get an overview of the “full stack” from frontend to backend, and version control. OTOH, you’ll be learning three distinct languages at once, which can get confusing. Testing frontends is extremely challenging, so we won’t discuss that aspect much. On the other hand, you can see the results in the browser, which can feel great.
Option B: Towards backend development.
We work through some Project Euler problems together. They’re bite-size math problems and each has a single answer, so there are clear goals and you get the satisfaction of solving each in turn. They start easy and get harder, and introduce you to powerful techniques along the way. We can use any language, but I’d recommend Clojure or Ruby. This path would introduce you to testing, algorithms, debugging… the process of problem solving in code. You only have to learn one language, which can give you a leg up on tackling A later. It’ll push you to deeply understand a given language and advanced techniques.
Option C: Build something you care about.
Take any problem you think is interesting. Make it personal. Doesn’t matter if anyone else cares, you just need something that’ll drive you to think about and solve it. Maybe you want to… translate Latin texts automatically, make a chat client, plot your weight, index papers, make a videogame… whatever. I’ll help you design a solution in any language.
And of course you can switch between these whenever you get bored. All of these paths will broaden over time and introduce you to the language and techniques you’ll need for a job.