Code Mock-ups

This page presents and discusses several code presentation "mock-ups", varying in their use of HTML markup and treatment of white space.

Note: The Elixir code below is taken from page 144 of Programming Elixir 1.2: Functional |> Concurrent |> Pragmatic |> Fun, by Dave Thomas (The Pragmatic Programmers, 2016).

Objective

For sighted readers, the example code's careful use of white space (e.g., indentation, vertical alignment) can help to clarifiy program structure, parallelism, etc. Our task is to make this code accessible to both blind and sighted readers.

Using assorted transformations and combinations of HTML tags, Rich Morin created a series of presentation mock-ups. Amanda Lacy then evaluated each example, using Apple's Safari web browser and VoiceOver screen reader.

Examples

Amanda, who has been blind since birth, recently graduated from the University of Texas at Austin with a B.A. in Computer Science. She will need to read a lot of source code in her career, so she is highly motivated to make this as fast and convenient as possible. Read on for her observations and reactions...

1. PRE

This version uses the pre (preformatted) tag. So, it preserves all of the original white space. This is great, from the perspective of a sighted reader, but Amanda's braille display doesn't handle it well. If she moves to a neighboring, heavily indented line, she's required to space over until something appears. And, if there are more than 40 characters of indentation, the initial version of the line displays no text at all.

#####
def parse_args(argv) do
  parse = OptionParser.parse(argv, switches: [help: :boolean],
                                   aliases:  [h:    :help   ])
  case parse do
  { [ help: true ], _,           _ } -> :help
  { _, [ user, project, count ], _ } -> { user, project,
                                          String.to_integer(count) }
  { _, [ user, project ],        _ } -> { user, project, @default_count }
  _                                  -> :help
  end
end
#####

2. BR, DIV, & TT

This version uses div to generate a shaded block, br (break) to force line breaks, and tt (teletype) to force use of monospace font. So, it generates a "flush left; ragged right" block of text. This gets rid of the massive indentation in the previous example, so Amanda considers it to be a major improvement. Indeed, it's similar to her default format for source code.

#####
def parse_args(argv) do
parse = OptionParser.parse(argv, switches: [help: :boolean],
aliases: [h: :help ])
case parse do
{ [ help: true ], _, _ } -> :help
{ _, [ user, project, count ], _ } -> { user, project,
String.to_integer(count) }
{ _, [ user, project ], _ } -> { user, project, @default_count }
_ -> :help
end
end
#####

3. BR, DIV, NBSP, & TT

This version adds indentation, using a nbsp (non-breaking space) entity for each level. Amanda finds the indentation to be worthwhile and skipping past a space for each level isn't a big deal. Interestingly, although all of her screen readers speak nbsp as "space", VoiceOver renders it as 1-6-8 (rather than a space) on her braille display.

#####
def parse_args(argv) do
 parse = OptionParser.parse(argv, switches: [help: :boolean],
  aliases: [h: :help ])
  case parse do
  { [ help: true ], _, _ } -> :help
  { _, [ user, project, count ], _ } -> { user, project,
   String.to_integer(count) }
  { _, [ user, project ], _ } -> { user, project, @default_count }
  _ -> :help
  end
end
#####

4. BR?, DIV, NBSP, & TT (1)

This version replaces some of the br (break) tags with spaces, allowing arbitrary-length lines. Amanda didn't like the mid-statement line breaks in the previous examples, so she likes the fact that each line contains a complete statement.

#####
def parse_args(argv) do
 parse = OptionParser.parse(argv, switches: [help: :boolean], aliases: [h: :help ])
 case parse do
 { [ help: true ], _, _ } -> :help
 { _, [ user, project, count ], _ } -> { user, project, String.to_integer(count) }
 { _, [ user, project ], _ } -> { user, project, @default_count }
 _ -> :help
 end
end
#####

5. BR?, DIV, NBSP, & TT (2)

This version adds an extra nbsp (non-breaking space) entity for each element in the case statement. Amanda likes the fact that this clearly delineates the "internal" statements in the case construct.

#####
def parse_args(argv) do
 parse = OptionParser.parse(argv, switches: [help: :boolean], aliases: [h: :help ])
 case parse do
  { [ help: true ], _, _ } -> :help
  { _, [ user, project, count ], _ } -> { user, project, String.to_integer(count) }
  { _, [ user, project ], _ } -> { user, project, @default_count }
  _ -> :help
 end
end
#####

6. Indentation keys (1)

This version replaces each sequence of leading spaces with a single-character indentation key. Single digits (0-9) indicate the (abstract) indentation level; question marks (?) flag unusual indentation. A single space separates the key from the actual code.

#####
0 def parse_args(argv) do
1 parse = OptionParser.parse(argv, switches: [help: :boolean],
? aliases: [h: :help ])
1 case parse do
2 { [ help: true ], _, _ } -> :help
2 { _, [ user, project, count ], _ } -> { user, project,
? String.to_integer(count) }
2 { _, [ user, project ], _ } -> { user, project, @default_count }
2 _ -> :help
1 end
0 end
#####

7. Indentation keys (2)

This version replaces each sequence of leading spaces with a two-character indentation key. Two digits (00-98) indicate the starting column; 99 represents itself and any higher value. A single space separates the key from the actual code.

#####
01 def parse_args(argv) do
03 parse = OptionParser.parse(argv, switches: [help: :boolean],
36 aliases: [h: :help ])
03 case parse do
03 { [ help: true ], _, _ } -> :help
03 { _, [ user, project, count ], _ } -> { user, project,
43 String.to_integer(count) }
03 { _, [ user, project ], _ } -> { user, project, @default_count }
03 _ -> :help
03 end
01 end
#####

Futures

Now that we have a reasonable start on the layout of the code, it's time to look into adding support for code folding (selectively hiding and displaying sets of lines). This feature, which would greatly speed up code scanning and navigation, is discussed in the Code Folding page.


This wiki page is maintained by Rich Morin, an independent consultant specializing in software design, development, and documentation. Please feel free to email comments, inquiries, suggestions, etc!

Topic revision: r8 - 31 Oct 2016, RichMorin
This site is powered by Foswiki Copyright © by the contributing authors. All material on this wiki is the property of the contributing authors.
Foswiki version v2.1.6, Release Foswiki-2.1.6, Plugin API version 2.4
Ideas, requests, problems regarding CFCL Wiki? Send us email