Your browser doesn't support impress.js. Try Chrome or Safari.

Large-scale Software Development with Elisp

Rocky Bernstein: rocky@gnu.org

Use a spacebar or arrow keys to navigate

Talk Overview

  • Short GUD rewrite demo
  • Development Requirements
  • Internal vs. External linking
  • Testing framework
  • Questions, where to go from here?

Development Requirements

Here are the things that are important to me:

  • Of course, I use GNU Emacs.
  • I need to be able to break this program into small chunks or modules.

Development Requirements

Here are the things that are important to me:

  • Of course, I use GNU Emacs.
  • I need to be able to break this program into small chunks or modules.
    Implication: there may be many files.

Development Requirements

Here are the things that are important to me:

  • Of course, I use GNU Emacs.
  • I need to be able to break this program into small chunks or modules.
    Implication: there may be many files.
  • I need to be able to run and debug each module in isolation.

Development Requirements

Here are the things that are important to me:

  • Of course, I use GNU Emacs.
  • I need to be able to break this program into small chunks or modules.
    Implication: there may be many files.
  • I need to be able to run and debug each module in isolation.
    Implication: each module needs to have enough information to pull in whatever other modules it needs

Development Requirements

Here are the things that are important to me:

  • Of course, I use GNU Emacs.
  • I need to be able to break this program into small chunks or modules.
    Implication: there may be many files.
  • I need to be able to run and debug each test in isolation.
    Implication: each module needs to have enough information to pull in whatever other modules it needs
  • I want quick development turnaround (edit,test,run...)

Development Requirements

Here are the things that are important to me:

  • Of course, I use GNU Emacs.
  • I need to be able to break this program into small chunks or modules.
    Implication: there may be many files.
  • I need to be able to run and debug each test in isolation.
    Implication: each module needs to have enough information to pull in whatever other modules it needs
  • I want to reduce the development loop.
    Implications:
    • This means reducing the amount of "compilation" time
    • it means I don't want to have to "install" code to try modules I am interested in.
    • I may have an "installed" version and a "development" version and ...
    • I want to be able to run from the "development" code with little overhead.

Development Requirements Continued...

  • I need to be able to test each module in isolation.
  • I need to be run all tests often.
  • Test modules are still modules, so see above.

Development Requirements Continued...

  • I need to be able to test each module in isolation.
  • I need to be able in batch
  • Test modules are still modules, so see above.

  • Implications:
    • Because there are many files there are many tests
    • Tests need to be able to be run interactively
    • Tests need to be run in batch

The Internal/External Linking Problem

A (large) Emacs Lisp program uses modules from many places. Some modules reside inside and some outside.

Example: location positioning might be such a thing.

C #includes

Interestingly the very old language, C, got it right. Consider:

#include "stdio.h"
which can also be written as:
#include "./stdio.h" 
versus:
#include <stdio.h>

Ruby requires

In Ruby 1.9.x:

require 'rubygems'
versus:
require_relative 'rubygems'

load-path is evil

In Emacs Lisp we have load-path which is consulted in load() and require().

Problems with load-path

  • It is insecure
  • It is complex
  • It is fragile

Show curent load-path

load-relative

I wrote emacs-load-relative for internal linking. In its simplest form:

(require 'load-relative) ; pull in (load-relative)
(load-relative "my-module")
(load-relative "./my-module") ; same as above
(load-relative "my-module" 'dbgr) ; find under 'dbgr
(require-relative "my-module" 'dbgr) ; use require instead of load

A real example from emacs-dbgr/debugger/trepan.pl/init.el:

(require-relative-list '("../../common/regexp" 
                         "../../common/loc" 
                         "../../common/init") 
                         "dbgr-")

Testing

Relatively Recent Schools of Testing
  • Test Driven Development (TDD).
  • Behavior Driven Development (BDD)

Some Test frameworks. See http://www.emacswiki.org/emacs/UnitTesting:

Emacs Test Unit

I have 39 tests for over 90 Emacs Lisp files. This is more than Emacs 24 using elr.

Let's now dive into a test from emacs-dbgr, specifically one for testing gdb regular expressions:

Emacs Test Unit Example

Testing gdb regular expressions:

(require 'test-unit) 
(load-file "../dbgr/common/buffer/command.el") 
(load-file "../dbgr/debugger/gdb/init.el")
...
(test-unit-clear-contexts)
...
(context  "traceback location matching"
   (tag regexp-gdb)
   (specify "basic location"
     (assert-t (numberp (loc-match text))))
...
)
(test-unit "regexp-gdb")

Go through example

Running in Batch

  $ remake --tasks # shows what targets are around
  CTAGS
  ChangeLog
  ...
  check
  check-am
  check-recursive
  check-short	# Run all tests without bloated output
  $ cd test
  $ make check-short
	  
  Running specs tagged "bp":
  .
  0 problems in 1 specification using 1 assertions. (0 seconds)
	

The End... Thanks!