Requirements gathering:
	Main objectives:
		1) Understand the problem
		2) Understand how software is supposed to solve that problem
	Asking questions to aim discussion and to build your understanding
	Observe current process / workflows
	Determine common usage scenarios / stories
	Use active listening
Problem solving:
	How to facilitate a brainstorming session
		* Enumerate possible solutions (no critiquing or arguing in this stage)
		* Jot down ideas for everyone to see, as they are generated.
		* When things slow down, identify the good qualities of various ideas that were proposed
		* Narrow it down to one or two possible plans of action
Requirements document (mainly consider the system as a black box in the context of the problem domain):
	Entities and attributes
	Relations, cardinalities, and entity-relation diagrams
	Events and sequence
	Queries and notifications
System specification:
	What the system will look like
	How it will behave in response to input (users / sensors / other software)
	Operating procedures
Prototyping
User interface design:
	* Consistency (within the application and with similar applications)
	* Provide easy navigation (logical hierarchy: navigating menus or tools for more options; multiple ways to carry out an action where it's natural to do so)
	* Provide informative feedback (e.g. password strength)
	* Design workflows to yield closure (e.g. "purchase complete", "file saved")
	* Prevent user errors (e.g. "are you sure you want to exit without saving?")
	* Allow users ways to reverse their actions easily (e.g. undo, redo, cancel, and exit)
	* Avoid surprises and changes in behavior
	* Minimize the user's memory load (avoid having to remember things in order to perform a task, e.g. "I forgot that I already bought that book.")
	* Aim for clarity (quickly and easily understand what something does)
	* Use visual hierarchy (size, color, font, white space, and negative space) to illustrate what is important and what groups together
	* Design for flexibility: Accommodate different user skill levels (e.g. mouse vs keyboard shortcuts, advanced features, filters) and disabilities (color contrast, screen reader, easy tab key navigation, for web: different devices)
	* Lead the user to formulate a good mental model of what happens internally
Software development life cycle models:
	Types: Waterfall / incremental / iterative / spiral / agile / evolutionary / code & fix
	Considerations: requirement stability, schedule constraints, team skills, human factors, visibility, parallelizablity
Language selection:
	Familiarity vs suitabilitiy for the task at hand
System-level design:
	Technology selection
	Feasibility
	File formats
	Database management system selection and design
	Performance
	Scalability
	Security
	Error processing & fault tolerance
Databases:
	SQL:
		Properties (ACID):
			Atomic - either all of the transaction takes affect, or none of it (including under power failures and crashes)
			Consistent - database invariants are maintained (constraints, triggers, referential integrity, etc.)
			Isolated - transactions are executed as if they were sequential
			Durable - committed transactions are never forgotten (i.e. they stored to non-volatile memory)
		Basic operations (CRUD) and their associated SQL statements:
			Create (INSERT)
			Retrieve (SELECT)
			Update (UPDATE)
			Delete (DELETE)
	NoSQL:
		Useful when you need high-performance at a huge scale, with little or no relation between tables
Class-level design:
	Main focus (managing complexity):
		Limit the amount of complexity we deal with at a time
		Limit the effects when a change is made to the code
	Abstraction (a class should represent one coherent abstraction or concept)
	Information hiding / encapsulation (outside a class, you should not have to understand the internal implementation)
	Loose coupling
	High cohesion
	Guide to design: "How will this class be used?"
	Code reuse opportunities
	Other tips:
		* Every constructor and public method should leave the instance variables in a consistent and correct state for the next public method call
		* Generally avoid going over 7 (plus or minus 2) instance variables in a class.
		* Do not repeat data unless truly necessary.
		* Do not give variables more scope than they require.
	Immutable objects
		Benefits:
			Thread-safe
			Can freely share pointers to objects; no hidden side effects if something changes
		Drawback:
			If there are lots of changes then immutability may result in memory burn and slowdowns
Method-level design:
	* Naming
		* Give descriptive names that say exactly what the routine does (usually verb-noun)
		* The name should include or imply the return type
	* Size
		* Functions over a couple hundred lines of code tend to be more error-prone
		* Otherwise, no hard constraints on method length - whatever is natural for the situation
	* Parameters
		* Use parameter order consistently among different functions
		* Document assumptions on parameters
		* Document units
		* Document zero-based-counting vs one-based-counting if not obvious
	* Error handling
		* Check values of input parameters
		* Use assertions to check for bugs.  Use error handling to check for bad input.
		* Techniques for error handling:
			* Return null or neutral value
			* Print or log the error and continue execution
			* Throw an exception/error
			* Terminate the program
Control structures:
	When should you use break or continue in a loop?
		* When it makes your code easier to read/maintain/understand as opposed to working it into the boolean condition for the loop.
		* The danger of using break or continue in a large loop is that it becomes 'hidden' and people might not realize that something inside the loop affects its control flow.
	What are the advantages/disadvantages of switch...case?
		+ The expression is only checked once in one place, and would only need to changed in one place
		+ You can exploit the fall-through behavior.
		- You have to keep putting 'break;' at the end of each case if you don't want the case to "fall through".  If you forget, it still compiles.
