How to Design Programs (HtDP)

How to Design Programs: An Introduction to Computing and Programming

Systematic methodology for program design that emphasizes thinking before coding:

Core Design Philosophy:

The Design Recipe:

  1. Data Analysis: Understand the data your program processes
  2. Contract: Specify input/output types and purpose
  3. Examples: Create concrete examples of function behavior
  4. Template: Write function skeleton based on data structure
  5. Body: Fill in the function body
  6. Testing: Verify function works with examples

Example: Processing Lists

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
;; Data Definition
;; A List-of-Numbers is one of:
;; - empty
;; - (cons Number List-of-Numbers)

;; Contract and Purpose
;; sum : List-of-Numbers -> Number  
;; Computes the sum of all numbers in the list

;; Examples
;; (sum empty) should produce 0
;; (sum (cons 3 (cons 7 empty))) should produce 10

;; Template (follows the data structure)
(define (sum lon)
  (cond
    [(empty? lon) ...]
    [(cons? lon) (... (first lon) ... (sum (rest lon)) ...)]))

;; Body (fill in the template)
(define (sum lon)
  (cond
    [(empty? lon) 0]
    [(cons? lon) (+ (first lon) (sum (rest lon)))]))

;; Testing
(check-expect (sum empty) 0)
(check-expect (sum (cons 3 (cons 7 empty))) 10)

Key Principles:

Structure Follows Data:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
;; Binary Tree data definition
;; A BT is one of:
;; - 'leaf
;; - (make-node Number BT BT)

(define-struct node (value left right))

;; Template automatically follows data structure
(define (bt-template bt)
  (cond
    [(symbol? bt) ...]                          ; leaf case
    [(node? bt) (... (node-value bt)           ; node case
                     (bt-template (node-left bt))
                     (bt-template (node-right bt)))]))

;; Count nodes in binary tree
(define (count-nodes bt)
  (cond
    [(symbol? bt) 0]
    [(node? bt) (+ 1 
                   (count-nodes (node-left bt))
                   (count-nodes (node-right bt)))]))

Generative Recursion:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
;; When structure doesn't follow data: generative recursion
;; Example: Collatz conjecture

;; collatz : Number -> Number
;; Counts steps to reach 1 in Collatz sequence
(define (collatz n)
  (cond
    [(= n 1) 0]
    [(even? n) (+ 1 (collatz (/ n 2)))]
    [else (+ 1 (collatz (+ (* 3 n) 1)))]))

;; Need termination argument since structure doesn't follow input

Educational Benefits:

Systematic Thinking:

  • Problem Decomposition: Break complex problems into manageable pieces
  • Type-Driven Development: Let data definitions guide program structure
  • Test-First Mentality: Examples before implementation
  • Refinement Process: Iterative improvement through design recipe

Transferable Skills:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# HtDP principles in Python

from typing import List, Union
from dataclasses import dataclass

# Data Definition
@dataclass
class Empty:
    pass

@dataclass  
class Node:
    value: int
    rest: Union['Node', Empty]

ListOfInts = Union[Node, Empty]

# Contract and Purpose
def sum_list(lst: ListOfInts) -> int:
    """Computes the sum of all integers in the list."""
    
    # Examples (as doctests)
    """
    >>> sum_list(Empty())
    0
    >>> sum_list(Node(3, Node(7, Empty())))
    10
    """
    
    # Template follows data structure
    if isinstance(lst, Empty):
        return 0
    elif isinstance(lst, Node):
        return lst.value + sum_list(lst.rest)

Raft Consensus Algorithm

Raft Consensus Algorithm - Interactive Visualization

Elegant distributed consensus algorithm designed for understandability:

Core Concepts:

Server States:

  • Follower: Passive servers that respond to leaders and candidates
  • Candidate: Server trying to become leader during election
  • Leader: Handles all client requests and log replication

Key Components:

T L H E e o e l r g a e m : r c : t t S b i L e e o o q a n g u t i e : T c n i a c L m l e e e a o c o d u l f e t o r : c c k o s F m e o t m n l h i d l a t s o t t w e t e i d o r n c e m b r n a e e t i c a r n o s i t m e e a e s s i s n m c o a a n u n o t d t h i o o d n r a i i t c t e a y l i l f y n o h e a r t b e a t

Leader Election Process:

Election Flow:

1 2 3 4 5 6 . . . . . . F I S I I I o n e f f f l c n l r d m a e o e a n l w m R j o e e e e o t c r n q r h t t u i e i t e t r o i t s y n m e t l e r V e t o m o o a i u , t t d m t e e e e s r o → o R u t P r d t B e C e i e s c s → c f e c o o t i o S m r o v v t e e e a s a d r r C e l e t a l l → d n f n d s B → e i e e w d r c B a v o e e t e m c l e r e o e s m c L e t e i a F o d o n e l r l o w e r

Election Safety Properties:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Pseudo-code for election logic
class RaftServer:
    def __init__(self):
        self.state = "follower"
        self.current_term = 0
        self.voted_for = None
        self.log = []
        self.election_timeout = random_timeout()
    
    def start_election(self):
        self.state = "candidate"
        self.current_term += 1
        self.voted_for = self.server_id
        votes_received = 1  # Vote for self
        
        for server in other_servers:
            vote_granted = server.request_vote(
                term=self.current_term,
                candidate_id=self.server_id,
                last_log_index=len(self.log) - 1,
                last_log_term=self.log[-1].term if self.log else 0
            )
            if vote_granted:
                votes_received += 1
        
        if votes_received > len(all_servers) // 2:
            self.become_leader()
        else:
            self.become_follower()
    
    def request_vote(self, term, candidate_id, last_log_index, last_log_term):
        # Only vote if:
        # 1. Haven't voted in this term, or voted for this candidate
        # 2. Candidate's log is at least as up-to-date as ours
        if (term > self.current_term and 
            (self.voted_for is None or self.voted_for == candidate_id) and
            self.log_is_up_to_date(last_log_index, last_log_term)):
            self.voted_for = candidate_id
            self.current_term = term
            return True
        return False

Log Replication:

Replication Process:

1 2 3 4 5 6 . . . . . . C L L L L L l e e e e e i a a a a a e d d d d d n e e e e e t r r r r r s a s w c n e p e a o o n p n i m t d e d t m i s n s s i f d t i c s A f s e o p o s m t p r e m o e n f a n m t o n l d a r l d o E j y l c n o o t a t r a w o l r i n e i t d r l l e y s e o s r a g a e o d R c s f e P k p r C n o c o n o t w d m o l s m e i f d t t o g o m l m e l e c n o n l t w t i e e r n s t

Log Consistency:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class LogEntry:
    def __init__(self, term, command):
        self.term = term
        self.command = command

class RaftLeader:
    def replicate_entry(self, command):
        # Append to local log
        entry = LogEntry(self.current_term, command)
        self.log.append(entry)
        
        # Send to followers
        responses = []
        for follower in self.followers:
            response = follower.append_entries(
                term=self.current_term,
                leader_id=self.server_id,
                prev_log_index=len(self.log) - 2,
                prev_log_term=self.log[-2].term if len(self.log) > 1 else 0,
                entries=[entry],
                leader_commit=self.commit_index
            )
            responses.append(response)
        
        # Check for majority
        success_count = sum(1 for r in responses if r.success) + 1  # +1 for leader
        if success_count > len(self.all_servers) // 2:
            self.commit_index = len(self.log) - 1
            return True
        return False

Safety Properties:

Key Guarantees:

  • Election Safety: At most one leader per term
  • Leader Append-Only: Leader never overwrites/deletes log entries
  • Log Matching: If two logs contain entry with same index/term, logs identical up to that point
  • Leader Completeness: If entry committed in term, present in logs of leaders for higher terms
  • State Machine Safety: If server applies entry at index, no other server applies different entry at same index

Network Partition Handling:

S G - - - G - - - W - - c r r h e o C C C o C C R e M S n u a a o u a a e n i y a p n n n p n n m n s r t n n a p o t i w e c i w o o i a r e o i l o n i t t n r i m : t e m u t s t t h c m e h e c i y r 5 t i s l o u t e - 3 t 2 e m n i g t s l o c m a o r u e s e e p s t i v n o r r e a n e e t a u n v r d t r r l i h p s e v e r a v e e l e r e r i t e a n a a a t r e i r d t b l d o c s ( s n s e r l s o l : 3 g : r i e : p n u ( e t o s > 3 n ( s u s r t o 2 n m e 5 > r t m a r / m ≤ i a l 2 5 a l j s ) / l 5 o o p 2 l / p r p l ) y 2 a i e i ) r t r t t y a s i t t g i i i r o n o o n t n u o p h ' g e s r a o l l u s o p g s o f 3 a n d 2

DWIM - Do What I Mean

DWIM - The Jargon File

Computing philosophy emphasizing intelligent interpretation of user intent:

Core Philosophy:

Historical Context:

  • Origin: Warren Teitelman’s BBN-LISP system (1960s-70s)
  • Goal: Systems that understand user intent even with imperfect input
  • Trade-off: Convenience vs. predictability

Implementation Challenges:

1
2
3
4
5
6
7
8
9
;; Original DWIM in LISP
;; If user types (CAR X Y) instead of (CAR (X Y))
;; System might auto-correct to intended meaning

;; But ambiguity arises:
(SETQ FOO (CAR X Y))  ; What did user mean?
;; Option 1: (SETQ FOO (CAR (X Y)))
;; Option 2: (SETQ FOO (CAR X) Y)  
;; Option 3: Syntax error

Modern DWIM Examples:

Successful DWIM:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Python's flexible type system
def add_items(items):
    # Works with lists, tuples, strings, etc.
    result = []
    for item in items:  # DWIM: iterate over any iterable
        result.append(item)
    return result

# Shell command completion
$ git co<TAB>     # Expands to 'git commit' or 'git checkout'
$ ls /us/lo<TAB>  # Expands to '/usr/local'

# URL autocomplete in browsers
"github.com/user/repo" → "https://github.com/user/repo"

Problematic DWIM:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// JavaScript's type coercion (too much DWIM)
"5" + 3    // "53" (string concatenation)
"5" - 3    // 2 (numeric subtraction)  
[] + []    // "" (empty string)
[] + {}    // "[object Object]"
{} + []    // 0 (in some contexts)

// PHP's magic (inconsistent DWIM)
$array = [1, 2, 3];
echo $array;        // "Array" (not very helpful)
echo json_encode($array);  // "[1,2,3]" (more useful)

Design Principles:

Good DWIM Characteristics:

  1. Predictable: Users can learn and predict behavior
  2. Consistent: Similar contexts produce similar interpretations
  3. Reversible: Easy to undo or override automatic behavior
  4. Transparent: Clear about what interpretation was made
  5. Conservative: Err on side of asking rather than guessing

Modern Examples:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# pandas DataFrame - good DWIM
import pandas as pd

df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})

# These all "do what you mean" intuitively:
df['A']           # Column access
df[0:2]           # Row slicing
df[df['A'] > 1]   # Boolean indexing
df['A'] + df['B'] # Element-wise addition

# Git - good DWIM examples
git add .              # Add all changed files
git commit -am "msg"   # Add all and commit
git push              # Push to tracked upstream branch
git checkout main     # Switch to main branch

The Jargon File

The Jargon File

Comprehensive glossary of hacker slang and computing culture:

Historical Significance:

Cultural Documentation:

  • Origins: MIT AI Lab, Stanford, CMU hacker communities
  • Evolution: From 1975 to present, maintained by Eric S. Raymond
  • Purpose: Preserve and explain hacker culture terminology
  • Influence: Shaped understanding of computing subculture

Notable Entries:

Technical Terms:

H K G C a l r r c u o u k d k f : g : t e : ( 2 : T F n . E o r A " . A t o c T ) A y u m c h p m n u i 1 q T o o d R m s . u o o l e o u i r o r b l c A c p l g s e a o n k r y y t r t d - o - : a t e e e a g d n d b l n r e F d H a e d a s r e j s g - m i o s i u e a d g m o n n n i e n m l k h t r n e G e e , a , t t d e t i s y h r h n b c u s m i ' u t l f s o a n s g o e i i l n g s o v x a u " , e s t " c S m r o t i k o t o u , r i o l m r r c c n u p a h o m a g l n p r o l t " e g o c d l h t e o r i i y a ( e r r u n f t c l l f s i o l y i y t p c r w e n - " i a o v a d r t o r e n a e e i b k r d s d o s s ) S i n e i t g s s d + n r n o s e t a e l i s " u n d u v p f i g t e i u t e c i l t d i o o y e g v L d n e e a e i " l n t t y d o s " e a l f p r o g r a m m i n g p r o b l e m

Cultural Concepts:

R W G M e i u u a z r n l a u d r : a P d n r : E e o x : g P m p r r a e N a o g r o m g i t n m r c - e a a w h r m l h a : m o c e a k M d r b o e y r i t r t i w l h ; h n i i e i k t t r s c s h i s o a e m l c d s c e o e o o f f e t n n i f p o s e g e u u e s f l o r , y i t u e s x t a t f s w n e c o i h d m o r d o m e w k p d c o n l i t o r o e f h d k w x f e e s l i s e p c c t d r u o i h g o l m n r e b t p o l u a u a e t t s g n m e i s h d s c n e h g m t s n b h e i c l e e c o y m a m n i l m l i n u a g g p n n h l r i g t y o t u b y a l g e e m , s

Programming Philosophy:

Hacker Ethics (from the Jargon File):

  1. Information wants to be free: Open access to information and code
  2. Mistrust authority: Decentralized decision-making
  3. Judge by hacking ability: Meritocracy based on technical skill
  4. Computers can change life: Technology as force for positive change
  5. Create beautiful, elegant solutions: Aesthetic appreciation of code

Design Values:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Examples of hacker aesthetic values:

# Elegance - simple, clean solution
def factorial(n):
    return 1 if n <= 1 else n * factorial(n - 1)

# vs. verbose alternative
def factorial_verbose(n):
    if n < 0:
        raise ValueError("Negative input not allowed")
    if n == 0 or n == 1:
        return 1
    result = 1
    for i in range(2, n + 1):
        result = result * i
    return result

# Cleverness - non-obvious but brilliant
def reverse_bits(n):
    return int(bin(n)[2:].zfill(32)[::-1], 2)

# Orthogonality - tools that compose well  
# Unix philosophy: do one thing well
cat file.txt | grep "pattern" | sort | uniq -c | head -10

Modern Relevance:

Continuing Traditions:

  • Open Source Movement: Direct descendant of hacker ethics
  • Stack Overflow Culture: Modern Q&A inherits hacker help traditions
  • Code Golf: Competitive programming for shortest solutions
  • Easter Eggs: Hidden features in software
  • RFC Humor: April Fools’ RFCs (like RFC 1149 - IP over Avian Carriers)

Evolution of Terms:

H M H M H M N i o i o i o e s d s d s d w t e t e t e o r o r o r t r n r n r n e i : i : i : r c c c m a O a " a " s l f l T l 1 : : t : e : 0 e c x " " n " h " C H G W e o a c u l i n d c o r e z g e k n u a a i e f " d r n s r l " d e m " a w " e e t a o r l m e s r h " l e d a " a r " d ( , n w e S c t i v t m o " t e a a n T s h r f g t e k e f i r c i " d c o h l c e a v n l r e n l e i e a x g r c d c p i p s a k e n r i l p e r e o a r r t e g l d o " r r e g " a t b r ( m e t a m m r " m a i m , m l n ) e i g " r c Y i a a o b k u i s l s i h a t a t i v t e i a s n c g k " e r )

These resources represent different aspects of computing culture and methodology - systematic program design, elegant distributed algorithms, user-centered design philosophy, and the rich cultural history of computing communities. Together they illustrate how technical and cultural evolution intertwine in the computing field.