Sometimes when I’m working with docker, I’ll have a frustrating experience. I want to do something simple, like copy a shell script into the container and execute it as the container’s entry point, but I miss a silly detail and get stuck for a while. The other day I was trying to run a dockerized Redis instance, and I kept running into a silly permissions issue with the file system that I just couldn’t figure out. In retrospect, as is so often the case in software, I was testing elaborate hypotheses and not checking something obvious, but in case this post saves someone else the trouble, I wanted to go into a little detail. Here’s how to make a redis container that starts with a shell script instead of just starting up the redis server right away. Continue reading “Troubleshooting a basic docker issue: Getting a script into the container”
I’ve been thinking about tests and legacy code. The topic came up when I was listening to an episode of the Legacy Code Rocks podcast with the famous Michael Feathers, author of Working Effectively with Legacy Code. Andrea Goulet, one of the podcast’s hosts, and co-founder Corgibytes, a company that specializes in legacy code, made the observation that when working in legacy code, tests are like bones: They are very important to archeologists, and they stick around.
The analogy of legacy code work to archeology is a good one, but I’m not sure about the analogy between tests and bones. On one hand, bones are very important to archeology. They last a long time (or, as academics would say, they “persist in the archeological record”), and they can be tied to a particular species. But I think tests have a more important aspect than durability. The important thing about tests is that they were written down by their authors. Reading tests is more like finding documents.
When I was studying ancient literature and history in college, there was one glorious semester when I was taking a class in Roman Comedy, and a class in archeology of Roman domestic life. Once, we were having a debate in the archeology class about how private different parts of the house were, asking questions like: “guests are allowed in the atrium, but would it be awkward if some guest wandered into the kitchen?”
This type of question is difficult to answer from an archeological perspective. People have done studies like count the number of doors a person has to pass through from the street to get to a particular room, and used that as a proxy for how “private” the room is considered, but that’s a bit of a guess. Then, when I was reading Roman Comedy, I found a passage where a man starts complaining about how unwanted visitors are trampling all over his privacy because they won’t stay out of the kitchen. In my mind, that answers the question definitively: The way we know Romans felt like the kitchen was more private than the atrium is that one of them makes a joke about unwelcome visitors who aren’t polite enough to stay out of the kitchen. Mystery solved.
Going back to software for a moment: Tests, even bad or very old tests, tell us about what the authors of a system believed at the time that the system actually did. I think legacy code can be approached from two perspectives, much like the Roman house: We can do archeology or we can look at documents. Archeology is reading the source code itself, doing little refactorings, running static analyzers, figuring out when and whether a given method is called. Document-finding is about tests and documentation. If there’s a test that says
test "the autoload module works like normal autoload" do (from Rails), we may not love the descriptor, but we know that the previous developers thought autoloading was a normal thing that people do, and that the code in the test represented normal autoloading. That’s a valuable piece of information. I think in terms of archeology, it’s definitely document-type evidence, not artifact-type evidence.
Let me try to tie the analogy all back together: Archeology and legacy code investigation are similar in that they both involve trying to discover more about some artifact that previous people left. In both cases, we generally can’t ask the original creators of the author what they wrote, either because they don’t work at that company any more, or because they’ve been dead for thousands of years. Legacy code investigation and (recent) archeology both have two primary modes of investigation: By inspecting the artifacts themselves, and by inspecting documents that were produced by the same people as produced the artifacts. Both modes have strengths and weaknesses, but they work well together in concert.
So next time you’re trying to understand some old piece of code that ancient peoples (or you 2 months ago) wrote, remember to examine the artifacts (code itself) and the documents (tests and commit messages) together. And check out the next episode of Legacy Code Rocks!
Till next time, happy learning!
In C#, I can make a custom indexer. In other words, I can write my own class that will let me say things like
var x = myClass[foo]; and have my own code run when we “index” into myClass with foo. In Ruby, I was wondering how to do this. I knew that I could subtype
Hash and get something like this, but (1) that might not be best practice, and (2) I want to know whether
= are built into the language, or I can define their behavior myself. As is often the case with Ruby, this feature is wide open and I can override or modify this behavior. In order to illustrate this, I decided to make a case insensitive dictionary in both Ruby and C#. This dictionary will use strings as its keys, and will return the value associated with a string in any casing. (Note that this is not a dictionary I have a real use case for; I am just building it as an experiment.) Continue reading “Custom Indexers: Ruby vs C#”
Last Saturday I attended my very first computer security Capture the Flag (CTF). This event consisted of teams competing in computer security related challenges to score points. Generally, at the end of the challenge, the team has caused the system we’re attacking to give up a file that says “This is the flag:” and has a long random number. Submitting the flag scores a point, hence “capture the flag.”
First things first: This was a great time, and I highly recommend attending events like this. I came without a team, sat at a table of strangers, and had a great time. Today I’ll talk about what the event was like. Continue reading “CTF is Awesome”
I have a project at work that uses Minitest, but I want to use
mutant to test it. Mutant is a gem that does mutation testing. Mutation testing is an important complement to regular automated testing. Regular automated testing asserts that correct code passes your test suite; mutation testing asserts that incorrect code fails your test suite. In this series, I’m going to try to find the best way to mutation test a Rails app that’s covered mostly be minitest.
Last time, I made a simple model called
Lightswitch so that I could play with mutable state:
class Lightswitch < ActiveRecord::Base attr_accessor :turned_on def turn_on self.turned_on = true end end
When I first wrote the model, not wanting to suggest that my electrical fixtures were aroused, I named the attribute
on instead of
turned_on. I immediately saw some strange errors.
rake test started complaining that there was no column named
true. Today, I’m going to reproduce this error on purpose so that I will understand why, specifically, I can’t use
on as a column name with active record. Continue reading “Don’t YAML on, man (in Rails 4)”
Last time, I learned that using
let blocks in minitest cause minitest to define a method on the test class, and I hypothesized that this was to allow tests to share code while preventing them from sharing state. But the method that gets defined caches the results, so that the initializing block is only evaluated on the first call. I want to convince myself that test methods cannot corrupt this cache, or rather, can’t corrupt this cache without doing so on purpose. Continue reading “State and Caching in Minitest”
I want to know the difference between a few constructs in Ruby, specifically in minitest-spec-rails, so today I’m going to write several similar tests exploring different pieces of the DSL that minitest-spec-rails exposes, and look at the differing behaviors that result. Continue reading “Let blocks in Minitest”
I’ve been thinking about code reviews a lot lately.
My mom has often worked as an editor, and she once told me of the most difficult thing about being an editor (I paraphrase):
You have to let the writer keep his or her style. The challenge is to improve the writing without making it seem like you wrote it.
Working as a technical writer and as an English teacher, I thought about these things a lot. I would often think, “that is not a sentence that I would have written, but it is clear. It works.” Sometimes I would read a sentence and think, “I don’t know what that meant; that sentence doesn’t work.” I would change the sentence in the second situation but not the first. Continue reading “Throwing Darts at Code”
I’ve been thinking a lot about how and when I work recently. I missed a couple Wednesdays posting here, so I’ve been looking at ways to become more consistent.