How I do my taxes

< Adulting bookmarks

NOTE: This page is an explanation of how I, personally, prepare and file my own taxes. It is not intended as tax advice, and I am not qualified to give such advice. It also includes example numbers and calculations. These are intended only to illustrate the general approach I use, and the details of these examples may not reflect reality. Please do not use any information here in your tax preparation without first independently verifying its accuracy and applicability to your situation.

Any code snippets contained here are offered under the terms of the MIT License, which notably disclaims all warrantees and liability.

I'm mostly writing this to provide context for my bookmark of Free File Fillable Forms, and why I like it so much.

All software I've encountered for filing taxes, save one, works in an "interview" style. The tax software asks the user a series of questions. The answers to these questions are used to decide which tax forms are needed and to fill them out. This would, on the surface, appear to make things easier for the user.

I did this for many years. The problem I encountered is simply that I have poor memory. Some of the questions were full of jargon that appeared to be lifted directly from forms and form instructions (sadly I cannot provide an example because I didn't do that this year, and I'm not willing to provide personal information just to see what questions I'm asked). I found myself having to correlate questions with form instructions to figure out what they mean. Further, I would not remember this information the next year, and despite saving all my returns, I'd have no record of how I answered the questions last year, and certainly not why.

In 2017, I tried a different approach. I downloaded the forms and form instructions directly from the IRS, and I wrote a little Python class to help me:

#!/usr/bin/env python3

import math
import sys

assert(sys.version_info >= (3,)) # Python 3.x for true division

class Form(object):
    def __init__(self, name, rounding=False):
        object.__setattr__(self, 'name', name)
        object.__setattr__(self, 'rounding', rounding)

    def __setattr__(self, name, value):
        if name in self.__dict__:
            raise ValueException("tried to assign %s line %s twice" % (self.name, name))

        if isinstance(value, float) and self.rounding:
            frac, whole = math.modf(value)
            if frac > 0.49999999:
                whole += 1
            value = int(whole)

        print("%s line %s = %s" % (self.name, name, value))

        object.__setattr__(self, name, value)

    def __setitem__(self, name, value):
        self.__setattr__(str(name), value)

    def __getitem__(self, name):
        return getattr(self, str(name))

I could then use it like this:

w2 = Form("W-2")
w2[1] = 12345.67 #wages
w2[2] = 1234.56 #fed tax withheld

f1040 = Form("1040", rounding=True)
f1040[7] = w2[1]

If I then run the program in Python, I get this output:

W-2 line 1 = 12345.67
W-2 line 2 = 1234.56
1040 line 7 = 12346

If I also save the output, I have a record of: all the inputs into the process, exactly how every calculation was done, and any further relevant information I want to provide through comments. Once I have all the calcuations in the program, I use shell redirection to save the output to a text file (so I also have a record of calculation results), and I enter the numbers into the forms. I use Free File Fillable Forms for my federal return, and for my state taxes I type numbers into the form PDFs (which I then have to print out and mail, sadly).

If I need to make an assumption that may not always hold for me (such as numbers falling in a specific range of a table, or a number being below a certain amount), I will often use the assert statement to document and enforce this assumption. So, if I am told to look up an entry in a tax table, my code might look like this.

# taxable income: 42069
assert(42050 < f1040[15] <= 42100) # lookup range from tax table
f1040[16] = 4817 # from tax table

If I were to change my inputs or intermediate calculations such that line 15 of Form 1040 fell outside the range I had looked up in the table, the program would fail, and I would know that I need to redo the lookup.

Unfortunately, this leaves open the possibility that I redo the lookup, remember to update the range, and forget to update the result. I couldn't come up with a way to catch that error. I pay special attention when doing table lookups for this reason. In the future, though, I may try deleting all related numbers in a single step, so that if I forget to fill one in I get a syntax error.

The next year, I make a copy of my saved program from last year, and I adjust it with new inputs, and for any changes that year.

As for how well this works, I can only really say that I personally like it. It makes me feel like I have the information I need, and that if I have to revise or figure out how I made a mistake, I'm well equipped to do so. But it also doesn't feel as "safe" as having a professional or commercial program handle things for me. My guess is that basically no one other than me will have the particular skillset where this approach makes sense. I know some people use spreadsheets, but with those I would worry that the lack of symbolic names and comments would make documentation more difficult (but maybe I'm wrong, I'm not experienced with spreadsheets). But in spite of the lack of broad utility, I hope this was at least interesting to someone.