CSC 321.01, Class 13: Software as a service
Overview
- Preliminaries
- Notes and news
- Upcoming work
- Questions
- DRYing out your code
News / Etc.
- I know that there is a planned student protest on March 1. I will still hold class, but I will not penalize you for missing class.
- Sorry about Friday’s class.
- Note for next semester: Sam should rearrange.
Upcoming work
- Read SaaSbook chapter 7 on Behavior-Driven Design for Wednesday.
- Reading Journal due Wednesday.
- Sinatra Hangman exercise from chapter 2 of the SaasBook for Friday. (It should be in “Intro to BDD, TDD, and SaaS” on the MOOC. I’ll work on getting links updated tonight.)
- There was no reading journal for today. Sorry.
Good things to do
Nope, no extra credit.
- Executive debate for SGA elections. Thursday 8pm JRC 101.
- CS Table, Tuesday, 21 Feb 2017, noon: Net neutrality.
- Women in CS, Tuesday, 21 February 2017, 7pm
- CS Extras, Thursday, 23 February 2017, 4:15 pm: The future of MathLAN
Questions
DRY
- It means: “Don’t Repeat Yourself.”
- Why is this an important principle?
- Only fix or improve code once
- Often makes the code cleaner and easier to read.
- Can improve efficiency or locality (less code means it is more likely to stay in the cache)
- Makes programmers more efficient
What are techniques we know to help us avoid repeating ourselves?
Write functions instead of writing the same code multiple times.
(define irgb-flatten
(lambda (color val)
(irgb (* val (round (/ (irgb-red color) val)))
(* val (round (/ (irgb-green color) val)))
(* val (round (/ (irgb-blue color) val))))))
(define component-flatten
(lambda (component val)
(* val (round (/ component val)))))
(define irgb-flatten
(lambda (color val)
(irgb (component-flatten (irgb-red color) val)
(component-flatten (irgb-green color) val)
(component-flatten (irgb-blue color) val))))
; And yes, we could improve this even more
(define irgb-flatten
(lambda (color-val)
(apply irgb (map (section component-flatten <> val)
(irgb->list color)))))
Another example
// Volume of prism one
prism1vol = prism1width * prism1height * prism1depth;
prism2vol = prism2width * prism2height * prism2depth;
prism3vol = prism3width * prism3height * prism3depth;
prism4vol = prism4width * prism4height * prism4depth;
int
volume (int width, int height, int depth)
{
return width * height * depth;
} // volume
prism1vol = volume (prism1width, prism1height, prism1depth);
prism2vol = volume (prism2width, prism2height, prism2depth);
prism3vol = volume (prism3width, prism3height, prism3depth);
prism4vol = volume (prism4width, prism4height, prism4depth);
I think that’s more readable. What is evidence that it’s not DRY?
- It doesn’t look DRY. (It looks WET. Weirdly Excessive Typing.)
- Sam wrote it by copy-and-paste. Copy-and-paste is generally a sign that you are not writing DRY code.
How would you dry out that code?
Idea 1: We should be using objects or structs to represent prisms (prismi?).
Idea 2: We could use a list or array along with a for loop.
for (int i = 0; i < prisms.length; i++)
{
prismVol[i] = volume (prismWidth[i], prismHeight[i], prismDepth[i]);
}
for (int i = 0; i < prisms.length; i++)
{
maxDim[i] = max (prismWidth[i], prismHeight[i], prismDepth[i]);
}
We could dry out this repetition using lambdas and/or iterators
prismVol = prisms.map { volume }
prismMaxDim = prisms.map { max }
Repetition
print (1); print (2); print (3); print (4); print (5); print (6); print (7);
for (i = 1 ; i <= 7; ++i) { print(i); }
Detour
Is there a difference between
for (i = 1 ; i <= 3; ++i) print (i); // 2 3
and
for (i = 1 ; i <= 3; i++) print (i); // 1 2 3
How does a for loop work?
for (init ; check ; increment) body
-
init. In both cases, i is 1.
-
check. In both cases, i is <= 3.
-
body. Both print 1.
-
increment. In both cases, i is 2.
-
check. In both cases, i is <= 3.
-
body. Both print 2.
-
increment. In both cases, i becomes 3.
-
check. In both cases, 3 <= 3.
-
body. Both print 3.
-
increment. In bothc ases, i becomes 4.
-
check. In both cases i ! <= 3
Is there a difference between
i = 5; x = i++; // i = 6, x = 5
and
i = 5; x = ++i; // i = 6, x = 6
Quick review
- Functions to extrract common components
- Arrays + Repetition
- Repetition
- Iterators
- HOP
How else?
- Generics, for languages that support them. Rather than writing the same code again and again for different types, you just write one set of generic code.
- Libraries: Don’t reinvent the wheel (unless it’s a bad wheel).
- Interfaces and polymorphism.
- Write code that works with similar objects, even if they are
different types. (Works well with duck typing.)
- If it walks like a duck and squawks like a duck, it must be a duck.
- I can write a sorting routine for anything that provides a compareTo method.
- Write code that works with similar objects, even if they are
different types. (Works well with duck typing.)
- Inheritance.
- Don’t reimplement the methods of your parent
- Global constants.
- PI, rather than 3.14159
- MAX_ARRAY_SIZE rather than 128
- BIGNUM rather than 128
- Ruby’s yield and blocks (a kind of HOP)
- Ruby’s funky repetition statements, like 5.times
- Ruby’s metaprogramming (e.g., for getters and setters)
- Ruby’s mixins
Use these techniques as you go. Pay attention to non-DRY code, and use one or more to DRY your code out.