Link
Software Engineering I
Software as an engineering problem, and the interplay between technical constraints and design demands.
Kevin Lin, with thanks to many others.
1
Ask questions anonymously on Piazza. Look for the pinned Lecture Questions thread.

2
Single-Pair Shortest Path: Dijkstra’s Algorithm
© Mapbox; © OpenStreetMap; Improve this map.

3
Single-Pair Shortest Path: A* Search
© Mapbox; © OpenStreetMap; Improve this map.

Arbitrary Challenging Problem of the Day
Given a weighted graph, find the second-shortest path from a source to a goal vertex.
Given a weighted graph, find the kth-shortest path from a source to a goal vertex.
4
Q
B
C
A
s
5
5
D
1
2
1
0
1
2
4
ACBD
ACD
ABD

k-Shortest Paths Dijkstra’s
PQ.add(s, 0)pathTo[s][0] = [s]; distTo[s][0] = 0For all vertices v, count[v] = 0While PQ is not empty:
pi = PQ.removeSmallest()count[p] += 1If p is goal: add pathTo[p][i] to result	If count[p] = k: returnIf count[p] ≤ k: relax all edges from pi
Relaxing an edge (v, w) with weight:
distTo[w].add(distTo[v][i] + weight)pathTo[w].add(pathTo[v][i] + w)PQ.add(w, distTo[w].getLast())
The Dijkstra’s shortest path to a vertex is only correct when the vertex is visited!

Invariants
pi: ith-relaxed copy of p.
pathTo[v][i]: ith-relaxed path to v.
distTo[v][i]: ith-relaxed distance to v.
count[v]: number of shortest paths to v.
5

6
Case Study: Wheelchair-Accessible Routes
Developing Accessible Routes for Google Maps (Google Developers/YouTube)

Software Development Lifecycle
Analyzing the problem
Market research
Gathering requirements for the proposed business solution
Devising a plan or design for the software-based solution
Implementation (coding) of the software
Testing the software
Deployment
Maintenance and bug fixing
7
Software Development (Wikipedia)

Engineering Computer Software
Unlike other engineering disciplines, software is mostly unconstrained by laws of physics.
Chemical engineers have to worry about temperature.
Material scientists have to worry about the properties of materials.
Civil engineers have to worry about the strength of concrete.

Programming is a purely creative discipline like mathematics and like literature. Computational agents can bring programs to life.
Our greatest limitation is simply understanding the system we’re trying to build!
8

Software Complexity
Our greatest limitation is simply understanding the system we’re trying to build!

As real programs are worked on, they gain more features and complexity.
Over time, it becomes more difficult for programmers to understand all the relevant pieces as they make future modifications.
Tools like IntelliJ, unit tests, and the visualizer all make it easier to deal with complexity.

But our most important goal is to keep software simple.
9

Dealing with Complexity	
There are two general approaches to managing complexity.

Making code simpler and more obvious.
Eliminating special cases, e.g. sentinel nodes. Iterative design, test-driven development, refactoring, can help identify simple ways to implement complex behavior, e.g. k-d tree.
Encapsulation into modules.
In a modular design, creators of one “module” can use other modules without knowing how they work, e.g. our A* search can use any ExtrinsicMinPQ implementation.
10

TMWLO, CSE 373 Edition
programming is [...] fundamentally about the iterative process of refining mental representations of computational problems and solutions and expressing those representations as code
11
Programming, Problem Solving, and Self-Awareness: Effects of Explicit Guidance (Loksa et al./CHI ‘16); Self-Regulated Learning: Beliefs, Techniques, and Illusions (Bjork, Dunlosky, Kornell/Annual Review of Psychology 2013)
The average human can only hold 7 ± 2 chunks of information in their working memory. One of the meta-challenges for learning in this course is determining what chunks make the most most effective use of that space: which mental representations best model a particular problem. Learning happens when you refine and update your mental representations, so we should embrace the mistakes we make along the way. That’s when we know learning is happening.

Nature of Complexity
“Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system.”

Understanding how the code works.
The amount of time it takes to make small improvements.
Finding what needs to be modified to make an improvement.
Difficult to fix one bug without introducing another.

“If a software system is hard to understand and modify, then it is complicated.If it is easy to understand and modify, then it is simple.”
12
A Philosophy of Software Design (John Ousterhout/Yaknyam Press)

Nearest Pseudocode
nearest(Node n, Point goal, Node best):
If n is null: return best
If n.distance(goal) < best.distance(goal): best = n
If goal < n:
closer = n.left
further = n.right
else:
closer = n.right
further = n.left
best = nearest(closer, goal, best)
best = nearest(further, goal, best)
return best
13
Q
Something is missing. What?

Nearest Pseudocode
nearest(Node n, Point goal, Node best):
If n is null: return best
If n.distance(goal) < best.distance(goal): best = n
If goal < n:
closer = n.left
further = n.right
else:
closer = n.right
further = n.left
best = nearest(closer, goal, best)
best = nearest(further, goal, best)
return best
14
A
Missing pruning rule!

Overly-Complex KDNode and ArrayDeque
15

Symptoms of Complexity
Ousterhout describes three symptoms of complexity.

Change amplification. A simple change requires modification in many places. Our overly complex k-d tree was a good example of this.
Cognitive load. How much you need to know in order to make a change. Note that, often, more lines of code actually makes code simpler because it is more narrative.
Unknown unknowns. The worst type of complexity. This occurs when it’s not even clear what you need to know in order to make modifications! Common in large code bases.
16
A Philosophy of Software Design (John Ousterhout/Yaknyam Press)

Obvious Systems
A well-designed software system is, ideally, obvious.

A new developer can quickly and confidently make changes in an obvious system.
Quickly understand how existing code works.
Come up with a proposed change without doing too much thinking.
Feel confident that the change should work without knowing the rest of the system.
17
A Philosophy of Software Design (John Ousterhout/Yaknyam Press)

Complexity as the Accumulation of Technical Debt
Every software system starts out beautiful, pure, and clean.
As they are built upon, they slowly twist into uglier and uglier shapes. This is almost inevitable in real systems. “Move fast and break things” often incurs technical debt.

“Complexity comes about because hundreds or thousands of small dependences and obscurities build up over time… Eventually, there are so many of these small issues that every possible change is affected by several of them.”

Ousterhout recommends a zero tolerance philosophy.
18
A Philosophy of Software Design (John Ousterhout/Yaknyam Press)

Case Study: Tactical Programming
As a startup, Facebook embraced tactical programming: “Move fast and break things.”
Common for new engineers to push changes to the live site within their first week. Very rapid development process in the short term, and it felt empowering!

Facebook was very successful but its codebase was a mess.
“incomprehensible, unstable, few comments or tests, and painful to work with.”

Eventually, motto became “Move fast with stable infra.”
19
A Philosophy of Software Design (John Ousterhout/Yaknyam Press)

Case Study: Strategic Programming
By contrast Google and VMware are known as highly strategic organizations.
“Both companies placed a heavy emphasis on high quality code and good design.”
“Both companies built sophisticated products that solved complex problems with reliable software systems.”
“The companies’ strong technical cultures became well known in Silicon Valley. Few other companies could compete with them to hire the top technical talent.”

Real world projects and companies succeed with either approach!
20
A Philosophy of Software Design (John Ousterhout/Yaknyam Press)

Tactical vs. Strategic Programming
Tactical programming introduces tons of little complexities and code smells, e.g. making two copies of a method that do something similar. These temporary patches deal with technical debt by taking on more technical debt.

“The first step towards becoming a good software designer is to realize that working code isn’t enough.”

Strategic programming. In real systems: Try to imagine how things might need to be changed in the future, and make sure your design can handle such changes.
In large, changing systems, new problems or new demands will arise. Refactor code.

21
A Philosophy of Software Design (John Ousterhout/Yaknyam Press)

Problem Decomposition
22

Arbitrary Challenging Problem of the Day (Redux)
Suppose we have a 2 dimensional space from 0 to MAX_X and 0 to MAX_Y.
 e.g. MAX_X = 100, MAX_Y = 100.
23
100
100

Arbitrary Challenging Problem of the Day (Redux)
Find all labels that overlap the query.



findAnswer(20, 90, 40, 60) 
[“AA”, “AB”, “BA”, “BB”]
24
AA
AB
AC
AD
BA
BB
BC
BD
CA
CB
CC
CD
DA
DB
DC
DD
100
100
(20, 90)
(40, 60)

25
Goal: Fill in the findAnswer Method
public class Rasterer {
  private static final double MAX_X = 100;
  private static final double MAX_Y = 100;

  public static List<String> findAnswer(double x1, double y1,
                                        double x2, double y2) {
    // TODO
    return null;
  }
}
What are some potentially useful helper methods?

Arbitrary Challenging Problem of the Day (Redux)
Find all labels that overlap the query.



findAnswer(20, 90, 40, 60) 
[“AA”, “AB”, “BA”, “BB”]
26
AA
AB
AC
AD
BA
BB
BC
BD
CA
CB
CC
CD
DA
DB
DC
DD
100
100
(20, 90)
(40, 60)
Q