Hacker News new | past | comments | ask | show | jobs | submit login

Org-mode and literate programming.

Bring all the code into a set of org-mode files each file has one code block, which emits back the original code. You can verify this using diff or (better) putting the initial repo into git if it's not already and seeing if your emitted code causes any unstaged changes to appear. Start dividing the blocks into more logical chunks (includes, declarations, definitions, one block per function implementation, etc.). Use a hierarchy like:

  * foo.c
  #+BEGIN_SOURCE c :tangle foo.c :noweb tangle
    <<foo-includes>>
    <<foo-file-variables>
    <<foo-functions>>
  #+END_SOURCE
  ** includes
  #+NAME: foo-includes
  #+BEGIN_SOURCE c
    #include<stdio.h>
    #include "bar.h"
    #include "foo.h"
  #+END_SOURCE
  ** file variable declarations
  #+NAME: foo-file-variables
  #+BEGIN_SOURCE c
    int x, y, z;
    some_struct a, b, c;
  #+END_SOURCE
  ** Function bodies
  #+NAME: foo-functions
  #+BEGIN_SOURCE c :noweb tangle
    <<foo-baz>>
    <<foo-quux>>
  #+END_SOURCE
  *** baz: int->int
  #+NAME: foo-baz
  #+BEGIN_SOURCE c
    int baz (int i) {
      // some logic
      return some_val;
    }
  #+END_SOURCE
Those variable names are useless, figure out what they actually mean and document them in the org file. Consider renaming them. There are no test cases, create a tests section in the org file and start writing up simple test programs (or use a unit test framework, but you may need to do some significant refactoring before you can do that).

A benefit of org-mode here is that sometimes you want to test some functionality (and have no unit tests yet). So you try to test baz from above. But once you build that source file and a second foo_test.c file you find out that foo has a function, quux, which has dependencies outside of just the header files and foo.c itself. To build this thing you have to build bar.c and maybe even the whole Linux kernel. "Shit!", you say, "How do I handle this?" Well, org-mode to the rescue:

  * Testing Foo
  ** Testing baz
  #+BEGIN_SOURCE c :tangle foo_baz_test.c :noweb tangle
    <<foo-includes>>
    <<foo-file-variables>>
    <<foo-baz>>
    // maybe some other things like the header references.
    // some test code that is able to focus in on just the baz function
  #+END_SOURCE
You've fully isolated that one chunk, and quux is no longer being included in the build for this test. Whatever problems it has don't impact you (for this test). Once you figure out how to isolate or mock quux's dependencies so that you aren't including the full Linux kernel, you can add it to the set of tests. Now the foo file is fully brought under testing and you can more effectively refactor it. And the mocks and all you've made allow you to move to a proper unit test framework if you want, versus the ad hoc initial framework we've produced here.

Even if you don't care about testing your code, the above process (sans the testing part) will allow you to perform a disection on your codebase and get it documented and specced out properly.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: