If you are anything like me, you may find yourself hacking on a variety of different applications during a given week.
Occasionally I get the luxury of working on a single app, which gives my brain the freedom to immerse itself into the details of the program. However, inevitably at some point I have to set the project aside and fire up a different one… perhaps one that was written months, or even years ago.
Several thoughts have repeatedly surfaced as I re-familiarize myself with an old project. Instead of having to collect them each time, I thought I’d write them down here, to serve as a reminder.
My personal programming pitfalls
1. Don’t mess with the repository
Anything I might need to recreate should exist within the repository. I should never set up assets that can not be fetched with anything other than a
composer install, and
2. Include working migrations & functional data seeders
When pulling from a repository, I shouldn’t need a database with any pre-populated information. I should be able to create a new database and get up and running with
php artisan migrate —seed.
3. Have an extensive test suite that is safe to run at any time
This one is key! It’s nearly impossible to remember everything an app does, especially after any length of time has passed. A good test suite ensures, at a minimum, I won’t break anything the tests covered when I start making modifications. As a bonus it also acts as a form of documentation!
While we’re talking about tests, occasionally I have a test that will need to communicate with a third-party API (naughty, naughty) and I only run it at specific times.
For example, one app subscribes an email to MailChimp, and I like to actually test that the subscription works. The pitfall is, if I don’t remember to add
$this->markTestSkipped(), it will run next time I trigger the whole suite. Things like this raise red-flags for me and I try to avoid them at all cost.
4. Starting the queue worker shouldn’t cause side-effects
During development I tend to run queueable operations through the
sync queue driver, but occasionally I will push things onto an actual queue, like Redis or Beanstalk. The issue being, if I’m not careful when I start the queue worker, there may be old jobs on the queue that end up being run.
What I’ve done to remedy this it is to make sure I protect myself from any actions or functions that would modify data, or send it anywhere I don’t want. I also use dummy emails and a service like MailTrap to catch any emails being sent from my development environment.
5. Be very careful with auto-deploy features
As handy as it is during development to have a service deploy your code to a staging server when you push new commits, it can bite you if you don’t remember you have it turned on! On projects that have moved out of the development phase, I tend to turn off auto-deploy as a safeguard.
6. Ask if my future-self will understand or remember
This sounds cheesy, but it has helped me. If there is any functionality, or practice that causes me to say “I need to remember this”, I try to figure out a different way to handle it. It’s highly unlikely that I can remember all my kid’s birth-years, let alone that I should not run a specific function on an app from a year ago!
This list could go on and on, but these six items are the ones that repeatedly surface.
Feedback from my peers
I was also curious if any of the other programmers I interact with had similar experiences, or if they had uncovered anything that could help this process. I posed the following question:
When you open a project you wrote X months ago, what do you have to remember, or what do you hope you didn't do?
To me, it all comes down to documentation. While working it is important to remember that the little things you figure out will need to be transferred to other team members along the way. If you don’t document it they will be stuck at square one trying to figure it out again themselves.
To document, I often find that a readme.md file within the repository itself is a best practice. I don’t try to write everything there, but instead link of to other Markdown files that address specific topic area (queues, emails, complex design choices, and even shortcomings I hope to fix some day). While this will leave other devs that come on to the project with some work to do getting up to speed, it serves as a map they can start with to relieve as much burden as possible.
Have been learning to stop being so clever and just use default methods and to favor discoverability instead of trying to abstract and hide code in little nooks and crannies just for the sake of cutting a few lines out of a class. Not worth it in the long run and can really kill ya six months later.
Not having tests is a problem with some older projects. Most of my last job had none. I've been a lot better about stuff I'm working on in my new job - leading by example - having the tests make me more confident in being able to change things much more easily.
Sometimes I fell into design pattern hype, "repository all the things". My focus lately has just been making things simple and building with the knowledge I have on hand. Not worrying about what the code _might_ need to do in the future or even in the next "sprint". Making code easy to refactor as new knowledge is acquired.
As you are working on an exciting project, remember that (hopefully) you will wrap it up, ship it, put it in your resume, and move on to the next app.
BUT, please remember someday you may have to brush the cobwebs off, fire it up, and make some changes.
Be kind to your future-self and try not to be too clever. Leave yourself working tests… and if there are any parts of the app that need more explanation, take the 20 minutes necessary to write them down in a readme.
Thanks, and happy hacking!
Want to read more tips and insights on working with a website development team that wants to help your organization grow for good? Sign up for our bimonthly newsletter.
By Jesse Schutt
Director of Engineering
Jesse is our resident woodworker. His signature is to find the deeper meaning in a project and the right tool for the job.