420 likes | 555 Views
Design Issues. Design to Code GUI design RDBMS design Performance Optimization. UML to code. Smalltalk class for each UML class Instance variable for each attribute Instance variables for each relationship possibly bidirectional possibly a collection. pet. owner. Person. Dog. pet.
E N D
Design Issues Design to Code GUI design RDBMS design Performance Optimization
UML to code • Smalltalk class for each UML class • Instance variable for each attribute • Instance variables for each relationship • possibly bidirectional • possibly a collection
pet owner Person Dog pet owner * Person Dog
Bidirectional relationships • Dog has ‘owner’, person has ‘pet’ • owner: aPerson • aPerson pet: self. • owner := aPerson • pet: anAnimal • pet := anAnimal owner: aPerson aPerson setPet: self. owner := aPerson setPet: anAnimal pet := anAnimal
One to many relationships • Instance variable holds a collection • Initialization creates empty collection • addPet:, removePet:, petDo:
The rest of UML • UML good at specifying easy stuff • classes, instance variables, accessing methods • UML not good at specifying hard stuff • algorithms • methods
How to build GUIs • 1) GUI first approach • Paint screen, build application model • Build domain model • 2) Domain model first approach • Build domain model and tests • Paint screen, build application model
Results • 1) GUI first approach • discover inputs and outputs • weak domain model, too much in application model • can be hard to test • 2) Domain model first approach • good, tested, domain model • changes needed when GUI added
How to build GUIs • Build the domain model first unless the application is focused on graphics • Counter examples: • The Incredible Machine • Drawing editor (HotDraw)
How to build DBMS interface • 1) DBMS first approach • design tables • build an application to talk to tables • 2) Domain model first approach • design application with no DBMS • make a good, tested, domain model • design tables and make objects read and write the database
Results • 1) DBMS first approach • good RDBMS design • unnatural object design, odd factoring • large systems get VERY complex • 2) Domain model first approach • good object design • unnatural RDBMS design
Modularizing DB access • 1) ApplicationModel knows how to read and write objects from database • 2) “Persistent objects” know how to write themselves to database, their class knows how to read them • 3) “Database access layer” knows which objects are persistent and how to read and write them.
Modularizing Database access • Two choices: • 1) Embed SQL in Smalltalk methods • 2) Describe tables and classes with “metadata” and generate SQL from them
Modularizing Database access • Embed SQL Metadata • ApplicationModel • Persistent Object • DB access layer Simple, unscalable Lens Do this! Hard to implement, most scalable Ugly, unscalable
Persistent Object • Implement “read”, “update” and “delete” operation as instance method. • Class knows its key. • Read a record by making an object with only its key filled in, then reading it. • Class methods for queries.
Persistent Object • VisualWorks has • EXDI - direct access to database, SQL • Object Lens - high layer access, hides SQL • “dbadg.pdf”
Kent Beck’s formula for fast software • Make it work. • Make it right. • Make it fast.
Make it work. (Analysis) 50% • Make it right. (Design) 35% • Make it fast. (Implementation) 15%
Facts of Life • C is 10 times faster than Smalltalk on small benchmarks. • Smalltalk business applications are as fast as C business applications.
Why is Smalltalk so fast? • Smalltalkers can spend more time on optimization. • Well-written Smalltalk programs are easy to optimize. • Most business programs are limited by network and database, not by CPU.
How to make fast software • Make your software correct and easy to understand. • Measure the performance of each part of your program. • Find bottlenecks. • (80% of the time is spent in 20% of the program) • Fix them.
Wrong way to make fast software • Choose most efficient language possible. • Make each line of code as efficient as possible. • Choose fastest algorithms possible.
How to measure performance • Profilers are in the parcel advanced/ATProfiler.pcl • Read “atug.pdf” • TimeProfiler profile: [3 + 4] • TimeProfiler openView
Profiling a Server • TimeProfiler • profile:[100 timesRepeat: • [| req | • req := WikiClientRequest new. • req • action: 'GET'; • ... • WikiServer current handleRequest: req]].
100.0 WikiServer>>handleRequest: • 100.0 Wiki>>replyToRequest: • 94.6 PageRendering>>renderBody • 78.3 PageRendering>>renderCommands • 61.7 WikiRendering>>linkTo:titled: • 34.2 WikiRendering>>putUrlForCommand: • 17.9 WikiRendering>>&= • 16.3 WikiRendering>>encodedPageTitle • 10.9 WikiRendering>>page • 10.9 Wiki>>pageTitled: • 5.4 CharacterArray>>asUppercase
WikiRendering>>page • page • ^wiki pageTitled: request identifier last • This method is called several times, so cache it. • Add an instance variable called “page”.
WikiRendering>>page • page • page isNil • ifTrue: [page := wiki pageTitled: • request identifier last]. • ^page • Reduced time from .31 seconds to .28 seconds.
Process of improving performance • Measure performance. • Make change. • Run tests, measure performance. • Undo changes if they don’t improve performance. • Repeat until performance is good enough.
Performance Strategy • Make performance targets • (e.g.<2 seconds) • Benchmark • Try out improvements • Only install ones that help • Stop when you reach your targets
Techniques • Better algorithms • Optimize low-level design • cache • simplify • reuse objects • inline objects and methods • Smalltalk specific
Cache • Store result in variable and reuse it instead of recomputing it. • Move expression out of loop. • Store method result in instance variable. • You must recompute the result when the values it depends on change.
Simplify • Instead of using powerful, easy to use objects, use simple and efficient ones. • Arrays instead of OrderedCollection • Symbol instead of String
Reuse objects • Creating and collecting objects can take a lot of time. • Use AllocationProfiler • 1) Keep a list of unused objects • 2) Change object rather than make new one • Make sure object is really unused!
Inline objects and methods • Lots of small methods can take time. • Replace messages in inner loops with the • bodies of the methods they call. • To eliminate access to an object’s instance variables, eliminate object and put its instance variables in the calling class. • This is ugly -- a step of last resort.
Smalltalk specific • Make collections of right sizes • Use streams to concatenate • Avoid blocks • Avoid reflective programming
Make Collections of Right Size • Many Collections grow: Set, Dictionary, OrderedCollection • Growing requires copying, which takes time. • Make Collections large enough that they don’t have to grow very often. • OrderedCollection new: 20
Use Streams to Concatenate • result := ‘’. • names do: [:each | result := result , each]. • result := WriteStream on: (String new: 50). • names do: [:each | result nextPutAll: each]. • result contents
Avoid Blocks • Blocks are used for • powerful control structures • parameterizing objects • Alternatives • in-line the algorithms • make subclasses
Inlining blocks • Compiler optimizes whileTrue:, to:do:, ifTrue: and does not create a block for them. • (1 to: 100) collect: [:each | each * each] • result := Array new: 100. • 1 to: 100 do: [:each | result at: each put: each * each]
Avoid Reflection • perform:, doesNotUnderstand: can make programs much smaller and eliminate coding work. • They are slower than a normal message send.
Scheduling • 60% - Functionality • 25% - Refactoring • 15% - Performance tuning • Good performance takes work, so schedule time for it.
Summary • Performance depends more on the programmer than on the programming language. • Functionality and good design are harder to achieve than good performance. • Don’t let your need for good performance prevent you from making a good design.