correctness through simplicity

Post on 01-Nov-2014

388 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

Correctness through simplicityUlvi K. Guliyev

“…domain of dependable software engineering boils down less to money and more to ethics. Its about your duty as a software engineer to ensure that system is of as higher quality as possible.”

Prof. Joseph Kiniry (Software Development Group)

How do we think about computation?

Meet imperative Bob

void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){

_burps = new List<Burp>();foreach(var dish in dishes){

foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){

Burp burp;switch(foodItem.Kind){

case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;

case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;

default:throw new Exception(“Yuk!”);

}if(burp != null)

_burps.Add(burp);}else{

Environment.Spit(foodItem, bob);}

}}foreach(var burp in _burps){

Environment.Release(burp);}

}

BranchLo

op

Side-effect

Jump

Loop

Side-effect

Loop

Branch

Branch

Branch

Branch

Branch Side-effect

Side-effect

∞ ∞

Meet accidental complexity

How do we change thinking

modality?

• We are computers• Technology is secondary• Intuition and ingenuity• Structured roadmap

Roadmap to dependable software

• Targeted at imperative programmers• Focus on reducing code complexity• Step by step discovery• Meant to alter the way we reason about

computation

Step 1. Procedural decomposition

void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){

_burps = new List<Burp>();foreach(var dish in dishes){

foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){

Burp burp;switch(foodItem.Kind){

case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;

case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;

default:throw new Exception(“Yuk!”);

}if(burp != null)

_burps.Add(burp);}else

Environment.Spit(foodItem, bob);}

}foreach(var burp in _burps){

Environment.Release(burp);}

}

Operational

demarcation

void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){

_burps = new List<Burp>();foreach(var dish in dishes){

foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){

Burp burp;switch(foodItem.Kind){

case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;

case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;

default:throw new Exception(“Yuk!”);

}if(burp != null)

burps.Add(burp);}else

Environment.Spit(foodItem, bob);}

}Burp();

}

void Burp(){

foreach(var burp in _burps){Environment.Release(burp);

}

}

Step 2. Single responsibility

void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){

_burps = new List<Burp>();foreach(var dish in dishes){

foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){

Burp burp;switch(foodItem.Kind){

case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;

case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;

default:throw new Exception(“Yuk!”);

}if(burp != null)

_burps.Add(burp);}else{

Environment.Spit(foodItem, bob);}

}}

}

void Burp(){

foreach(var burp in _burps){Environment.Release(burp);

}

}

Responsibility demarcation

void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){

_burps = new List<Burp>();foreach(var dish in dishes){

foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){

Burp burp = ProcessFoodItem(foodItem, bob);if(burp != null)

_burps.Add(burp);else

Environment.Spit(foodItem, bob);}

}}Burp();

}

Burp ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {

Burp burp = null;switch(foodItem.Kind){

case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;

case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;

default:throw new Exception(“Yuk!”);

}return burp;

}

Step 3. Semantic regression

Code beacons

• Patterns in code• Sequences of imperative instructions• Describe how to compute and not computation itself• Denote hidden semantic intent

void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){

_burps = new List<Burp>();foreach(var dish in dishes){

foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){

Burp burp = ProcessFoodItem(foodItem, bob);if(burp != null)

_burps.Add(burp);else

Environment.Spit(foodItem, bob);}

}}Burp();

}

void Burp(){

foreach(var burp in _burps){Environment.Release(burp);

}}

Beacon

Beacon

Beacon

void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){

_burps = ProcessFood(dishes, bob);Burp();

}

List<Burp> ProcessFood(List<Dish> dishes, ImperativeGeek bob){

return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));

}

void Burp(){

foreach(var burp in _burps){Environment.Release(burp);

}}

Step 4. Controlled side-effects

void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){

_burps = ProcessFood(dishes, bob);Burp();

}

List<Burp> ProcessFood(List<Dish> dishes, ImperativeGeek bob){

return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));

}

void Burp(){

foreach(var burp in _burps){Environment.Release(burp);

}}

Mutable type

Mutable

type

Mutable type

void InsertNutritionalSubstance(IEnumerable<Dish> dishes, ImperativeGeek bob){

_burps = ProcessFood(dishes, bob);Burp();

}

IEnumerable<Burp> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){

return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));

}

void Burp(){

foreach(var burp in _burps){Environment.Release(burp);

}}

Step 6. Functional composition

void InsertNutritionalSubstance(IEnumerable<Dish> dishes, ImperativeGeek bob){

_burps = ProcessFood(dishes, bob);Burp();

}

IEnumerable<Burp> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){

return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));

}

void Burp(){

foreach(var burp in _burps){Environment.Release(burp);

}}

Non-compositional

void InsertNutritionalSubstance(IEnumerable<Dish> dishes, ImperativeGeek bob){

Burp(ProcessFood(dishes, bob));}

IEnumerable<Burp> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){

return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));

}

void Burp(IEnumerable<Burp> burps){

foreach(var burp in burps){Environment.Release(burp);

}}

Composition

Step 7. Computational abstraction

IEnumerable<Burp> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){

return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));

}

Burp ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {

Burp burp = null;switch(foodItem.Kind){

case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;

case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;

default:throw new Exception(“Yuk!”);

}return burp;

}

void Burp(IEnumerable<Burp> burps){

foreach(var burp in burps){Environment.Release(burp);

}}

Could be null

IEnumerable<Maybe<Burp>> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){

return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));

}

Maybe<Burp> ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {

Burp burp = null;switch(foodItem.Kind){

case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;

case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;

default:throw new Exception(“Yuk!”);

}return burp != null ? burp.ToMaybe() : Maybe<Burp>.Nothing;

}

void Burp(IEnumerable<<Maybe<Burp>> burps){

foreach(var burp in burps.Where(b => b.HasValue)){Environment.Release(burp);

}}

Step 8. Constrained state space

IEnumerable<Maybe<Burp>> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){

return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));

}

Maybe<Burp> ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {

Burp burp = null;switch(foodItem.Kind){

case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;

case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;

default:throw new Exception(“Yuk!”);

}return burp != null ? burp.ToMaybe() : Maybe<Burp>.Nothing;

}

∞ ∞

∞ ∞

IEnumerable<Maybe<Burp>> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){

Contract.Requires(dishes.Any());Contract.Requires(bob.IsHungry);Contract.Ensures(bob.IsFull);

return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));

}

Maybe<Burp> ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {

Contract.Requires(foodItem.ExpiryDate < DateTime.Now);Contract.Requires(foodItem.IsWarm);Contract.Requires(bob.IsHungry);

Burp burp = null;switch(foodItem.Kind){

case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;

case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;

default:throw new Exception(“Yuk!”);

}return burp != null ? burp.ToMaybe() : Maybe<Burp>.Nothing;

}

top related