From Domain Analysis to Domain Models to Object-oriented Designs to CodeHow do we take fuzzy requirements information (features, use-cases, sketches, domain analysis) and get to code?
- You can just start coding..
- But, most times the underlying logic needed in the app is so fuzzy that the initial code will be garbage
- Solution: make an initial object-oriented design to dig a little deeper.
- Domain analysis: understand your domain better (you should have done this in requirements).
- Domain modeling: use UML class diagrams to outline the key objects and relationships of the app
- Object-Oriented Design: the classes in your code and the relationships between then: refine the domain model UML more with coding in mind
- Code: use the object-oriented design to help in initial coding.
Initiating and refining designs
Domain modeling to get started
- A Domain model is a conceptual model of the underlying domain, not necessarily of the actual program.
- Our form of domain modeling is to make a UML class
diagram of the underlying domain
-- This means applying code process diagramming tools (UML) to real-world processes: seems strange but it works!
- Entity-relationship diagrams of databases are a similar diagram, but lack the ability to put actions (methods) in them
- Depending on the framework(s) used this diagram can be refined to an object-oriented design and serve as the initial classes/objects of the application.
Textual analysis to get started
This is a simple but effective way to come up with an initial list of classes / methods
- Look at your vision statement, feature list, and use-cases.
- Classes are the nouns (the things)
- Methods are the verbs.
Tangent: The UML class diagram widgets we will be usingLets look at some domain models expressed in UML.
- Classes: make sure to include relevant fields and methods in a class. Don't include a field if its already shown elsewhere in the diagram. Don't forget methods!
- Associations: all an association is is a line conecting two classes. Its that simple. If classes are interacting directly, put a line between them.
- Multiplicities: on an association, denote how many of each thing is interacting: 1, 2, 5, * (same as 0..*), 1..*, 2..*, etc
- Whole-part relationships on associations: use the diamond on associations to show the whole and parts. The filled-in diamond means "ownership".
- Inheritance: use the special inheritance arrow between classes, only for inheritance.
- Other: feel free to use other UML syntax. In particular naming associations can be helpful. But, its not required. Regular arrowheads on associations mean "accessibilty" - from one class you can get to another. They are often used but are not required.
- Think about an individual class' responsibilities; make any responsibility or action a class needs a method of the class (with an evocative name so you will remember what its supposed to do)
- Play out different storyboards / use-cases over the class diagram and make sure there is a class & method responsible for implementing each action in the use-case
- If two or more classes are similar but not quite the same, make an abstract superclass of them containing the shared functionality
- Refine your UML class diagram with appropriate notation to better understand relationships
- classes interacting with each other are placed nearby and are marked with a UML association edge
- think carefully about the multiplicity on the UML associations, they help add understanding.
- Think about "is-a" and "part-of" for inheritance and association edges respectively (the former adds open arrows, the latter adds the diamonds)
- Draw a class diagram showing only the classes involved in the part of the app you are focusing on. This helps reduce clutter.
- Focus on the core logic for your projects -- there isn't much interesting in all the UI classes for example, so there is probably no need to diagram them.
Evolving the requirements to a design
- Use-cases are a bridge from the more complex features to code: they are step-by-step operations
- Some requirements-level use-cases need refinement as the app comes more into focus
- Add new use cases based on a missed complex action needed in e.g. a UI
- Given improved UI sketches and classes, replay a use-case looking for missing steps
- Expand on individual use-case steps which clearly have more sub-steps in them
- Break out too-big steps into their own use cases
- Visualise in detail how the app is going to work; don't use fake placeholder names, draw potentially real data in the views.
- Make sure there is a UI associated with each feature or use-case activity
Component and Package Design
Terminology: packages, components, and deployment nodes.
- Packages aka Modules: Dividing software into packages is critical for larger software: complex software has larger logical groupings of code than classes.
- Components: a component has a run-time identity with an explicit run-time interface. For example if you are using a database, that is a separate component.
- Deployment node: the physical network setup for distributed applications. Components are often remotely deployed.
Start with the bigger picture: pull out logical modules to factor design from the top.
- You should have a vague idea of what libraries/frameworks you want to use already
- Refine that to a component/deployment structure of your application
- Within components, look for modular functionality groupings to make packages from
We will spend a good amount of time going over example initial designs, including some recent OOSE Project design documents.
PrototypingFor complex libraries/frameworks, prototype before integrating into your app
- Exercise the library with a small bit of code to make sure its doing what you need it to; then use it in your app
- Prototyping is also helpful for UIs, stand them up as dummies before hooking into app logic.
Project Iteration 2
The details of what you need to do for Iteration 2 will be discussed.