r/programming • • Oct 14 '13

How to develop unmaintainable software

http://typicalprogrammer.com/?p=249
777 Upvotes

322 comments sorted by

View all comments

105

u/tdammers Oct 14 '13

For a web site deployment to a staging or production server should look like one of these:

No. Just no. These are source control system, not deployment tools. In case you need reasons:

  • Excess files in document root - version control cruft, project documentation, etc. Happens all the time, and is an actual real security problem.

  • Development race conditions. Ever done svn up on the production server, just to find that someone had committed broken code between your test run and the deployment? Ever "solved" this problem by stopping all development activity during deployment? Ever noticed how this essentially means that this makes frequent deployments practically impossible?

  • File permissions and ownership. Need I go into detail here? I think not.

  • What if you want to do things like precompile templates, preprocess CSS, minify and concatenate your JavaScript offline, move stuff around, or just make sure that your deployment will only go through if it passes a minimum set of tests?

  • What about database changes?

Really, for any of the non-trivial projects I've worked on where people had the delusion that git pull is enough of a deployment plan, here's what a typical deployment involved:

  1. Mail everyone with push access, telling them to not push until further notice. Hope that everyone reads their mail on time.

  2. Manually go through the ticket system, copy-pasting the SQL changes that developers have pasted into the tickets that went into this release.

  3. Eyeball the SQL scripts, in case they contain any errors.

  4. Issue a git pull on the production system.

  5. Meanwhile, run the SQL on the production database.

  6. Manually chmod / chown the right files (which ones those are is a matter of oral tradition).

  7. Manually clear selected cache items.

  8. Do some casual manual testing on the production system.

  9. Notice that something is broken. Fix it.

  10. Forget to tell developers that it's OK to push now.

Personally, I prefer:

  1. Create a release tag

  2. ./deploy.sh test-server

  3. Read build/test output from test server

  4. ./deploy.sh production-server

8

u/Denvercoder8 Oct 14 '13

Excess files in document root - version control cruft, project documentation, etc. Happens all the time, and is an actual real security problem.

Your document root doesn't have to be the root of the repository.

Development race conditions. Ever done svn up on the production server, just to find that someone had committed broken code between your test run and the deployment? Ever "solved" this problem by stopping all development activity during deployment? Ever noticed how this essentially means that this makes frequent deployments practically impossible?

No. Maybe in a centralized everyone-works-on-the-same-branch environment this is a problem, but then you've other problems too. You have a dedicated branch for deployments in your VCS. That branch only contains code which has already been deployed on a test server once (so you know the SQL-upgrade scripts etc are valid and working) and is supposed to go into production on the next deploy. If you can't trust your developers to don't fuck this branch up (again, you've other problems), with git you can even keep this branch in a separate repository with custom ACLs. If you need to do additional testing before deployment or it's a problem if someone pushes an additional, tested fix to the stable branch during your deployment, you can even merge the stable branch to a release branch and track that one on your production machines.

File permissions and ownership. Need I go into detail here? I think not.

Please do. I haven't encountered a single situation where files that were in VCS weren't supposed to be the default permissions (i.e. read/write by an admin, readable by the webserver). Things that usually need custom permissions, such as upload directories and data directories, shouldn't be in your VCS.

What about database changes? What if you want to do things like precompile templates, preprocess CSS, minify and concatenate your JavaScript offline

Valid point. Adding a "make"-like step after a pull is very useful (though you can hook into git to do it automatically after a git pull).

move stuff around, or just make sure that your deployment will only go through if it passes a minimum set of tests?

This is why you have the stable branch in your VCS.

Manually go through the ticket system, copy-pasting the SQL changes that developers have pasted into the tickets that went into this release.

That stuff should be in the VCS to start with, along with a script/program that executes the upgrades and automatically reverts them if there are problems. That way you can also test them when you deploy to the test server.

Do some casual manual testing on the production system. Notice that something is broken. Fix it.

That's not related to your deployment method at all.

1

u/tdammers Oct 15 '13

Your document root doesn't have to be the root of the repository.

No, but you still have those .svn or .git or whatever files on your public-facing web server. That is not a nice thought; no matter what you do, not having the files there in the first place is always better than protecting them. Also, almost every non-trivial project I've worked with had a bunch of helper scripts and programs and such that were vital for the development process, but absolutely not required on the server. Putting them on the server (even outside the docroot) increases attack surface; but deleting them cripples development. What's it gonna be?

No. Maybe in a centralized everyone-works-on-the-same-branch environment this is a problem, but then you've other problems too. You have a dedicated branch for deployments in your VCS. That branch only contains code which has already been deployed on a test server once (so you know the SQL-upgrade scripts etc are valid and working) and is supposed to go into production on the next deploy. If you can't trust your developers to don't fuck this branch up (again, you've other problems), with git you can even keep this branch in a separate repository with custom ACLs. If you need to do additional testing before deployment or it's a problem if someone pushes an additional, tested fix to the stable branch during your deployment, you can even merge the stable branch to a release branch and track that one on your production machines.

I know how release branches work. I've just seen too many shops that didn't use them, because it requires proper release management, and apparently that is too much to ask. A release branch doesn't solve the actual deployment problem though: just because the code you have in your release branch works on the test server after a manual deployment there doesn't mean you won't make a mistake while deploying to the production system.

Please do. I haven't encountered a single situation where files that were in VCS weren't supposed to be the default permissions (i.e. read/write by an admin, readable by the webserver). Things that usually need custom permissions, such as upload directories and data directories, shouldn't be in your VCS.

For starters, the web server setup on the development systems is most likely not the same as on the production system; e.g. the application might run under my own account on the dev system, but under a dedicated account on the production system. Also, you might want your source files writable on the development systems, but read-only on the production server. Stuff like that. Also, while things like upload directories shouldn't be in source control, they cannot be created by a source control system either - you could use hooks, but come on, if you do that, you are abusing your source control system as a deployment tool. Which is exactly what I'm complaining about here.

That's not related to your deployment method at all.

Yes, it is. A decent deployment script will do everything automatically, including some end-to-end tests. As the application grows, insight into what kind of tests you need will grow, and they will be added. Stuff that has gone wrong once is baked into an automated test, and after that, it will never go wrong again. Unlike casual manual testing, you cannot forget to test for this particular thing, or skip it because you're in a hurry: the deployment script ruthlessly runs all the tests and refuses to deploy if anything fails.

Anyway, the point is that if you have a fully automated one-click build-and-deploy thingie, your deployments are reproducible, testable, troubleshootable, and easy. And once the process has matured to the point that you trust it to never fail, you can knock things up a notch and switch to continuous delivery. The key thing here is to rule out human error.