Post

CS2103T Week 4 & 5

CS2103T Week 4 Topics

Design: Models

What are models

A model is a representation of something else, providing a simpler view of a complex entity as a model captures only a selected aspect. Implies models are abstractions.

A class diagram is a model that represents software design. It captures strucutre, but not behavior of the design.

Multiple models of the same entity may be needed to capture it fully.

Why Models

In software dev, models are useful to analyze a complex entity, to communicate information among stakeholders and as a blueprint for creating software.

UML Models

Unified Modeling Language (UML) is a graphical notation to describe various aspects of a software system. UML is the brainchild of three software modeling specialists James Rumbaugh, Grady Booch and Ivar Jacobson.

  • UML is currently the most commonly used modeling notation used in the software industry.

SequentialModel

Class Diagram Notation of different types of UML Diagrams

Class/Object Diagram Basics

UML Object Diagrams model object structures, UML Class Diagrams model class structures.

Modelling relevant objects ‘networked’ together inside a software present an OO (Object Orientated) solution.

  • Object structures within the same software can change over time.
  • Rules that object structures need to follow illustrated as a class structure.

UML Class Digrams

UML Class Diagrams describe structure (and not behavior) of an OOP solution. Possibly most used diagrams in industy, indispensable tool for an OO programmer.

classDiagram

Class Diagram Notations

The Operations/Methods compartment and Attributes compartment may be omitted if details not important. However, ‘Attributes’ always appear above ‘Operations’ copmartment.

Visibility of attributes and operations (public, private, protected, package private) used to indicate level of access allowed for each attribute or operation.

Generic classes also have special notation.

Class-Level Members

In UML class diagrams, underlines denote class-level attributes and methods.

Associations (represented by solid lines) are main connections among classes in a class diagram.

  • Associations in obj. structure can change over time.
  • Association among objects can be generalized as associations between the corresponding classes too.
  • Can be represented by a solid line, or shown as an attribute instead of a line. Either or, but not both.

Association Representation: Show additional decorations, such as labels, roles, multiplicity and navigability.

  • Labels describe meaning of association, with arrow head indicating direction label to be read. (e.g. Admin uses Student, Student used by Admin)
  • Role used to indicate role played by classes in the association. (E.g. Man, husband; Woman, wife.)
  • Navigability: Concept of which object in association knows about the other object. Can be uni/bidirectional. (Concept of which object has reference to which object) Use arrowheads to indicate navigability of an association. Can be shown in class and object diagrams.
  • Multiplicity: diciates how many objects take part in each association. (e.g. 0..1, 1, n..m, *). To implement n multiplicities e.g. use a suitable data structure such as Arrays, HashMap etc.

Object Diagrams

An object diagran shows an object structure at a given point of time. Object diagrams can complement class diagrams.

Object Diagram Notation

Object Diagram Notations

Note:

  • No compartment for methods, need underline, need colon
  • Can have no object name.

Similarly, for object diagrams:

  • Solid line indicates association.

Object vs. Class Diagrams

Object diagrams show objects instead of classes

  • Instance name may be shown, : before class name
  • Methods, Multiplicities omitted.
  • Multiple object diagrams can correspond to a single class diagram.
  • When class diagram has inheritance r/s, object diagram show either object as parent class, or as child class, not both. (e.g. show Jake:Employee, or Jake:Person, but not both.)
  • Association labels/roles can be omitted unless useful.

Class Digrams Intermediates

UML Notes

UML notes can augment UML diagrams with additional info. Shown connected to particular element with text, or not connected.

  • Constraint can be given inside a note, within curly braces.

Class Diagrams Intermediate Notation

Class Diagrams can also show different types of relationships between classes:

  • Inheritance
  • Composition, Aggregation
  • Dependencies

Inheritance: Allows defining new class based on existing class.

  • Use a hollow/filled triangle (don’t confuse with arrow) to indicate class inheritance.

Composition: Association that represents strong whole-part relationship. This implies, when whole is destroyed, parts must be destroyed too. No cyclical links. (E.g. a Email, EmailSubject ).

  • Common use of composition when parts of big class carved out as smaller classes.
  • Cascading deletion alone not sufficient for composition, must be integral part of larger class.
  • Identifying & keeping track of composition benefits by maintaining data integrity of system.
  • Use SOLID DIAMOND symbol to denote composition. Diamond is on the side of the whole in the (whole-part) relation.

Aggregation: Container-contained relationship, weaker than composition. (E.g. Club, Person).

  • Use a HOLLOW DIAMOND symbol to indicate aggregation. Diamon is on side of container in the (container-containee) relation.
  • Recommended not to use aggregation symbol as it is not as important as composition.

Dependencies: Need for one class to depend on another without having a direct association in the same direction.

  • Focus on non-obvious dependencies, if already has association, no point noting down. Association is r/s resulting from keeping reference to another object. Only use dependency arrow to indicate if not captured in other way (e.g. association, or inheritance)
  • One cause of dependency is interaction between objects that do not have a long-term link between them.
  • Use DASHED ARROW to show dependencies, with arrow pointing to the class that is depended on. E.g. A –> B, where A depends on B.

Other class-like Entities

Class diagram can show different tpyes of class-like entities.

Enumerations: Fixed set of values that can be considered as a data type.

  • Notation: «\enumeration»

Abstract Classes: Class that cannot be instantiated, but can be subclassed.

  • Notation: {abstract}, to denote classes/methods

Interfaces: Interface is a behavior specification.

  • Notation: «\interface»
  • When class implements interface, shown similar to class inheritance (triangle), except use dashed dotted line instead of solid line.

Association Class: Represents additional information about association. (E.g. Marriage class, Man, Woman). Can use to store data about an association.

  • No special way to implement class, implement normally.
  • Notation: dotted connection to association link.

Java: JavaFX

JavaFX is a technology for building Java-basded GUI (Graphic User Interface). Previously part of Java, now 3rd party dependency maintained by OpenJDK.

Tutorial Guide

Java: varargs

Varargs stands for Variable Arguments, syntatic sugar allowing writing a method that can take a variable number of arguments.

1
2
3
public static void search(String... keywords){
   // method body
}

Still true that multiple arguments must be passed in an array, but varargs feature automates and hides the process.

  • Only usable in final argument position.

Code Quality: Naming

Proper naming improves readability of code, reduces bugs from ambiguities regarding intent of variable or method.

  • Use nouns for things, verbs for actions. (E.g. class: LimitChecker instead of CheckLimit, Method: calculate(), instead of result().)
  • Distinguish clearly single-valued and multi-valued variables. (student, students)
  • Use standard words, correct spelling.
  • Use name to explain entity at sufficient LOD. (e.g. processInput() bad, removeWhiteSpaceFromInput() good. flag bad, isValidInput good.)
  • Names: not too long, not too short.
  • Avoid misleading names. (e.g. colorBlue as no. of times blue used, colorBlack as hex value)
  • Avoid ambiguous names. (e.g. rightDirection, instead of right)

Static Analysis

Static analysis of code finds useful information such as

  • Unused variables, unhandle exceptions
  • Style errors, statistics.

Static means code analyzed without executing code. Dynamic requires code execution (e.g. for performance characteristics). Higher-end static analysis tools can perfrom more complex analysis, e.g. locating potential bugs, memory leaks, inefficiency.

Linters are a subset of static analyzers aiming to locate areas where code can be made ‘cleaner’.

Code Reviews

Code review is the systematic examination of code with intention of finding where the code can be improved.

  • Pull Request Reviews
  • Pair Programming
  • Formal Inspections

Advantages include detecting functionality defects as well as other problems such as coding standard violations. Verify non-code artifacts (diagrams, etc.) and incomplete code. Does not require test drivers, stubs. However, manual process, error prone.

RCS: Managing Pull Requests I, II

Reviewing PRs

PR Review stage is a communication between PR author and members of repo that received the PR, to refine and merge the PR.

Steps to take:

  • Locate PR on github page, click on PR to review.
  • Read the PR decription.
  • Click on the +- files changed tab to see the diff. view.
  • Add review comments.
  • Submit the review.

Take note to follow guidelines when conducting the review.

Merging PRs

Once PR has been reviewed, refined and approved for merging, we can merge the PR.

Steps to take:

  1. Locate the PR in repo GitHub page.
  2. Click on the converstaion tab, to see PR status summary
  3. If not merge-able in current stage. This could be due to it being (out-od-date, merge conflicts etc.) Rectify accordingly, or post message for PR author to update the PR.
  4. Merge the PR by clicking on the merge pull request button.

Lastly, sync your local repos (and forks), since merging only modifies upstream remote repository. PR author needs to pull merged code from upstream repo to local repo, and push new code to respective forks to sync.

CS2103T Week 5 Topics

Requirements: Software Requirements Introduction

A software requirement is a need to be fulfilled by the software product. Requirements need to be gathered, analyzed, specified and managed.

  • Requirements come from stakeholders (E.g. users, sponsors, developers)
  • Identifying requirements often not easy. Communication not done correct, not willing to spend effort finding requirements.

Software project may be:

  • Brownfield: (Develop product to UPDATE existing software product)
  • Greenfield: (Develop totally NEW system from scratch).

Quality of Requirements:

Requirements as a whole should be consistent, non-redundant and complete. When defining requirements, they should specficially be

  • Unambiguous, Testable (verifiable)
  • Clear (concise, terse, simple, precise)
  • Correct, Understandable
  • Feasible (realistic, possible)
  • Independent, Atomic
  • Necessary, Implementation-free (i.e. abstract)

Prioritizing Requirements:

Requirements prioritized based on importance and urgency, keeping in mind constraints of schedule, budget, resources etc. One way is to group into priority categories, e.g. (Essential, Typical, Novel), (Must-have, Nice-to-have, Unlikely-to-have).

Some requirements can be discarded if they are considered ‘out of scope’.

Functional & Non-Functional Requirements

Functional requirements specify what the system should do.

Non-functional requirements specify what the system should do.

NFR Examples:

  • Data requirements (e.g. size, violatility)
  • Environment requirements
  • Accessibility, Capacity, Compilance with regulations, Documentation, Disaster recovery, Efficiency, Extensibility, Fault tolerance, Interoperability, Maintainability, Privacy, Portability, Quality, Reliability, Response time, Robustness, Scalability, Security, Stability, Testability, and more …

NFRs are easier to miss, as FRs are thought of first. Sometimes, NFRs are critical to the sucess of the software.

Requirements: Gathering

Several ways to gather Requirements:

  • Brainstorming: Group Activity to generate large number of diverse, creative ideas for solution of a problem. No ‘bad’ ideas, aim is to generate idea, not validate them.
  • Product Surveys: Study existing products to unearth shortcomings of existing solutions that can be addressed by a new product.
  • Observation: Observe users in their natural work environment to uncover pdt. requirements.
  • User Surveys: Solicit responses and opinions from a large number of stakeholders regarding current / new product.
  • Interviews: Stakeholders and domain experts can produce useful information.
  • Focus Groups: Informal interview within interactive group setting.
  • Prototyping: Mock up to get user’s feedbackm validate technical concept, give preview, do early field-testing. Can uncover requirements related to how users interact with system, usable in brainstorms, or user surveys.

Requirements: Specifying

Several ways to specify requirements for a project.

  • Textual description, aka PROSE: Useful when describing abstract ideas, such as vision of a product.
  • Feature Lists: List of features grouped according to some criteria such as aspect, priority etc.
  • User Stories: Short, simple descriptions of feature told from perspective of person who desires new capability. ( COMMON FORMAT: As User/Role XX, I CAN DO YY, Benefiting through ZZ). Additionally, {benefit} can be omitted if obvious.
    • Add characteristics to user roles to provide more context. (E.g. as a forgetful/expert user)
    • Write user stories at various levels. High-level called epics/themes cover bigger functionality.
    • Can add conditions of satisfaction: Things that need to be true to accept being done.
    • Usage: User Stories capture user requirements in a way convenient for scoping, estimation and scheduling.
    • Can capture NFRs as well.
  • Glossary: Glossary. Ensures all stakeholders have common understanding on noteworthy terms, abbreviations, acronyms.
  • Supplementary Requirements: Section used to capture requirements that do not fit elsewhere. Typically, NFRs Non-Functional Requirements listed here.

Code Quality

IMPORTANT!!

Code Quality: Readability

Among various dimensions of code quality, such as run-time efficiency, security, and robustness, one of the most important is readability.

  • Code needs to be read, understood, modifable.

Basic Implementation Guidelines:

  • **Avoid Long Methods: **Contain more info than read can process at a time, corrective action if beyond 30 LoC.
  • Avoid Deep Nesting: Deeper the nesting (indenting), the harder to keep track of logic. Avoid arrowhead style code.
  • Avoid Complicated Expressions: Esp. having many negations, and nested parentheses.

The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility, and among other things he avoids clever tricks like the plague. – Edsger Dijkstra

  • Avoid Magic Numbers: Magic numbers are unexplained numbers (E.g. 3.14236). Instead, use named constants, make easier to understand (E.g. static final double PI = 3.14236). Also makes it easier to modify. Applies to magic strings, magic booleans, magic literals. etc.
  • Make the code Obvious: Make code as explicit as possible. E.g. use explicit type conversion, use braces to show groupings, use enumerations where possible.
  • Structure Code Logically: Code should read like a story, use classes, methods, indentation, blank lines to group segments.
  • Do not ‘Trip Up’ reader: Avoid things that would make reader go ‘huh’? E.g. unused parameters, similar things looking different etc.
  • Practice ‘KISS’: Do not try to write ‘clever’ code. ‘Keep it Simple, Stupid’ KISS. Do not dismiss brute force, yet simple solution.
  • Avoid premature optimizations: May complicate code, may not even work, may be harder for compiler to optimize. Make it work, then make it right, then make it fast (in general).
  • SLAP hard: Single Level of Abstraction Principle. Avoid having multiple levels of abstraction within a code fragment.
  • Make the Happy Path Prominent: The happy path should be clear and prominent in your code. Restructure the code to make the happy path (i.e. the execution path taken when everything goes well) less-nested as much as possible. Use guard clauses.

Code Quality: Unsafe Practices

There are some error-prone shortcuts to avoid, it is safer to use language constructs in the way they are meant to be used.

Some guidelines to follow:

  • Case Statements: Always include a default branch, use it for the intended default option, not just to exe the last option. Also applies to final else of if-else construct.
  • Don’t recycle variables/parameters: Use one variable for one purpose.
  • Avoid empty catch blocks.
  • Delete dead code.
  • Minimize scope of variables: Minimize global variables, define variables in least possible scope.
  • Minimize code duplication: Especially copy-paste-modify code, often idicates poor quality implementation.

Code Quality: Code Commenting

Commenting your code does not necessarily increase ‘code quality’. Avoid writing comments to explain bad code. Improve the code to make it self explanatory.

Some Guidelines to follow:

  • Do not repeat the obvious
  • Write to the reader, not yourself.
  • Explain WHAT and WHY, not HOW: Explain specification of what code is supposed to do, so reader can compare and verify correctness. Add rationale of implementation. Do not give explanation of how code works, since it should be self-explanatory.

Refactoring

Refactoring: The process of improving a program’s internal structure in small steps without modifying its external behavior.

Refactoring is not rewriting, is not bug fixing.

  • Can make hidden bugs easier to spot.
  • May improve performance, simple code easier to optimize.
  • When refactoring, we should do regression testing after each change.

Common Refactorings:

  • Consolidate duplicate conditional fragments: (Move duplicates outside if else)
  • Extract Method: Turn fragments into method, whose name explains purpose of the method.
  • Combine Functions into Class
  • Decompose Conditional
  • Inline Method
  • Remove Double Negative
  • Replace Magic Literal
  • Replace Nested Conditional with Guard Clauses
  • Replace Parameter with Explicit Methods
  • Reverse Conditional
  • Split Loop
  • Split Temporary Variable

One way to identify refactoring opportunities is by code smells. Periodic refactoring is a good way to payy off technical debt a code base has accumulated.

Assertions

Assertions are used to define assumptions about the program state so that the runtime can verify them. An assertion failure indicates a possible bug in the code because the code has resulted in a program state that violates an assumption about how the code should behave.

If the runtime detects an assertion failure, it typically takes some drastic action such as terminating the execution with an error message. This is because an assertion failure indicates a possible bug and the sooner the execution stops, the safer it is.

1
2
3
x = getX();
assert x == 0 : "x should be 0";
...

Java disables assertions by default. To enable: java -enableassertions HelloWorld

Java assert vs JUnit assertions: Both check for a given condition but JUnit assertions are more powerful and customized for testing. In addition, JUnit assertions are not disabled by default. Use JUnit assertions in test code and Java assert in functional code.

It is recommended that assertions be used liberally in the code. Their impact on performance is low, and worth the additional safety they provide.

Do not use assertions to do work because assertions can be disabled. If not, your program will stop working when assertions are not enabled

Assertions are suitable for verifying assumptions about Internal Invariants, Control-Flow Invariants, Preconditions, Postconditions, and Class Invariants. Refer to Programming with Assertions (second half) to learn more.

Exceptions and assertions are two complementary ways of handling errors in software but they serve different purposes. Therefore, both assertions and exceptions should be used in code.

Java: streams

Java 8 introduced a number of new features (e.g. Lambdas, Streams) that are not trivial to learn but also extremely useful to know.

This post is licensed under CC BY 4.0 by the author.