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.