[Style] first draft wrapped up
This commit is contained in:
parent
11a04cd6fa
commit
ad583ff720
9
collects/scribblings/style/acknowledgment.scrbl
Normal file
9
collects/scribblings/style/acknowledgment.scrbl
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#lang scribble/base
|
||||||
|
|
||||||
|
@title{Acknowledgment}
|
||||||
|
|
||||||
|
The rules borrow from many sources. While many helped the authors survive
|
||||||
|
their own coding experience, the first author also conducted focus sessions
|
||||||
|
with the members of PLT and these sessions produced many insights about
|
||||||
|
coding style. Jacob Matthews took the time to write up his thoughts on
|
||||||
|
testing, and they are much appreciated.
|
|
@ -39,6 +39,32 @@ racket
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@compare[
|
||||||
|
@racketmod[#:file
|
||||||
|
@tt{good}
|
||||||
|
racket
|
||||||
|
|
||||||
|
(define-syntax (increment! stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ s sn fn i)
|
||||||
|
(with-syntax ([w (r #'s)])
|
||||||
|
(define g (ff #'sn #'w))
|
||||||
|
...)]))
|
||||||
|
]
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@racketmod[#:file
|
||||||
|
@tt{bad}
|
||||||
|
racket
|
||||||
|
|
||||||
|
(define-syntax (increment! stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ s sn fn i)
|
||||||
|
(with-syntax ([w (r #'s)])
|
||||||
|
(let ([g (ff #'sn #'w)])
|
||||||
|
...))]))
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
@; -----------------------------------------------------------------------------
|
@; -----------------------------------------------------------------------------
|
||||||
@section{Conditionals}
|
@section{Conditionals}
|
||||||
|
|
||||||
|
@ -81,7 +107,6 @@ Of course you should also favor @scheme[cond] (and its relatives) over
|
||||||
|
|
||||||
Keep expressions small. Name intermediate results.
|
Keep expressions small. Name intermediate results.
|
||||||
|
|
||||||
|
|
||||||
@compare[
|
@compare[
|
||||||
@racketmod[#:file
|
@racketmod[#:file
|
||||||
@tt{good}
|
@tt{good}
|
||||||
|
@ -101,3 +126,152 @@ racket
|
||||||
(sqr (posn-y p)))))
|
(sqr (posn-y p)))))
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@section{Structs vs Lists}
|
||||||
|
|
||||||
|
Use @racket[struct]s when you represent a combination of a fixed number of
|
||||||
|
values. Don't use lists.
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@section{Lambda vs Define}
|
||||||
|
|
||||||
|
While nobody denies that @racket[lambda] is cute, @racket[define]d
|
||||||
|
functions have names that tell you what they compute and that helps
|
||||||
|
accelerate reading.
|
||||||
|
|
||||||
|
@compare[
|
||||||
|
@racketmod[#:file
|
||||||
|
@tt{good}
|
||||||
|
racket
|
||||||
|
|
||||||
|
(define (process f)
|
||||||
|
(define (complex-step x)
|
||||||
|
... 10 lines ...)
|
||||||
|
(map complext-step
|
||||||
|
(to-list f)))
|
||||||
|
]
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@racketmod[#:file
|
||||||
|
@tt{bad}
|
||||||
|
racket
|
||||||
|
|
||||||
|
(define (process f)
|
||||||
|
(map (lambda (x)
|
||||||
|
... 10 lines ...)
|
||||||
|
(to-list f)))
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@section{List Traversals}
|
||||||
|
|
||||||
|
With the availability of @racket[for/fold], @racket[for/list],
|
||||||
|
@racket[for/vector], and friends, programming with for @racket[for] loops
|
||||||
|
has become just as functional as programming with @racket[map] and
|
||||||
|
@racket[foldr]. With @racket[for*] loops, filter, and termination clauses
|
||||||
|
in the iteration specification, these loops are also far more concise than
|
||||||
|
explicit traversal combinators. And with @racket[for] loops, you can
|
||||||
|
decouple the traversal from lists.
|
||||||
|
|
||||||
|
@compare[
|
||||||
|
@;%
|
||||||
|
@(begin
|
||||||
|
#reader scribble/comment-reader
|
||||||
|
[racketmod #:file
|
||||||
|
@tt{good}
|
||||||
|
racket
|
||||||
|
|
||||||
|
;; [Sequence X] -> Number
|
||||||
|
(define (sum-up s)
|
||||||
|
(for/fold ((sum 0)) ((x s))
|
||||||
|
(+ sum x)))
|
||||||
|
|
||||||
|
;; examples:
|
||||||
|
(sum-up '(1 2 3))
|
||||||
|
(sum-up #(1 2 3))
|
||||||
|
(sum-up (open-input-string "1 2 3"))
|
||||||
|
])
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@;%
|
||||||
|
@(begin
|
||||||
|
#reader scribble/comment-reader
|
||||||
|
[racketmod #:file
|
||||||
|
@tt{bad}
|
||||||
|
racket
|
||||||
|
|
||||||
|
;; [Listof X] -> Number
|
||||||
|
(define (sum-up s)
|
||||||
|
(for/fold ((sum 0)) ((x s))
|
||||||
|
(+ sum x)))
|
||||||
|
|
||||||
|
;; example:
|
||||||
|
(sum-up '(1 2 3))
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
Note: @racket[for] traversals of user-defined sequences tend to be
|
||||||
|
slow. If performance matters in these cases, you may wish to fall back on
|
||||||
|
your own traversal functions.
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@section{Functions vs Macros}
|
||||||
|
|
||||||
|
Use functions when possible; do not introduce macros.
|
||||||
|
|
||||||
|
@compare[
|
||||||
|
@racketmod[#:file
|
||||||
|
@tt{good}
|
||||||
|
racket
|
||||||
|
...
|
||||||
|
;; Message -> String
|
||||||
|
(define (message-name msg)
|
||||||
|
(first (second msg)))
|
||||||
|
]
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@racketmod[#:file
|
||||||
|
@tt{bad}
|
||||||
|
racket
|
||||||
|
...
|
||||||
|
;; Message -> String
|
||||||
|
(define-syntax-rule
|
||||||
|
(message-name msg)
|
||||||
|
;; ===>
|
||||||
|
(first (second msg)))
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@section{Parameters}
|
||||||
|
|
||||||
|
If you need to set a parameter, use @racket[parameterize]:
|
||||||
|
|
||||||
|
@compare[
|
||||||
|
@racketmod[#:file
|
||||||
|
@tt{good}
|
||||||
|
racket
|
||||||
|
...
|
||||||
|
;; String OutputPort -> Void
|
||||||
|
(define (send-to msg op)
|
||||||
|
(parameterize
|
||||||
|
((current-output-port op))
|
||||||
|
(format-and-display msg))
|
||||||
|
(record-message-in-log msg))
|
||||||
|
]
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@racketmod[#:file
|
||||||
|
@tt{bad}
|
||||||
|
racket
|
||||||
|
...
|
||||||
|
;; String OutputPort -> Void
|
||||||
|
(define (send-to msg op)
|
||||||
|
(define cp
|
||||||
|
(current-output-port))
|
||||||
|
(current-output-port op)
|
||||||
|
(format-and-display msg)
|
||||||
|
(current-output-port cp)
|
||||||
|
(record-message-in-log msg))
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
|
@ -59,3 +59,4 @@ Also, we encourage everyone to look over the commit messages. If you see
|
||||||
@include-section["constructs.scrbl"]
|
@include-section["constructs.scrbl"]
|
||||||
@include-section["textual.scrbl"]
|
@include-section["textual.scrbl"]
|
||||||
@include-section["branch-and-commit.scrbl"]
|
@include-section["branch-and-commit.scrbl"]
|
||||||
|
@include-section{acknowledgment.scrbl}
|
||||||
|
|
|
@ -220,8 +220,46 @@ These lines help both writers and readers to orient themselves in a file.
|
||||||
Use meaningful names. The Lisp convention is to use full English words
|
Use meaningful names. The Lisp convention is to use full English words
|
||||||
separated by dashes. Racket code benefits from the same convention.
|
separated by dashes. Racket code benefits from the same convention.
|
||||||
|
|
||||||
|
@compare[
|
||||||
|
@;%
|
||||||
|
@(begin
|
||||||
|
#reader scribble/comment-reader
|
||||||
|
[racketmod #:file
|
||||||
|
@tt{good}
|
||||||
|
racket
|
||||||
|
|
||||||
|
render-game-state
|
||||||
|
|
||||||
|
send-message-to-client
|
||||||
|
|
||||||
|
traverse-forest
|
||||||
|
])
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@;%
|
||||||
|
@(begin
|
||||||
|
#reader scribble/comment-reader
|
||||||
|
[racketmod #:file
|
||||||
|
@tt{bad}
|
||||||
|
racket
|
||||||
|
|
||||||
|
rndr-st
|
||||||
|
|
||||||
|
sendMessageToClient
|
||||||
|
|
||||||
|
trvrs-frst
|
||||||
|
])
|
||||||
|
]
|
||||||
|
@;
|
||||||
|
If you cannot give a unit a good name, consider the possibility that it
|
||||||
|
isn't a proper unit of code.
|
||||||
|
|
||||||
|
You may use dots between parts of names, e.g., @racket[p.x] to suggest that
|
||||||
|
field @racket[x] is selected from struct @racket[p].
|
||||||
|
|
||||||
In addition to regular alphanumeric characters, Racketeers use a few
|
In addition to regular alphanumeric characters, Racketeers use a few
|
||||||
special characters.
|
special characters by convention, and these characters indicate something
|
||||||
|
about the name:
|
||||||
|
|
||||||
@;column-table[ @col[? ! "@" ^ %] @col[1 2 3 4 5] @col[1 2 3 4 5] ]
|
@;column-table[ @col[? ! "@" ^ %] @col[1 2 3 4 5] @col[1 2 3 4 5] ]
|
||||||
|
|
||||||
|
@ -233,3 +271,7 @@ special characters.
|
||||||
@row["@" units a@]
|
@row["@" units a@]
|
||||||
@row[^ signatures a^]
|
@row[^ signatures a^]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Some Racketeers use the suffix of the name to suggest type(-like)
|
||||||
|
information, e.g., @racket[body-xexpr] or @racket[body-xml]. For such uses,
|
||||||
|
a colon is commonly found, e.g., @racket[p:posn] or @racket[p:pair-of-numbers].
|
||||||
|
|
|
@ -27,14 +27,55 @@ If a unit of code looks incomprehensible, it is probably too large. Break
|
||||||
division; consider alternatives.
|
division; consider alternatives.
|
||||||
|
|
||||||
@; -----------------------------------------------------------------------------
|
@; -----------------------------------------------------------------------------
|
||||||
@section{Module Interfaces}
|
@section{Modules and their Interfaces}
|
||||||
|
|
||||||
The purpose of a module is to provide some services.
|
|
||||||
|
|
||||||
|
The purpose of a module is to provide some services:
|
||||||
|
@;
|
||||||
@centerline{Equip a module with a short purpose statement.}
|
@centerline{Equip a module with a short purpose statement.}
|
||||||
@;
|
@;
|
||||||
Often ``short'' means one line; occasionally you may need several lines.
|
Often ``short'' means one line; occasionally you may need several lines.
|
||||||
|
|
||||||
|
In order to understand a module's services, organize the module in three
|
||||||
|
sections below the purpose statement: its imports, its exports, and its
|
||||||
|
implementation:
|
||||||
|
@;%
|
||||||
|
@(begin
|
||||||
|
#reader scribble/comment-reader
|
||||||
|
(racketmod #:file
|
||||||
|
@tt{good}
|
||||||
|
racket/base
|
||||||
|
|
||||||
|
;; the module implements a tv server
|
||||||
|
|
||||||
|
(require 2htdp/universe htdp/image)
|
||||||
|
|
||||||
|
(provide
|
||||||
|
tv-launch
|
||||||
|
tv-client)
|
||||||
|
|
||||||
|
(define (tv-launch)
|
||||||
|
(universe ...))
|
||||||
|
|
||||||
|
(define (tv-client)
|
||||||
|
(big-bang ...))
|
||||||
|
))
|
||||||
|
@;%
|
||||||
|
If you choose to use @racket[provide/contract], define auxiliary concepts
|
||||||
|
related to the contracts between the @racket[require] and the
|
||||||
|
@racket[provide] sections. A test suite section---if located within the
|
||||||
|
module---should come at the every end, including its specific
|
||||||
|
dependencies, i.e., @racket[require] specifications.
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@subsection{Require}
|
||||||
|
|
||||||
|
With @racket[require] specifications at the top of the module, you let
|
||||||
|
every reader know what is needed to understand the module. The
|
||||||
|
@racket[require] specification nails down the external dependencies.
|
||||||
|
|
||||||
|
@; -----------------------------------------------------------------------------
|
||||||
|
@subsection{Provide}
|
||||||
|
|
||||||
A module's interface describes the services it provides; its body
|
A module's interface describes the services it provides; its body
|
||||||
implements these services. Others have to read the interface if the
|
implements these services. Others have to read the interface if the
|
||||||
external documentation doesn't suffice:
|
external documentation doesn't suffice:
|
||||||
|
@ -150,12 +191,29 @@ Consider using @scheme[provide/contract] for module interfaces.
|
||||||
contracts (constructor predicates that check only a tag); they tend to
|
contracts (constructor predicates that check only a tag); they tend to
|
||||||
cost relatively little.
|
cost relatively little.
|
||||||
|
|
||||||
|
@subsection{Uniformity of Interface}
|
||||||
|
|
||||||
|
Pick a consistency rule for the names of your functions, classes, and
|
||||||
|
methods. Stick to it. For example, you may wish to prefix all exported
|
||||||
|
names with the same word, say @racket[syntax-local].
|
||||||
|
|
||||||
|
Pick a consistency rule the parameters of your functions and methods. Stick
|
||||||
|
to it. For example, if your module implements an abstract data type (ADT),
|
||||||
|
all functions on the ADT should consume the ADT-argument first or last.
|
||||||
|
|
||||||
|
@subsection{Sections}
|
||||||
|
|
||||||
Finally, a module consists of sections. It is good practice to separate the
|
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
|
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
|
for sections so that readers can easily understand which part of a module
|
||||||
implements which service. Alternatively, consider using the large letter
|
implements which service. Alternatively, consider using the large letter
|
||||||
chapter headings in DrRacket to label the sections of a module.
|
chapter headings in DrRacket to label the sections of a module.
|
||||||
|
|
||||||
|
With @racketmodname[rackunit], test suites can be defined within the
|
||||||
|
module using @racket[define/provide-test-suite]. If you do so, locate the
|
||||||
|
test section at the end of the module and @racket[require] the necessary
|
||||||
|
pieces for testing specifically for the test suites.
|
||||||
|
|
||||||
@; -----------------------------------------------------------------------------
|
@; -----------------------------------------------------------------------------
|
||||||
@section{Classes & Units}
|
@section{Classes & Units}
|
||||||
|
|
||||||
|
@ -163,3 +221,5 @@ Finally, a module consists of sections. It is good practice to separate the
|
||||||
@section{Functions & Methods}
|
@section{Functions & Methods}
|
||||||
|
|
||||||
|
|
||||||
|
If your function or method consumers more than two parameters, consider
|
||||||
|
keyword arguments so that call sites can easily be understood.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user