Writing Objects to a File
A version number in a file's first line tells a program which layout rules were used, and a higher number signals a newer format.
When a Saved File Outlives Its Program
Imagine a drawing program that saves its pictures to a file. Later, the same program is updated, and the new version may store its information a little differently than the old one did. Will the new version still open the files the old version saved? The honest answer is that it depends on how the data was represented in the file from the beginning.
This article looks at two problems that appear when a file is tied too closely to the exact layout a program uses today. It also looks at two design habits that reduce those problems: storing a version number inside the file, and choosing a format that a person can read and understand. Along the way you will trace what happens to the values in a file as the program changes, so the problems are visible rather than abstract.
Following Values Through a Saved File
A file written without a version number is a long sequence of values. Nothing in the file names each value. Its meaning comes entirely from its position: the reader takes the values in the same order the writer produced them. The reader is only correct if it assumes the same positions the writer used.
The example below is an invented illustration, not one from the source. Version 1 of a program saves two values in this order: a width at position 0 and a height at position 1. Version 2 adds a depth value and places it between them, so the layout becomes width, depth, height. Before you look at the diagram, decide what the old reader will see when it reads position 1.
What do you think happens?
Version 2 writes width, depth, height in that order. A version 1 reader expects height at position 1. What value does it read as height?
Reveal answer
The depth, 16, because that value now sits at position 1
The reader does not look for labels. It counts positions. Position 1 now holds depth, so the old reader treats 16 as the height. The real height has moved to position 2 and is never read as height.
The diagram shows the cause of the failure. Nothing in the file was damaged. The height value still exists at position 2, and the depth value sits exactly where the old reader looks for height. Only the assumed positions have changed, so the old reader quietly reads the wrong number. Because no error is raised, this kind of failure can go unnoticed for a long time.
Why Fixed Positions Make Files Fragile
A file that depends on exact program internals is fragile because its meaning is tied to a specific set of rules inside the program. The file itself does not say which rules were used. If those rules change, the same bytes can be interpreted in a new and incorrect way.
The source gives a concrete case. Suppose the program adds a new property to curves, so that it now expects an extra value for each curve. Every older file becomes unreadable, unless the user happens to remember which version of the program created that file. The data is not damaged in any physical sense. What has changed is the set of rules needed to interpret it.
The Version Number as a Gatekeeper
A well-designed data file begins with a small header that describes the file itself. In the format discussed in the source, the first line names the program that created the file. This gives the program a quick test. When a user picks a file to open, the program can read the first word and confirm the file is the correct type before it tries to read anything else.
The same first line also carries a version number. In the source example it is 1.0. The version answers a different question from the program name. It asks which rules were used to write the rest of the file. Each time the layout changes, the number changes with it, and a higher number means a newer layout.
Follow the diagram for a file from a known version. The program confirms the type, reads the version, recognizes it, and reads the rest of the file using the rules for that version. Now follow a file from a newer version. The program still confirms the type and reads the version, but it does not recognize the version. The source says the program should explain that a newer version is needed rather than guess at the contents. A guess could produce the wrong values silently, which is exactly the failure shown earlier.
Store the version number inside the file itself, not only in documentation. A reader that sees a version it does not understand can stop and report the problem, which is far safer than interpreting the file under the wrong rules.
Labels That Make a File Readable
A human-readable format uses clear labels so that a person looking at the file can tell what each piece of data means. In the source's example, a line in the file begins with the word background and is followed by three numbers. Those numbers are the red, green, and blue components of the color. The label removes the guesswork, so the line explains itself.
The same idea appears in the curve data. Each curve is wrapped between the markers startcurve and endcurve. Inside those markers the file holds the curve's color, its symmetry property, and the xy-coordinates of each point. Because the structure is spelled out in words, a reader can follow the file from top to bottom without running a program.
Readability has practical value in three ways. Files in this format can be created or edited by hand, and the source notes that the example file was in fact written in a text editor rather than produced by the program. A readable file is easier to debug, because a missing marker or a misplaced number is visible on the page. And labeled data is easier to extend, since a new option can be added as a new labeled line without forcing every reader to memorize a fixed position.
| Aspect | Position-based layout | Labeled, readable format |
|---|---|---|
| Meaning of a value | Depends on its position in the file | Stated by a label next to the value |
| Adding a new value | Can shift every later value and break old readers | Can be added as a new labeled item |
| Editing by hand | Hard, since a person must count positions | Possible in a text editor |
| Finding a mistake | A misplaced value looks like any other value | A missing marker or misplaced label is visible |
Two ways to lay out the same information in a file.
Mistakes When Designing a Data File
Common mistake Assuming a file is safe because nothing has been lost
What it looks likeThe old reader in the earlier example reads 16 as the height, yet no error is raised and the file still looks complete.
Why it failsA file can be fully intact and still be misread. Meaning depends on the rules used to interpret the bytes, not only on whether the bytes exist.
Do this insteadRecord which layout rules were used, so a reader can check whether it understands them before reading.
Common mistake Leaving out a version number because the file seems simple
What it looks likeA program saves a list of values with no header. A later update adds one value in the middle of the list.
Why it failsWithout a version, a reader has no way to tell which layout produced the file, so older and newer files look identical.
Do this insteadStart every data file with a small header that names the file type and carries a version number.
Common mistake Guessing at the contents of a file with a newer version
Why it failsThe source says a program that meets a version it does not understand should explain that a newer version is needed rather than guess. A guess can produce wrong values with no warning.
Do this insteadCheck the version number first, and stop with a clear message when the version is not recognized.
Common mistake Using unlabeled values when a person may need to edit the file
Why it failsUnlabeled numbers force the reader to remember their meaning and their order. Mistakes are hard to spot and hard to fix by hand.
Do this insteadGive each piece of data a clear label, as in the background line that begins with its name.
Checking Your Understanding
A program saves a file with the header line 'drawing 1.0' followed by a list of values in fixed positions. Version 2 inserts a new value at position 0 and moves every other value one place down. Without changing the program, explain what a version 1 reader will read at each position, and state what the version 2 program should do when it opens a version 2 file that it does not recognize.
Hints
- Compare the position of each value in version 1 with its position in version 2.
- Think about what the reader assumes about position when the header says 1.0.
- The source says an unrecognized version should lead to an explanation, not a guess.
Key Takeaways
- 1A file that relies on fixed positions is fragile, because its meaning depends on the exact rules the program used when it wrote the file.
- 2A version number in the first line tells a program which layout rules were used, and a higher number signals a newer format.
- 3A program that meets a version it does not understand should explain that a newer version is needed rather than guess at the contents.
- 4Labeled, human-readable formats are easier to create, edit, debug, and extend, because each value carries its own meaning.
At a glance
- A file that relies on fixed positions is fragile, because its meaning depends on the exact rules the program used when it wrote the file.
- A version number in the first line tells a program which layout rules were used, and a higher number signals a newer format.
- A program that meets a version it does not understand should explain that a newer version is needed rather than guess at the contents.
- Labeled, human-readable formats are easier to create, edit, debug, and extend, because each value carries its own meaning.