[Style] modules and tables

This commit is contained in:
Matthias Felleisen 2011-02-27 17:14:53 -05:00 committed by Eli Barzilay
parent dbfbd6e860
commit 4c57167af7
4 changed files with 179 additions and 18 deletions

View File

@ -14,6 +14,7 @@
(all-from-out scribble/manual))
(provide
codebox
compare ;; create a comparison box for two code snippets
;; good ;; label a code fragment 'good' [doesn't work]
;; bad ;; label a code fragment 'bad' [doesn't work]
@ -30,6 +31,11 @@
(define stuff (list (list stuff1) (list stuff2)))
(table (sty 2 500) (apply map (compose make-flow list) stuff)))
;; good: a code snippet in a box
(define (codebox stuff1)
(define stuff (list (list stuff1)))
(table (sty 1 700) (apply map (compose make-flow list) stuff)))
(define-syntax (column-table stx)
(syntax-case stx (col)
[(_ (col x ...) ...)

View File

@ -1,17 +0,0 @@
#lang scribble/base
@(require "shared.rkt")
@title{Size Matters}
@; -----------------------------------------------------------------------------
@section{Code Units}
Keep functions small. Keep classes small. Keep units small. Keep modules small.
Anytime a unit of code looks incomprehensible, it is probably too
large. Break it up into smaller units. To bring across what these smaller
units compute, implement or serve, use meaningful names; see
@secref{names}. Conversely, if you can't come up with a good name for such
units, you are probably looking at the wrong kind of division; consider
alternatives.

View File

@ -52,6 +52,6 @@ create code for the PLT code base.
@include-section["correct-maintain-speed.scrbl"]
@include-section["some-performance.scrbl"]
@include-section["size.scrbl"]
@include-section["unit.scrbl"]
@include-section["constructs.scrbl"]
@include-section["textual.scrbl"]

View File

@ -0,0 +1,172 @@
#lang scribble/base
@(require "shared.rkt")
@title{Units of Code}
@; -----------------------------------------------------------------------------
@section{Module Interfaces}
The purpose of a module is to provide some services. @margin-note{The
modules we discuss in this section coincide with files.}
@centerline{Equip a module with a short purpose statement.}
Its interface describes which services it provides, and its body implements
the services. At least in principle others shouldn't have to read the
implementation ever, but it is quite likely that they have to read the
interface.
@centerline{Place the interface at the top of the module.}
@compare[
@;%
@(begin
#reader scribble/comment-reader
(racketmod #:file
@tt{good}
racket
;; This module implements
;; several game strategies.
(require "game-basics.rkt")
(provide
;; Strategy = GameState -> Action
;; Strategy
;; a GUI-based plug in for people
human-strategy
;; Strategy
;; a complete tree traversal
ai-1-strategy
;; Strategy
;; alpha-beta pruning traversal
ai-2-strategy)
;; ------------------------------------------------------------------------------------------
(define (general-strategy p)
... )
;; ------------------------------------------------------------------------------------------
... some 100 lines ...
(define human-strategy
(general-strategy create-gui))
;; ------------------------------------------------------------------------------------------
... some 100 lines ...
(define ai-1-strategy
(general-strategy traversal))
;; ------------------------------------------------------------------------------------------
... some 100 lines ...
(define ai-2-strategy
(general-strategy alpha-beta))))
@(begin
#reader scribble/comment-reader
(racketmod #:file
@tt{bad}
racket
;; This module implements
;; several game strategies.
(require "game-basics.rkt")
;; Strategy = GameState -> Action
;; ------------------------------------------------------------------------------------------
(define (general-strategy p)
... )
... some 100 lines ...
;; ------------------------------------------------------------------------------------------
(provide
;; Strategy
;; a GUI-based plug in for people
human-strategy)
(define human-strategy
(general-strategy create-gui))
... some 100 lines ...
;; ------------------------------------------------------------------------------------------
(provide
;; Strategy
;; a complete tree traversal
ai-1-strategy)
(define ai-1-strategy
(general-strategy traversal))
... some 100 lines ...
;; ------------------------------------------------------------------------------------------
(provide
;; Strategy
;; alpha-beta pruning traversal
ai-2-strategy)
(define ai-2-strategy
(general-strategy alpha-beta))))
]
As you can see from this comparison, an interface shouldn't just be a
@scheme[provide] with a list of names. Each identifier should come with a
purpose statement.
@bold{Note} Following this documentation guideline is most applicable to
modules that are a component of a large application. It is less relevant
for a module in the Racket that comes with a full-fledged description in
the guide.
While a one-line purpose statement for a function is usually enough, syntax
should come with a description of the grammar clause it introduces
@emph{and} its meaning.
@codebox[
@(begin
#reader scribble/comment-reader
(racketmod #:file
@tt{good}
racket
(provide
;; (define-strategy (s:id a:id b:id c:id d:id)
;; action:definition-or-expression)
;;
;; (define-strategy (s board tiles available score) ...)
;; defines a function from an instance of player to a placement
;; The four identifier denote the state of the board,
;; the player's hand, the places where a tile can be
;; placed, and the player's current score.
define-strategy)
))]
If the performance of your module doesn't suffer too much from contracts,
consider using @scheme[provide/contract]. The use of type-like contracts
(constructor predicates that check only a tag) impose a tolerable overhead
and still discover simple mistakes.
Finally, a module consists of sections. It is good practice to separate the
sections with comment lines. You may want to write down purpose statements
for sections so that readers can easily understand which part of a module
implements which service. Alternatively, consider using the large letter
chapter headings in DrRacket to label the sections of a module.
@; -----------------------------------------------------------------------------
@section{Functions & Methods, Classes & Units}
@; -----------------------------------------------------------------------------
@section{Size Matters}
Keep functions small. Keep classes small. Keep units small. Keep modules small.
Anytime a unit of code looks incomprehensible, it is probably too
large. Break it up into smaller units. To bring across what these smaller
units compute, implement or serve, use meaningful names; see
@secref{names}. Conversely, if you can't come up with a good name for such
units, you are probably looking at the wrong kind of division; consider
alternatives.