As a software developer, I spend almost every week at Code for Boston. There are a large number of attendees consisting of optimistic boot camp graduates thirsty to get some experience coding on real open source projects. Having worked with over fifty boot camp graduates over the past year and a half and seeing their challenges, I have developed an understanding of the challenges boot camp graduates face as they transition to coding in the real world. While you can join me at Code for Boston to learn these things, I am going to share some of my wisdom below.
In order to effectively code in a team, you should have mastery of git and work with some kind of project management tool. For most of our open source projects, we use GitHub at MAPC and Code for Boston. We use GitHub Issues to manage our project tasks. GitHub Issues are close to the code base, open to the world, and can be easily referenced and closed from commits.
There are lots of philosophies around how to structure git commits. Writing good commits will come to you with practice and experience. As a boot camp graduate, you have likely not yet had to dig into someone else’s code base and pray that certain information about a commit was there so that you can figure out what is going on. It is important to write a great commit message. If you are intentional about writing that great commit message and keeping your bug fix or feature down to a few great commits, it will be easier for others to understand the purpose of your code. Often the question you need to know the answer to is: “is it safe to change this code and if so, how?” Commit messages are a big part of how you find the answer to that question. You can also get a sense of commit message quality by looking at a class with git blame.
Inevitably you will at some point in your life commit a secret to a public GitHub repository. Do yourself a favor and setup and practice using BFG Repo-Cleaner today. When you actually need it, it will feel like a scary emergency and you will feel better having practiced this skill.
Pull Requests and Code Review
An important part of building your coding skill is to receive constructive criticism of your current work and style. You will likely do this by submitting a bug fix or feature as a pull request to an existing project. To improve your skills it is also helpful to review other people’s code. This is a chance to think and be intentional about what makes good code. While some new coders get anxious about making comments, the best thing to do is to treat code review as a discussion and not expect every thought of yours to be blindly implemented by the pull request author. Thoughtbot’s Guide has great advice on reviewing pull requests.
My process for reviewing a pull request is to first review the code on GitHub for any errors, opportunities for improvement, or obvious bugs. I make sure to understand what the pull request is attempting to do as a unit and also what each commit accomplishes towards this goal. If I do not understand I ask the requester questions to create this understanding. Once I fully understand the pull request I clone it to my local machine. There I run and check to see if the test suite passes. Then I actually run the app to try out the feature or go through the steps to reproduce to the fixed bug to prove it has been fixed. Once this has occurred I approve the pull request and let the requester merge it into the develop branch. Then the update is deployed to a staging instance to be tested one last time by a developer and any relevant outside parties before being promoted to production.
Fixing bugs on your own or other software can be challenging. With the right toolset, you can surmount these challenges and successfully get your software working. Your first step is to reproduce the bug. Hopefully, the user has submitted enough information so you can see and experience the bug for yourself. If not, you need to open the lines of communication with your user so that you can effectively reproduce it. If they are getting the bug and you are not, you need to figure out what is different between their setup and yours that might be causing the bug. If you cannot reproduce a bug, you do not understand it and most certainly will not be able to fix it.
Once you can reproduce the bug you need enough information to figure out what is going wrong in your code to cause it. There is a large menu of options of what can cause incorrect software behavior, your job is to eliminate options from that menu by trying the most likely things and working your way to the least likely things. If you are lucky you get a warning message somewhere that surfaces an obvious solution. Googling reveals a typo or need to coerce an object to another type. If you are unlucky you enter the frontier of the unknown. You uncover a bug in the web framework or programming language you use. An external API behaves differently than its documentation suggests. All sorts of crazy things can happen and go wrong in software, so when it comes to things you believe to be true: trust, but verify.
How to Build These Skills
Many of these skills involve coding in teams and working with users. While you are now one step ahead of your peers by reading about them above, you will only master them through practice and experience. The best way to get this practice and experience is to work on real projects with other developers. Try your hand at an issue for an open source project. Submit a pull request. As long as the project is maintained, you will likely get the feedback you need to improve your code.
Today I spent a lot of time trying to figure out how to organize a controller in Rails where we needed to filter based on some query params. I was initially inspired to follow a pattern from DHH which turned out to be a bit challening to follow due to some incomplete information in the original blog post. The first thing that the blog post had failed to explain was how to organize files in a situation with the co-controllers. The answer to this quesiton is that you setup a folder with the parent controller name and then name the .rb files after the sub-controller. So in the linked example the “Inboxes::PendingsController” class would go into app/controllers/inboxes/pendings_controller.rb. The second component is that in the routes.rb file you need to be aware that the nested route for the index action must come before the route for the parent resource’s show method. So for example in this commit I made /applicants/interests works, but if I put line 12-14 below line 15, then it would try and find an applicant with the ID intersts and fail to do so.
However I also learned that the sub-controller approach is not great for situations where the client is sending the controller params. After some research I determined the best practice was to simply concede that I should check for the presence of params in the applicants index method and filter on that. It is important to note that after a while your controller can get cluttered with if statements checking for params to filter. Several friends have suggested that the natural evolution of this pattern is to extract the query into a query object that takes params and returns a scope on applicants. This way the query object is testable and my controller does not get bloated.
Finally we also have been struggling with nested controllers in relation to some has_many relationships between our models. The struggle was largely related to the fact that the Rails routing documentation on nested resources does not explain the changes that need to be made to a controller when you start using nested routes with it. However as you can see later in that thread I was lucky enough to find an old Railscast with a useful pattern.
Is your computer or software secure? Despite what the experts or vendors want to tell you, the answer is probably no. This point was driven home to me yesterday when Citizen Lab published a report on three iPhone exploits. These exploits are called 0-days because it has been 0 days since they were known to the public and security researchers. These exploits fetch a large price on the private market and the only reason the intended target was not infected is because he was suspcious of the link. No software updates or other measures can defend you against a properly executed 0-day. It is up to you to reocgnize an attempt to infect you and be vigilant.
Security is a moving target. As companies find exploits they are patched with software updates. I was shocked when I put a new server on the Internet a few months ago and enabled something called LogWatch to show me how many times automated computers scan and probe my server to see if it is vulnerable to known exploits. It is a lot.
So how can we protect oursleves? A lot of the recommended security measures involve locking down the machine in a way that makes common attack vectors more challenging. With most online accounts using a complex password and two-factor authentication make breaking into your account more work. This deterrance approach is the same as getting a home alarm system: it will not make your system impenetrable but it makes it less appealing to opportunists. The second goal is to minimize the potential damage if your system is penetrated. Encrypt important data; restrict permissions. If you use different passwords for each account then when an adversary gets your password they cannot access your other accounts without getting those passwords. Keeping your system updated and using modern operating system software prevents you from getting exploited by known vulnerabilities.
For software developers the approach is different. We are not merely worried about protecting our machine or accounts, but protecting our code itself. Many programming languages have security guides that provide advice on common pitfalls and attacks. With the applications I develop with Ruby on Rails I have learned that there is a static code analyzer called Brakeman that checks for common security holes in your code. Deppbot keeps the modules updated when security updates occur. Finally the last line of defense is vigilence and having peers review your code. If someone discloses a vulnerability it is incumbent upon a developer to fix it as soon as possible. A code review by another experienced programmer can also help spot errors. Despite all this there will be security vulnerabilities, after all Apple and Google have some of the smartest software engineers in the world and they still have to fix vulnerabilities.
The final solution is resilience. Besides being vigilient, making sure that the failure state of being attacked is not going to hurt you badly is a good way to protect yourself. Avoid storing sensitive data if you do not need it. Use the current best practices around encryption if you do. Backup your data offsite so that you still have it if an attacker deletes it. Make a plan about what to do if you are attacked and how you will handle it so you can recover quickly.
As I have been working on my Code for Boston Project I have spent lots of time reviewing pull requests. While it is easy to review pull requests when you are working with someone in the same space everyday, it is a bit more challenging when someone is remote. I think that the good pull requests tend to have a few things in common:
- They are as small as possible. Often a feature can be broken down into multiple steps.
- They include tests for new functionality.
- They pass the existing tests.
- They describe what the feature or bug fix does so that the tester can test it.
- Merge conflicts have been resolved.
- They actually check in all the files necessary for the change.
Some of these are not applicable to some projects, but in general these are the issues I encounter when I’m reviewing pull requests. The most common issues are the size of the pull request, a lack of a description, and someone forgetting to check in a file. While the command line is cool, I strongly recommend a GUI client like Tower 2 to help with git. Otherwise it often takes practice and seeing the other side before you get an intuitive sense for whether your pull request is good.
Earlier this week I had the privilege of attending the Forbidden Research conference with others from Berkman Klein. There the speakers posed the question of “[h]ow can we most effectively harness responsible, ethical disobedience aimed at challenging the norms, rules, or laws that sustain society’s injustices?” This was explored both through panel discussions and also some announcements that were made at the conference. At the end of the conference I felt refreshed and motivated.
The panel that most resonated with me was the panel about the hacks at MIT. There they discussed the process and rules that MIT and its students follow in relation to the famous hacks that involve placing objects on top of the MIT dome. That panel helped me understand that while the students were breaking the rules, there were still a set of norms that governed that rule breaking. Both them and the administration understood it was something that happens and that the students would endeavor to conduct their activities in a responsible and ethical manner despite the fact it was not allowed.
The biggest takeaway I got from the panel is that often it is better to be proactive in reaching out to enforcement agencies than to have egos clash in public later. The other big takeaway is that breaking the rules is often fine if it works, but you can quickly be disavowed if it fails. I think it is fairly evident that we do not have enough space and room for people to experiment and fail in this world, and while I appreciate the idea of the prize that was presented at the conference, I think another good action item would have been to spend time figuring out how we can create more spaces for rule breakers to fail safely and ethically.