SlideShare a Scribd company logo
1 of 86
LENSES FOR
THE MASSES
…introducin
g Goggles
@KenScambler
λ
FP badly needs
optics
1
class Pos {
var x: Int = _
var y: Int = _
}
class Entity {
var pos: Pos = _
var embubbled: Boolean = _
}
class Game {
var player1, player2: Entity = _
var monsters: ListBuffer[Entity] = _
var bubbles: ListBuffer[Bubble] = _
var score: Int = _
}
game.player1.pos.x
208
game.player1.pos.x += 10
218
“Assignment… leads us into a
thicket of difficult conceptual
issues.”
Ch. 3.1.2
“Nevertheless… it is a powerful
technique for maintaining a
modular design.”
Ch. 3.1.2
• Tracks state over time
• Local change instantly
propagates without external
knowledge or orchestration
• Efficient
• Can’t reason locally
• Can’t substitute expressions
with result
• Spooky action at a distance
• Disadvantages are infectious
• Forget about concurrency
• Hard to isolate things for
testing
• Can’t fit behaviour patterns in
your head
GOOD BAD
Mutable?
case class Pos(x: Int, y: Int)
sealed trait Entity { def pos: Pos }
case class Monster(pos: Pos, embubbled: Boolean)
extends Entity
case class Player(pos: Pos, lives: Int)
extends Entity
case class Bubble(pos: Pos) extends Entity
case class Game(
player1: Player,
player2: Option[Player]
monsters: List[Monster],
bubbles: List[Bubble],
score: Int)
game.player.pos.x
208
game.copy(player =
game.player.copy(pos =
game.player.pos.copy(x =
game.player.pos.x + 10
)
)
)
218
• Referential transparency
• Local reasoning
• Equational reasoning
• Easily testable
• Need to manually orchestrate
position
• Need to know path
information within world
• Need to know how to recreate
in the world
• Need to write a lot of stuff
• Repetitive, hard to read
• Inefficient
Immutable?
GOOD BAD
Apparently it is terrible at a bunch of
common problems
😳
FP is supposed to be all about modularity!
set: S  A  S
get: S  A
LENS
(X,Y)
e => e.pos
e => p => e.copy(pos = p)
LENS
pos
(X,Y)
p => x
p => x2 => p.copy(x = x2)
LENS
Int
x
(X,Y)
LENS
Int
pos x
LENS
Int
posX
208
(playerL ∘ posL ∘ xL).get(game)
218
(playerL ∘ posL ∘ xL).modify(game)(_ + 10)
setBack: A  S
maybeGet: S  S | A
PRISM
{
case m: Player => Right(m)
case e => Left(e)
}
PRISM
asPlayer
TRAVERSAL
ISO
monsters each
Lens Traversal
embubbled
Bool
Lens
Traversal
monstersEmbubblement
Bool
(monsters ∘ each ∘ embubbled).getList(game)
false
true
false false
falsefalse
false
Iso
Lens
(X,Y)
×1
×1
Prism
×0-1
Traversal
×0-n
Optics libraries are
too hard to learn
2
data Player = Player { _playerPos :: Pos
, _lives :: Int }
data Pos = Pos { _x :: Int, _y :: Int }
data Monster = Monster { _monsterPos :: Pos
, _embubbled :: Bool }
data Bubble = Bubble { _bubblePos :: Pos }
data Game = Game
{ _player1 :: Player
, _monsters :: [Monster]
, _bubbles :: [Bubble]
, _score :: Int
}
makeLenses ''Player
makeLenses ''Pos
makeLenses ''Monster
makeLenses ''Bubble
makeLenses ''Game
import Control.Lens
g = Game (Player (Pos 33 22) 3)
[ Monster (Pos 1 2) True
, Monster (Pos 44 102) False
, Monster (Pos 33 88) False
] [] 1000
view monsters g

Lens
(1,2) (33,88)(44,102)
import Control.Lens
g = Game (Player (Pos 33 22) 3)
[ Monster (Pos 1 2) True
, Monster (Pos 44 102) False
, Monster (Pos 33 88) False
] [] 1000
toListOf (monsters.each) g

Traversal
(1,2) (33,88)(44,102)
import Control.Lens
g = Game (Player (Pos 33 22) 3)
[ Monster (Pos 1 2) True
, Monster (Pos 44 102) False
, Monster (Pos 33 88) False
] [] 1000
toListOf
(monsters.each.monsterPos) g

Traversal
(1,2) (44,102) (33,88)
import Control.Lens
g = Game (Player (Pos 33 22) 3)
[ Monster (Pos 1 2) True
, Monster (Pos 44 102) False
, Monster (Pos 33 88) False
] [] 1000
toListOf
(monsters.each.monsterPos.x) g

Traversal
1, 44, 33
import Control.Lens
g = Game (Player (Pos 33 22) 3)
[ Monster (Pos 1 2) True
, Monster (Pos 44 102) False
, Monster (Pos 33 88) False
] [] 1000
set
(monsters.each.monsterPos.x)
11 g

(11,2) (11,88)(11,102)
import Control.Lens
g = Game (Player (Pos 33 22) 3)
[ Monster (Pos 1 2) True
, Monster (Pos 44 102) False
, Monster (Pos 33 88) False
] [] 1000
over
(monsters.each.monsterPos.x)
(+1) g

(2,2) (34,88)(45,102)
import Control.Lens
g = Game (Player (Pos 33 22) 3)
[ Monster (Pos 1 2) True
, Monster (Pos 44 102) False
, Monster (Pos 33 88) False
] [] 1000
monsters.each.monsterPos.x .~ 11
$ g

(11,2) (11,88)(11,102)
import Control.Lens
g = Game (Player (Pos 33 22) 3)
[ Monster (Pos 1 2) True
, Monster (Pos 44 102) False
, Monster (Pos 33 88) False
] [] 1000
monsters.each.monsterPos.x %~ (+1)
$ g

(2,2) (34,88)(45,102)
class (
Choice p,
Corepresentable p,
Comonad (Corep p),
Traversable (Corep p),
Strong p,
Representable p,
Monad (Rep p),
MonadFix (Rep p),
Distributive (Rep p),
Costrong p,
ArrowLoop p,
ArrowApply p,
ArrowChoice p,
Closed p) => Conjoined p where ...
Boring problems demand boring
solutions!
Easy solutions are
too limited
3
(def users [{:name "Linda" :age 30}
{:name "Tom" :age 20}])
(get-in users [0 :name])
”Linda”
(update-in users [1 :age] + 1)
 [{:name ”Linda" :age 30}
{:name ”Tom" :age 21}]
(assoc-in users [1 :name] "Sparkles")
 [{:name ”Linda" :age 30}
{:name ”Sparkles" :age 20}])
[{"name": "Linda", "age": 30},
{"name": "Tom", "age": 20}]
.[0].name
“Linda”
.[].age += 1
 [{"name": "Linda", "age": 31},
{"name": "Tom", "age": 21}]
.[1].name |= "Sparkles”
 [{"name": "Linda", "age": 30},
{"name": ”Sparkles", "age": 20}]
<people>
<person>
<name>Linda</name>
<age>30</age>
</person
<person>
<name>Tom</name>
<age>20</age>
</person>
</people>
/people/person[1]/name
 <name>Linda</name>
/people/person/age
 <age>30</age>
<age>20</age>
[1,2,3]*.multiply(2)
[2,4,6]
grocery?.shelf?.box?.bananas
grocery?.shelf?.box?.bananas
grocery?.shelf?.box?.bananas
grocery?.shelf?.box?.bananas
Solutions that cut
corners don’t scale.
Best of both
worlds?
4
class Lens[S,A]
class Traversal[S,A]
class Prism[S,A]
class Iso[S,A]
class Fold[S,A]
class Getter[S,A]
class Setter[S,A]
class Optional[S,A]
import monocle.macros.GenLens
case class Pos(x: Int, y: Int)
object Pos {
val x: Lens[Pos,Int] = GenLens[Pos](_.x)
val y: Lens[Pos,Int] = GenLens[Pos](_.y)
}
import monocle.macros.Lenses
@Lenses
case class Pos(x: Int, y: Int)
@Lenses
case class Monster(pos: Pos,
embubbled: Boolean)
// in build.sbt
addCompilerPlugin(
"org.scalamacros" %% "paradise" %
"2.1.0" cross CrossVersion.full)
Game.monsters.composeTraversal(each).
composeLens(Monster.pos).
composeLens(Pos.x).set(11)(g)

(11,2) (11,88)(11,102)
Goggles
https://github.com/kenbot/goggles
Goggles principles
• You already know how to use it
• Gets out of the way of experts
• Fabulous first-class error messages
Goggles syntax
import goggles._
get"$g.monsters[1].embubbled”
set"$g.monsters*.pos.x" := 55555
set"$g.player2?.lives" ~= (_ + 3)
val g: Game
val posL: Lens[Monster, Pos]
get"${g}.monsters*.${posL}.x"
${game}
".monsters*."
${posL}
".x"
Macro
ERROR
{
or
…
}
Mode = GET
""
".monsters*." ".x"
Hole Name(monsters) Each Hole Name(x)
List[String]
AST
""
trait Parse[T, Arg, A] {
def apply(state: ParseState[T,Arg]):
(Either[GogglesError[T],A],
ParseState[T,Arg])
}
Interpreter monad
(List[Arg], List[Info])
(Either[Error,A], List[Arg], List[Info])
Interpreter monad
${game} ${posL}Args:
Info:
AST:
Tree:
Hole Name(monsters) Each Hole Name(x)
${game}
${posL}Args:
Info:
AST:
Hole
Tree:
”$game", Unit, Game, Iso, Iso
const(game)
Name(monsters) Each Hole Name(x)
Info:
AST:
Tree:
”$game", Unit, Game, Iso, Iso
const(game).composeGetter(Getter(_.monsters))
".monsters", Game, List[Monster], Getter, Getter
${posL}Args:
Name(monsters)
Each Hole Name(x)
Info:
AST:
Each
Hole Name(x)
Tree:
”$game", Unit, Game, Iso, Iso
const(game).composeGetter(Getter(_.monsters))
.composeTraversal(Each.each)
".monsters", Game, List[Monster], Getter, Getter
"*", List[Monster], ??????, Traversal, Fold
${posL}Args:
How to learn the type of values?
Info:
AST:
Each
Hole Name(x)
Tree:
”$game", Unit, Game, Iso, Iso
const(game).composeGetter(Getter(_.monsters))
.composeTraversal(Each.each)
".monsters", Game, List[Monster], Getter, Getter
"*", List[Monster], Monster, Traversal, Fold
${posL}Args:
typecheck(
q"implicitly[
_root_.monocle.function.
Each[List[Monster], _]]")
Typechecking will fill it in for us
Info:
AST:
Each
Hole Name(x)
Tree:
”$game", Unit, Game, Iso, Iso
const(game).composeGetter(Getter(_.monsters))
.composeTraversal(Each.each)
".monsters", Game, List[Monster], Getter, Getter
"*", List[Monster], Monster, Traversal, Fold
${posL}Args:
Got it!
${posL}
Args:
Info:
AST:
Hole
Name(x)
Tree:
”$game", Unit, Game, Iso, Iso
const(game).composeGetter(Getter(_.monsters))
.composeTraversal(Each.each)
.composeLens(posL)
".monsters", Game, List[Monster], Getter, Getter
"*", List[Monster], Monster, Traversal, Fold
”$posL", Monster, Pos, Lens, Fold
Info:
AST:
Name(x)
Tree:
”$game", Unit, Game, Iso, Iso
const(game).composeGetter(Getter(_.monsters))
.composeTraversal(Each.each)
.composeLens(posL)
.composeGetter(Getter(_.x))
".monsters", Game, List[Monster], Getter, Getter
"*", List[Monster], Monster, Traversal, Fold
”$posL", Monster, Pos, Lens, Fold
".x", Pos, Int, Getter, Fold
Info:
Error: NameNotFound("BLAH", Int)
”$game", Unit, Game, Iso, Iso
".monsters", Game, List[Monster], Getter, Getter
"*", List[Monster], Monster, Traversal, Fold
”$posL", Monster, Pos, Lens, Fold
".x", Pos, Int, Getter, Fold
get”$g.monsters*.$posL.x.BLAH"
The future…?
5
Optics are here to
stay!
• Benefits of immutability
• Benefits of mutation
• Vast abstractive power
Optics are here to
stay!
• Built-in support is really needed for good usability
• Future languages will have built-in optics
• Perhaps Goggles can help inform this process!
Watch this space!

More Related Content

What's hot

PyCon2009_AI_Alt
PyCon2009_AI_AltPyCon2009_AI_Alt
PyCon2009_AI_Alt
Hiroshi Ono
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
MongoSF
 

What's hot (20)

The Ring programming language version 1.5.3 book - Part 62 of 184
The Ring programming language version 1.5.3 book - Part 62 of 184The Ring programming language version 1.5.3 book - Part 62 of 184
The Ring programming language version 1.5.3 book - Part 62 of 184
 
The Ring programming language version 1.3 book - Part 52 of 88
The Ring programming language version 1.3 book - Part 52 of 88The Ring programming language version 1.3 book - Part 52 of 88
The Ring programming language version 1.3 book - Part 52 of 88
 
The Ring programming language version 1.10 book - Part 70 of 212
The Ring programming language version 1.10 book - Part 70 of 212The Ring programming language version 1.10 book - Part 70 of 212
The Ring programming language version 1.10 book - Part 70 of 212
 
Corona sdk
Corona sdkCorona sdk
Corona sdk
 
Intro22
Intro22Intro22
Intro22
 
"Java Concurrency Stress tests Tool" at IT Tage 2017 by Vadym Kazulkin/Rodion...
"Java Concurrency Stress tests Tool" at IT Tage 2017 by Vadym Kazulkin/Rodion..."Java Concurrency Stress tests Tool" at IT Tage 2017 by Vadym Kazulkin/Rodion...
"Java Concurrency Stress tests Tool" at IT Tage 2017 by Vadym Kazulkin/Rodion...
 
The Ring programming language version 1.3 book - Part 42 of 88
The Ring programming language version 1.3 book - Part 42 of 88The Ring programming language version 1.3 book - Part 42 of 88
The Ring programming language version 1.3 book - Part 42 of 88
 
Intro22
Intro22Intro22
Intro22
 
The Ring programming language version 1.5.4 book - Part 60 of 185
The Ring programming language version 1.5.4 book - Part 60 of 185The Ring programming language version 1.5.4 book - Part 60 of 185
The Ring programming language version 1.5.4 book - Part 60 of 185
 
PyCon2009_AI_Alt
PyCon2009_AI_AltPyCon2009_AI_Alt
PyCon2009_AI_Alt
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
 
Utility Classes Are Killing Us
Utility Classes Are Killing UsUtility Classes Are Killing Us
Utility Classes Are Killing Us
 
TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用TensorFlow 深度學習快速上手班--電腦視覺應用
TensorFlow 深度學習快速上手班--電腦視覺應用
 
PythonOOP
PythonOOPPythonOOP
PythonOOP
 
The Ring programming language version 1.5.2 book - Part 66 of 181
The Ring programming language version 1.5.2 book - Part 66 of 181The Ring programming language version 1.5.2 book - Part 66 of 181
The Ring programming language version 1.5.2 book - Part 66 of 181
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
 
Cocos2dx 7.1-7.2
Cocos2dx 7.1-7.2Cocos2dx 7.1-7.2
Cocos2dx 7.1-7.2
 
The Ring programming language version 1.5.1 book - Part 49 of 180
The Ring programming language version 1.5.1 book - Part 49 of 180The Ring programming language version 1.5.1 book - Part 49 of 180
The Ring programming language version 1.5.1 book - Part 49 of 180
 
The Ring programming language version 1.8 book - Part 57 of 202
The Ring programming language version 1.8 book - Part 57 of 202The Ring programming language version 1.8 book - Part 57 of 202
The Ring programming language version 1.8 book - Part 57 of 202
 
TensorFlow Tutorial
TensorFlow TutorialTensorFlow Tutorial
TensorFlow Tutorial
 

Similar to Lenses for the masses - introducing Goggles

Thinking Functionally In Ruby
Thinking Functionally In RubyThinking Functionally In Ruby
Thinking Functionally In Ruby
Ross Lawley
 
Introduction to Gremlin
Introduction to GremlinIntroduction to Gremlin
Introduction to Gremlin
Max De Marzi
 

Similar to Lenses for the masses - introducing Goggles (20)

present_2_new
present_2_newpresent_2_new
present_2_new
 
Provenance Games
Provenance GamesProvenance Games
Provenance Games
 
Gems of GameplayKit. UA Mobile 2017.
Gems of GameplayKit. UA Mobile 2017.Gems of GameplayKit. UA Mobile 2017.
Gems of GameplayKit. UA Mobile 2017.
 
여자개발자모임터 6주년 개발 세미나 - Scala Language
여자개발자모임터 6주년 개발 세미나 - Scala Language여자개발자모임터 6주년 개발 세미나 - Scala Language
여자개발자모임터 6주년 개발 세미나 - Scala Language
 
Stefan Kanev: Clojure, ClojureScript and Why They're Awesome at I T.A.K.E. Un...
Stefan Kanev: Clojure, ClojureScript and Why They're Awesome at I T.A.K.E. Un...Stefan Kanev: Clojure, ClojureScript and Why They're Awesome at I T.A.K.E. Un...
Stefan Kanev: Clojure, ClojureScript and Why They're Awesome at I T.A.K.E. Un...
 
Thinking Functionally In Ruby
Thinking Functionally In RubyThinking Functionally In Ruby
Thinking Functionally In Ruby
 
Start Writing Groovy
Start Writing GroovyStart Writing Groovy
Start Writing Groovy
 
Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語
 
The Ring programming language version 1.7 book - Part 53 of 196
The Ring programming language version 1.7 book - Part 53 of 196The Ring programming language version 1.7 book - Part 53 of 196
The Ring programming language version 1.7 book - Part 53 of 196
 
The Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsThe Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 Seasons
 
0.0. punto fijo
0.0. punto fijo0.0. punto fijo
0.0. punto fijo
 
The Ring programming language version 1.10 book - Part 71 of 212
The Ring programming language version 1.10 book - Part 71 of 212The Ring programming language version 1.10 book - Part 71 of 212
The Ring programming language version 1.10 book - Part 71 of 212
 
The Ring programming language version 1.10 book - Part 64 of 212
The Ring programming language version 1.10 book - Part 64 of 212The Ring programming language version 1.10 book - Part 64 of 212
The Ring programming language version 1.10 book - Part 64 of 212
 
Machine Learning Introduction
Machine Learning IntroductionMachine Learning Introduction
Machine Learning Introduction
 
The Ring programming language version 1.7 book - Part 64 of 196
The Ring programming language version 1.7 book - Part 64 of 196The Ring programming language version 1.7 book - Part 64 of 196
The Ring programming language version 1.7 book - Part 64 of 196
 
Introduction to Gremlin
Introduction to GremlinIntroduction to Gremlin
Introduction to Gremlin
 
関数プログラミングことはじめ revival
関数プログラミングことはじめ revival関数プログラミングことはじめ revival
関数プログラミングことはじめ revival
 
Game playing
Game playingGame playing
Game playing
 
Scala kansai summit-2016
Scala kansai summit-2016Scala kansai summit-2016
Scala kansai summit-2016
 
Python Puzzlers
Python PuzzlersPython Puzzlers
Python Puzzlers
 

More from kenbot

More from kenbot (12)

Grow your own tech leads
Grow your own tech leadsGrow your own tech leads
Grow your own tech leads
 
Applied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionalityApplied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionality
 
Responsible DI: Ditch the Frameworks
Responsible DI: Ditch the FrameworksResponsible DI: Ditch the Frameworks
Responsible DI: Ditch the Frameworks
 
FP adoption at REA
FP adoption at REAFP adoption at REA
FP adoption at REA
 
Good functional programming is good programming
Good functional programming is good programmingGood functional programming is good programming
Good functional programming is good programming
 
Data made out of functions
Data made out of functionsData made out of functions
Data made out of functions
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mocks
 
2 Years of Real World FP at REA
2 Years of Real World FP at REA2 Years of Real World FP at REA
2 Years of Real World FP at REA
 
Your data structures are made of maths!
Your data structures are made of maths!Your data structures are made of maths!
Your data structures are made of maths!
 
Category theory for beginners
Category theory for beginnersCategory theory for beginners
Category theory for beginners
 
The disaster of mutable state
The disaster of mutable stateThe disaster of mutable state
The disaster of mutable state
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monads
 

Recently uploaded

%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 

Recently uploaded (20)

call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 

Lenses for the masses - introducing Goggles