Since graduating from UC San Diego with a Computer Science degree, I've become increasingly aware of the disparity between the programming I did in college, and what I do now in the real tech world. I'm not talking about the science of writing good programs; my education amply prepared me for every challenging problem I've encountered as a professional Software Engineer—from architecture to algorithm. I'm talking about the practical work of programming: the tools, conventions, and routine of writing quality code as part of a team, and deploying it onto commodity hardware for real users.
In many ways it's completely expected that an undergrad CS degree won't prepare you for the bread and butter of industry—after all, Computer Science isn't trade school, it's science! So in this post I'll cover 10 industry-grade practices that I wish I'd used as an undergrad.
Above, UCSD's Geisel Library
1. Version Control Everything
This one is fundamental to almost everything that follows. You're probably taught about version control from day 1. But let's be honest; when it comes down to it, what matters in school is your program's output, whether your lines are < 80 characters, and possibly how many comments you've written.
But in real life, code doesn't exist unless it's version controlled. The benefits are innumerable, from synchronizing changes in a large team, to the ability to roll back, to simply having a precise record of what happened to the code. Version control everything. Additionally, I strongly recommend using Git. Not only is this the VCS of the web and open source, but the decentralized model allows for greater flexibility and experimentation. I use Bitbucket, which offers unlimited private git repositories and a GitHub-like pull request interface, among other features.
2. Try Another Language
Maybe you've already taken the obligatory programming languages course. Mine covered Python, OCAML, and PROLOG. But outside of this the bulk of classes will likely stay within the comfort zones of Java or C++. Why not try a new language for the odd assignment? While experientially it's true that real-world software companies will converge around a few languages and tech stacks, the best companies will always use the right tools for the job. Lately I've been playing around with TypeScript and the Go Programming Language at work.
3. Study Other Peoples' Code
Reading, understanding, and improving code you didn't write is in my experience, a rare activity when coding for school assignments. On the other hand, it's something that career programmers have to get used to. In academia, code tends to get written, tinkered with until it works, and finally submitted for evaluation, after which it never sees the light of day. But in a company with good software engineering practices, code is designed to outlive the tenure of any given programmer. Developers come and go, and software changes teams and evolves through multiple major versions. Programmers in these settings must not only become practiced at reading foreign code, but learn to enjoy the activity as essential for creating scalable and resilient software. Furthermore, reading what others have written can inform and improve your own practices. The best coding mentors I've had are the ones who can quickly understand what I'm trying to accomplish, and bring good practices to bear on my code, all while letting my personal style breathe.
But I don't have time to read my peers' code! One practice that can help you realize the benefits of working through strange code is to institute code reviews for team projects. At the beginning of a project, take the time to set up repositories such that you can accept pull requests from contributors. Tools like GitHub and BitBucket have a nice interface that allows you to inspect and comment on incoming contributions. Another idea is to get involved in open source software. The entire premise of open source is that opening up a codebase to the world strengthens it. Have you used a framework like AngularJS or Django? Go check out the code for these projects on GitHub!
4. Write READMEs
No README notice from BitBucket
If you have any experience with open source software on Github, you've read a
README.md file. A README documents a codebase, and is conventionally placed in the repository's root directory. It's used for things like (1) explaining how to install and run the codebase, (2) documenting usage, e.g. command line interface or API routes, and (3) instructions on how to contribute. Ghost—the software this blog is based on—has a nice README file. I'm a proponent of keeping documentation as close to the code as possible—relevent instructions should change in lockstep with the code they refer to, under version control. A versioned README is as prudent a practice for school as it is for enterprise development. Ditch the emails and Google docs, and start writing READMEs… with Markdown.
.md extension mentioned above? That's Markdown, a simple markup language for plain text formatting. It's becoming ubiquitous accross code-related parts of the Internet, notably StackOverflow and GitHub. I'm even writing Markdown at this very moment in the Ghost blogging editor. Markdown is an excellent choice for coders who have to write prose with traditional WYSIWYG features like headings, bold, italic, ordered lists, formatted code, and quotes. It doesn't require a special editor (it's formatted at render-time), and uses only basic characters like
# to denote special meaning. This means it works well with normal text editors—many code editors even render Markdown for you—and can be easily versioned! GitHub and Bitbucket will automatically render *.md files in your repositories for instant, readable documentation.
5. Get Handy with a Command-line Text Editor
Basic Linux command-line proficiency and use of a text editor like vi are also typically taught early on in a CS undergrad curriculum. In my experience however, the academic need for these skills quickly faded in favor of IDEs like Eclipse or IntelliJ. Assignments could be run and tested from the safe haven of these do-it-all environments. But a few years of industry experience has taught me that these editors only cater well to a small class of languages, situations, and workflows.
Don't get me wrong; these editors are invaluable and have their place in the real programming world. However there's a large class of situations where a lightweight, command-line text editor is preferrable. You may have to develop code on a remote server, inspect or tweak a config file somewhere, or simply be stuck with an environment that has no graphical component. The bottom line is that as a Software Engineer, you'll (hopefully) be doing more than committing code to well-defined projects from a sterile environment. You'll be learning, deploying and experimenting with tools and languages in all manner of environments! So it helps to have proficiency at vim, nano, emacs, or something that will likely be installed wherever your terminal happens to take you.
6. Learn Shell Scripting
It's one thing to be able cd your way around a Unix environment, but another to write shell scripts that do your bidding. Just like a text-editor such as vim is ubiquitous and useful enough to be worth learning, shell scripts will be supported anywhere you're using a terminal, and can be used to quickly create just about anything you'd want to exist in a shell environment—from custom command line tools to web server monitors.
Bash is a Unix shell that ships with GNU and OSX, among other Linux distros. The language has familiar constructs like looping and functions, but it's true utility (over a scripting language like Perl or Python) is it's ability to speak anything you'd type into the command line manually. Output redirection, environment variables, globbing, and other familiar tricks will all be at your disposal—in addition to any programs like sed and awk that are command-line ready. I recommend checking out a bash scripting tutorial.
7. Write a Daemonized Program
A striking difference between the kinds of programs written in school vs. industry is that the former tend to be "single use" programs. Outside of a game design or web server class, most coding assignments are intended to produce acceptable output, and then terminate. In industry, these kinds of simple programs exist in the form of software libraries, but only serve the purposes of higher-level programs called services and applications. The main cosmetic difference between these low- and high-level programs is that the latter are often long-running; they don't terminate after doing their job, but remain available for arbitrary clients, like humans or other programs.
Software libraries are just biproducts of applications and services, essentially sets of functions that have been grouped together and extracted so as to be atomic and reusable. Most college programming assignments end up looking like libraries, but in my experience, industry work tends to focus on the frontiers of services and applications. To mitigate this academic bias, consider writing an assignment as a long-running program, deploying it as a web service, or tinkering with a home web server.
8. Use Continuous Deployment
In the real world, the latest version of an application isn’t emailed to the customer, and test suites aren't run manually as a “sanity check” prior to submission. Rather, software exists within a living a mesh of infrastructure that tests, stores, and deploys it. A big part of this infrastructure is continuous deployment, a process whereby a snapshot of a codebase is automatically tested, packaged, and delivered as a trusted executable into the hands of its users. In a world where code must constantly evolve to customer demands, CD can worry about repeatable tasks like running unit tests, tagging a version, and pushing code to server. The latest working version of your work will just be there, ready for action.
There’s no reason you can’t take advantage of continuous deployment in school. Examples of free continuous deployment setups include drone, GoCD, and CodeShip. Instead of scraping together an executable minutes before a deadline, take some time to set up your own CD server to use for all your assignments. When you or a teammate makes a commit, your program will be tested, built, and deployed automatically.
9. Package and Version Your Code
Whatever package format you prefer (I've been using a combination of npm, bower, and Docker these days) these artifacts represent a definite snapshot of your software, can be named with meaningful versions using a scheme like Semantic Versioning, and are easily incorporated into a continuous deployment process. You can store packages in a file server or public registry, and achieve history and flexibility for the runnable state of your code, in addition the human-readable state achieved with version control.
10. Create and Use Libraries
After several years as a professional software engineer, I've noticed a major pattern with how code evolves, if teams are diligent to refactor appropriately, of course. As applications (websites, mobile apps, and user interfaces) mature and grow in complexity, parts of them tend to coalesce and chunk off into services and libraries. Services are long-running programs that are accessed remotely, often involving disk-storage, or implemented as formal APIs. At an even lower level, libraries are locally accessed collections of specialized code. Some of these can be built into a language, like the C numerics library.
The point is that well-maintained software ends up codifying into smaller pieces that are reusable, composable and independently testable. A lot of programs get written over the course of a four year Computer Science degree. With a bit of extra effort and some of the tools mentioned above, you can begin producing your own set of reusable software libraries.
A mobile library at Bosque de Chapultepec in Mexico, D.F..
Hopefully these tips can help you escape the feeling that you're programming in a theoretical vacuum. While the act of coding is often solitary, real-world software engineering culture is actually quite social. Achieving great things with software will require you to open up your code to foreign eyes, leverage the tools and processes of the craft, incorporate services and libraries that others have written, and ultimately give back what you have created to the community. Thanks!