Java
An issue I ran into when using IntelliJ IDEA is not being able to view Java source code, declarations, and Javadocs. This can be resolved by going to your src
folder (i.e., where your source code is located). Right click, navigate and toggle: Mark Directory As > Sources Root (link).
Meaning of public
class?
A public class has “public” visibility which means that it is accessible to any class in any package. If a class does not have the public
access modifier, then it has “default” package visibility which means that it is accessible only to classes inside the same package.
What is transient
keyword?
The transient
keyword in Java is used to indicate that a field should not be part of the serialization. A transient
variable is not part of the persistent state of an object. For example, if you have fields that are derived from other fields (programatically) then we can mark them as transient
to prevent their state from being persisted during serialization. This helps save memory and increases speed of serialization / deserialization process. Say we have a GalleryImage
class that implements Serializable
. Among other instance variables / methods, assume this class contains two instance variables: image
and thumbnailImage
. The thumbnailImage
is derived from the gallery image
. Upon deserialization, the readObject
method is called to perform any operations necessary to restore the state of the object. In this example, the thumbnailImage
needs to be regenerated. Thus, we override the readObject
method do that the thumbnail will be generated by calling a generateThumbnail
method (link).
Software Design
What is Software Design?
- Software design helps us provide structure to an application
- Process of decomposing a system into smaller, modular parts
- Ideally, we want to design for change… in software it’s best to always anticipate change in requirements
- Because of constant change, we want to address maintainability during design
- ideally, we want ease of modification / adaptation
- reduction of maintainance
Change in Software
Change is distinguishing feature that makes software different from any other human produced artifact:
- Since the 1970’s, change in software is constant, urgent, and unavoidable. Mastering change is inevitable.
- Software technology has made progress but change is treated as an afterthought.
- Change has to become a first class concept
- development tools, runtime environment, and design process should naturally accomodate change
Two types of change: (1) Evolution and (2) Adaptation
Evolution: enhancing the software with new functions and features
Adaptation: retrofitting or improving the relevance of a software system in a new environment (e.g., building mobile versions of desktop apps, porting Windows based app to MacOS).
Change of Social Environment
- change is necessary due to external influence
- factors beyond the control of software organizations, clients, and users
- changes are often hard to anticipate and difficult to implement
- often, programmers have to respond to these changes under severe time pressure
Examples of types of changes:
- Replacing an existing algorithm by a more efficient one
- Change the data representation
- Porting code for new architecture
- different OS / arch may have different system calls, different DBMS calls
- Java strives to solve this problem via the JVM (“write once, run anywhere”)
- change in peripheral devices
- change of “sovial environment”
- new tax laws (for a tax software.. e.g., TurboTax)
- move of EU to common currency
- change in safety requirements (e.g., Boeing)
Modules
Module: a well defined component of a software system which may provide services to other modules
Properties of USES relationship
fan-in: number of incoming edges indicates the number of modules that use (or “depend”) on this module.
fan-out: number of outgoing edges indicates the number of modules this module depend on
Low fan-out / high fan-in is desirable because:
- this implies loose coupling (modules are not highly dependent on each other). Loose coupling increases maintainability, scalability, and reduces bugs
- implies that modules are a good abstraction
“Is Component of Of”
Mi IS_COMPONENT_OF
Mj: Mj consists of several modules of which one is Mi
“Comprises” Mj comprises Mi: means that Mi is a component encapsulated within Mj
“IMPORTED” module: other modules or services that a module needs to import in order to work
“EXPORTED” module: parts of the module others can use
Advantages of modular design
- reduces complexity by breaking problem down into sub-problems
- facilitates change, maintainability, and bug reduction by reducing surface area a module covers within an application.. less surface area = low coupling -> easier to make changes
- increases development speed by encouraging parallel development
- allows for code reuse
Properties of modular design
Principles:
- each module should address a specific subfunction of the requirements
- each module should have a simple and clean interface
Module independence measured using two criteria:
- Cohesion: degree to which a module focuses on a group of related functions
- Coupling: degree to which a module is connected to / depends on other modules
Good design = high cohesion and low coupling.
Product family: set of software intensive systems that share a common set of features.
- Design and implement core features just once
- Differences or variations are pushed down the stack (think of abstraction of functionality, parent child relationships, inheritance, and polymorphism)
OO Design
How to find / determine what should be a class?
Heuristic: classes correspond to nouns in the natural language decomposition of the problem.
Some nouns do not correspond to classes:
- items outside the problem boundary
- some nouns are just attributes (e.g., student id, birthday, student email)
- synonyms or words used to refer to a single concept
Tangible: physical objects or object groups that are tangible (e.g., Medication, Receipt, Prescription, Medical Record)
Roles: people who perform certain actions or have responsabilities or duties (e.g., Doctor, Nurse, Administrative assistant)
Events: things that can happen
Interactions between roles: e.g., exams, immunizations, diagnosis
Other systems: external events or systems with which the system interacts (e.g., credit card system, insurance system..)
Comparison between interface and the “tip of the iceberg”
- possible for a ship to avoid an iceberg simply by viewing the top
- possible for a client to use a module by knowing its interface
Symbol Table
get
: returns value
put
: store / update value
get
method should only return the value of the variable. It should not return the variable location (i.e., memory address). If memory address is returned, then user can access location directly and modify the value of the variable rather than doing it through the put
method.
Documentation should be structured top down:
- level of detail increases as one proceeds down
- big picture first, provide additional details as you drill down into specifics
Interface hides implementation details like:
- algorithm
- data structure
- external services integration
- policy
How does inheritance promote re-use?
- promotes re-use because child class inherits data & behaviour from the parent class
- code does not need to be re-written for the child
- child can refer to and use data + methods from parent
Conflict in inheritance (Extension or Restriction) ??? Extension:
- behaviour / data in a child class are an extension an extension of parent class
- child class has all properties of parent class and adds some more
Restriction View:
- child class is a more specialized (restricted) case of a parent
- contraction
Functional or procedural programming
- program divided into smaller parts functions
- start with a problem and break it down into smaller problems
- break down sub-problems continually in a process called functional decomposition
- continue until each sub-procedure is simple enough to be implemented in code
OOP
- program divided into small parts called objects (bottom up design approach)
- start with basic level of classes and build upon those classes
Composition
Describes “has a” relationship
Inheritance
Describes “is a” relationship
has-a | is-a |
---|---|
car has-a engine | dog is-a animal |
game has-a player | car is-a vehicle |
db has-a entry | employee is-a person |
university has-a student | orange is-a fruit |
playlist has-a song |
Advatages of composition over inheritance
-
Java does not support multiple inheritance. For reading and writing you can compose your class with
Reader
andWriter
. You cannot implement more than one interface. -
Easier testing. You can easily create a mock object and inject that as a dependency to test vs. having to implement and inherit super class.
-
Inheritance provides “tight coupling.” If parent changes, child may break (e.g., removal of class in parent that is used in child).
-
Flexibility. For example,
Comparator
can be passed toCollections.sort()
for custom sorting behaviour. This is convenient if you want to provide sorting behaviour other than default (see).
UML
”+” indicates field or method is public
”-“ indivate field or method is private
Understanding the Utility of Classes
- Inheritance and delegation facilitate re-use
We can breakdown the classes in a software application into these groups:
- Domain-independent (20%):
- provide functionality regardless of domain
- e.g., data structures, math functions, file IO, UI components
- Domain-specific (65%):
- functions that function specific to a domain
- e.g., inventory control (inventory of video tape rentals, auto parts)
- likely to be used in current and future projects
- Application-specific (15%):
- special purpose, classes that implement custom logic specific to application
“85% of code is reusable”: organizations should strive for domain-independent and domain-specific use
Composition (i.e., Containment)
- class spawns and contains instances of other classes within it
- “part-of” relationship
- if containing class is freed by garbage collector, then so are all of its composing actors / entities
Inheritance
- re-use of code from another class
- child inherits data + methods from parent (if accessibility is
public
orprotected
) - “is-a” relationship
Inheritance vs Composition
- with inheritance we focus on defining / implementing things based on what they are
- is “B” a kind of “A”? if yes -> use inheritance
- with composition we focus on defining / implementing things based on what they do
- does B have an A? if yes -> use composition
With inheritance we often face the gorilla banana problem.. which is when we only ask for a banana but we get a gorilla holding a banana with the entire jungle in the background. In other words, we get more than we ask for and make the code more bulky / convoluted. See this: watch
Class Relationships
- Association
- Aggregation
- Composition
Association
- objects of one class are associated with objects from another class
- a relationship where all objects have their own lifecycle and there is no owner
Aggregation
- more specific variant of aggregation
- “has-a” relationship
- superset class made up of components from subset classes
- no existence dependency between superset and subset classes (i.e., superset can be removed w/o needing to remove subset class)
Composition
- more specific variant of aggregation
- “part of” relationship
- object of a subset class cannot exist w/o being linked to an object of the superset class
- if we destroy a superset object, then we must delete the subset object as well
Aggregation vs Composition
Simple rules:
- A “owns” B = Composition : B has no meaning or purpose in the system without A
- A “uses” B = Aggregation : B exists independently (conceptually) from A
Example:
A Text Editor owns a Buffer (composition). A Text Editor uses a File (aggregation). When the Text Editor is closed, the Buffer is destroyed but the File itself is not destroyed.
-
Composition is an Association
-
Aggregation is an Association
-
Composition is a strong Association (If the life of contained object totally depends on the container object, it is called strong association)
-
Aggregation is a weak Association (If the life of contained object doesn’t depends on the container object, it is called weak association)
Good read: https://softwareengineering.stackexchange.com/questions/61376/aggregation-vs-composition
Also, difference between Inheritance vs Aggregation in Maven documentation: https://maven.apache.org/guides/introduction/introduction-to-the-pom.html#project-inheritance-vs-project-aggregation
When to use inheritance
- “is-a” test
- code reuse
Polymorphism / Dispatching
- Runtime or dynamic choice of the method to be invoked depending on the class of the invoking object
- polymorphism is based on inheritance.. parent child relationship is required
Polymorphism benefits
- offer versatility in hierarchy and code development
- makes code more generic and increases reuse
Principles of Substitutability
- If A is a subclass of B, instances of A can be substituted for instances of B in any situation without any observable effect
Subtype vs Subclass
- A is a subclass of B merely asserts that A is formed using inheritance
- refers to a general inheritance relationship that may or may not satisfy the substitutability principle
- A is a subtype of B means A preserves the meaning of all operations in B
- refers to an inheritance relationship that satisfies the substitutability principle
- good reads here and the course directory here
Overiding
- child class overides a method in the parent class (i.e., child class provides new implementation for method inherited from parent)
- overridden method has same name and type signature as the parent class, but changed implementation
Specialization Inheritance
- each child class preserves the behaviour of the parent
- may add more functions / data
- preserves substitutability
Specification Inheritance
- all child classes implement the methods defined in the parent
- more specific version of specialization inheritance
- preserves substitutability
Construction Inheritance
- parent class is used as a source of behaviour
- child class has no “is-a” relationship to the parent
- child class may modify arguments
- may not preserve the behaviour of the parent
- violates substitutability
Generalization
- adds new features reutnrs existing ones
- preserves
Limitation
- child class overrides a method inherited from a parent in a way that makes it unusable or limits certain functions
- e.g., list data type that allows items to be inserted at either end
- e.g., limit by allowing insertion only at one end to create a stack
- violates
Variance
- Two or more classes that seem to be related but not clear which is child and which is parent
- May or may not preserve substitutability principle
Correctness vs Reliability
- Reliability encompasses correctness
When is a software system: correct yet unreliable or reliable yet incorrect
- requirements may not be well understood or an accurate representation of what the user wants
- requirments may not be known to user.. if this is the case, then software builds for these incorrect reqs will never behave as expected to the user -> not reliable from the user’s perspective
- software system may perform critical functions w/o failure but may be able to tolerate some flaws in non-critical functions
- system is incorrect yet reliable
Robustness vs. Application Domain
- How a particular unforeseen circumstance can occur will depend on the application domain
- if software is developed for users who are not conversant with tech, application must be prepared to accept ill-formatted or incorrect inputs
- embedded systems never use input from users, but interface with sensors and may need to handle sensor and hardware failure
- amt. of code dedicated to handling errors depends on domain and consequences of failures
Relationship between requirements, correctness, reliability, and robustness
- if requirements are specified then ensuring is a matter of correctness / reliability
- if requirements are not specified then it is a matter of robustness
Three levels of interoperability
- Minimum: multiple applications must coexist on the same machine
- Medium: one application must be able to embed or import data from another application (e.g., import powerpoint into google slides)
- Maximum: software sytem must interface and exchange data with other systems
How reusability affects reliability
- as more components are reused they are more likely to become reliabled since residual errors are progressively eliminated
- reliability of components improves leading to an improvement in sys. reliability
- components may also behave in unexpected ways which would lead to lower component and system reliability
Real-time system
- correct answer generated within a specified time delta
- tradeoff precision for timeliness
- performance is most important
Information system
- e.g., payroll system
- live much longer than originally planned
- adapted to new environments, enhanced with new features
- maintainability
UI and reliability
- well designed UI can direct a user through the sequence of necesarry steps to complete a task
- bad UI may cause a user to try alternate things and crash the app
SWE - Software Engineering Principles
What is a principle?
Abstract high level statements that must be followed.
Why are principles needed?
They become practice through methods and techniques.
Modularity is the cornerstone principle supporting software design
Seven important principles that may be used in all phases of software development
(Tools) -> (Methodologies) -> (Methods and Techniques) -> (Principles)
Key principles:
- Rigor and formality
- Separation of concerns
- Modularity
- Abstraction
- Anticipation of change
- Generality
- Incrementality
SWE - Software Specification - Entity Relationship Diagrams (ERD)
Overview:
- Based on entities, relationships, and attributes
- Used for modeling a system’s data, it’s flow, and how it’s related
What is the difference between UML
and ERD
?
Key Difference: UML
stands for Unified Modeling Language. ERD
stands for Entity Relationship Diagram. UML
is a popular and standardized modeling language that is primarily used for modeling object oriented software. Entity-Relationship diagrams are used in structured analysis and conceptual database modeling (source).
For data modeling (relational databases) we use ERD diagram, for storing data in object systems we can use ORM (object relational model – it is a mixed UML/Data model), for modeling object oriented systems we use UML.
Data objects (Entities)
A person place or thing to be represented in the system. E.g.:
- person
- event
- organizational unit (e.g., university)
Entity Type: definition for an entity. E.g.: Employee(ID, Name, SSN, Birthdate)
Entity Instance: concrete instance of an entity type. E.g.: (1234, John Smith,2345423345, 08/31/1972)
Similar concept to class and object in OOP.
Entities are represented by rectangles.
Weak entities: entity which cannot exist without the existence of some other (think composition in OOP) (e.g., concept of Employee and Dependent – one does not exist without the other)
Attributes
Define property of an entity. Represented by an oval attached to an entity.
Attribute examples: employee name, id, ssn, birthdate.
Identifier attribute: a “key” is an attribute that uniquely identifies the entity it is attached to
There exist single value attributes (e.g., “Name”) and multi value attributes (e.g., “Skills”)
Relationships
Logical association between two entities. Relationships are represented by diamonds. Examples:
- Bookstore orders Book
- Bookstore sells Book
- Bookstore buys Book
- Student enrolls in Course
Cardinality:
- one to one relationship (1:1) (e.g., Course - Instructor)
- one to many (1:N) (e.g., Insructor - Student)
- many to many (M:N) (e.g., Course - Student)
Modality:
0
: relationship is optional1
: relationshop is mandatory
Modality & Cardinality denoted as: (min, max)
min
= modalitymax
= cardinality
Effective Java
[Item 11] Always override hashCode
when you override equals
When you invoke get(Object key)
method from Java’s Map
interface (as well as various other collections methods), Java uses the generated hashCode
to know what bucket to look into. Once it knows that bucket to look into, it searches for the element using equals
. So, if two objects are equal (as defined by the overrided equals
method), then their hashcodes must be equal as well. Otherwise, Java will not look into the correct bucket.
Bottom line: some collections, like HashSet
, HashMap
or HashTable
use hashCode
to store its data and to retrieve it. If you don’t implement hashcode()
and equals()
in a consistent manner, then they will not function properly.
In Java, String
class already overrides equals
and hashCode
method such that two Strings
which are equal to each other also yield the same hashCode
. Because of this, you get expected functionality when you use String
as a key in a HashMap
. If String
did not override equals
and hashCode
then the following would not work:
1
2
3
4
5
6
HashMap<String, Integer> map = new HashMap<String, Integer>();
String a = new String("foo");
String b = new String("foo");
map.put(new String("foo"), 4);
map.put("bar", 7);
map.containsKey(new String("foo")); // false
This would not work because even though we expect that a
equals b
(because they both contain “foo”) applying equals
would not return true
unless we implement it to follow this business logic. Moreover hashCode
would return different numbers for a
and b
beacause, by default, in Java hashCode
is based of memory address. Due to this, Java would end up looking for a
and b
in different buckets. Luckily, this does not happen with Java String
because it overrides equals
and hashCode
to behave like how we expect (namely, two String
s have same hashCode
if they are equal)
Additional References:
- https://stackoverflow.com/questions/2265503/why-do-i-need-to-override-the-equals-and-hashcode-methods-in-java
- https://stackoverflow.com/questions/14608683/java-what-happens-if-hashcode-is-not-overriden