Junior Programmer cheat sheet
Junior Programmer · Keep the key ideas within reach.
Programming fundamentals: syntax, variables, data types, operators, expressions
A variable binds a name to a value; assignment (=) rebinds the name to a new value, while equality comparison uses == (value) or === (value and type in JavaScript).
Primitive types are typically integer, floating point, boolean, character, and null/none; strings, arrays, and objects are usually reference types whose variables hold a pointer, not the data itself.
Integer division truncates toward zero (7 / 2 == 3 in Java int math; 7 // 2 == 3 in Python); the modulo operator a % b returns the remainder.
Operator precedence, highest to lowest: parentheses, exponent, unary (! -), multiplicative (* / %), additive (+ -), comparison, logical NOT, logical AND, logical OR; parentheses always override this order.
String concatenation versus numeric addition: in JavaScript '5' + 3 evaluates to '53' but '5' - 3 evaluates to 2; in Python '5' + 3 raises TypeError instead of coercing.
Falsy values include false, 0, 0.0, empty string, null, undefined, and NaN; Python additionally treats empty list, tuple, dict, set, and None as falsy.
Short-circuit evaluation: A && B does not evaluate B when A is falsy, and A || B does not evaluate B when A is truthy; Python's and/or return an operand, not necessarily a boolean.
Immutability: Python strings and tuples cannot be modified in place, so s += 'x' inside a loop allocates a new string each iteration, giving O(n squared) total copying.
Naming conventions: camelCase for variables and methods in Java/JavaScript, snake_case in Python, UPPER_CASE for constants; a leading underscore marks internal use by convention only.
Control flow: conditionals, loops, and logical decision making
if/elif/else chains evaluate top-down and execute only the first true branch; a later elif is never tested once an earlier branch matched.
Conditions need not be boolean in Python and JavaScript: any truthy value passes; in Java the condition of an if must be an actual boolean expression.
A while loop tests its condition before each iteration, so it can run zero times; a do-while loop runs the body once before the first test.
range(a, b) yields a up to but excluding b; range(a, b, step) with a negative step counts downward, and range(len(x)) yields indices 0 through len(x) - 1.
break exits only the innermost enclosing loop; continue jumps to the next iteration of that loop; return exits the entire function from any nesting depth.
C-family switch falls through to the next case unless break is used; Python's match/case does not fall through and compares by pattern, not by identity.
De Morgan's laws: !(A && B) is equivalent to !A || !B, and !(A || B) is equivalent to !A && !B.
Off-by-one rule: an array of n elements has valid indices 0 to n - 1, so a full traversal uses index < n, never index <= n.
Nested loops over m and n items perform m * n iterations, so a doubly nested scan of the same n-element list is O(n squared).
Functions, parameters, scope, and modular code organization
A parameter is the name in the function definition; an argument is the value supplied at the call site. Positional arguments match by order, keyword arguments by name.
In Python, default parameter values are evaluated once when the function is defined, so a mutable default such as [] is shared across every call that omits the argument.
Passing follows pass-by-object-reference: rebinding a parameter inside the function does not affect the caller, but mutating a passed list or dict is visible outside.
Assignment inside a function creates a local variable that shadows an outer name; Python requires global or nonlocal to rebind an enclosing name.
return ends function execution and hands back a value; a function without a return statement yields None in Python and undefined in JavaScript.
A pure function's output depends only on its arguments and it has no side effects, which makes it deterministic and directly testable.
A module is a file of definitions imported by name; Python's if name == 'main' guard runs a block only when the file is executed directly, not when imported.
Recursion requires a base case plus a recursive call that moves toward it; each pending call consumes stack space, and Python's default recursion limit is about 1000 frames.
Data structures and strings: arrays/lists, dictionaries/maps, iteration and manipulation
Array/list access by index is O(1); appending at the end is amortized O(1); inserting or deleting at the front is O(n) because later elements shift.
Python slicing a[start:stop:step] includes start, excludes stop, and accepts negative indices, where -1 is the last element; the slice creates a new list.
A dict/map stores key-value pairs with average O(1) lookup; keys must be hashable and therefore immutable, so lists cannot be keys but tuples can.
Iterating a Python dict yields keys; use .items() for key-value pairs, .values() for values, and .get(key, default) to avoid KeyError on missing keys.
Strings are immutable character sequences: len, upper/lower, strip, split(sep), join(list), replace, find, startswith, and endswith are the standard operations; str.join is preferred over repeated += in loops.
A set holds unordered unique elements; membership testing is average O(1) versus O(n) for a list, with union |, intersection &, and difference - operators.
Python sorts with sorted(iterable, key=...) or list.sort(key=...), where the key function returns the value to compare; JavaScript's array.sort() compares as strings unless a comparator is passed.
A stack is LIFO via append/pop; a queue is FIFO and is implemented with collections.deque popleft, because list.pop(0) is O(n) per call.
Membership tests: 'x in list' scans linearly in O(n), while 'x in set' or 'key in dict' hashes the value in average O(1).
Object-oriented programming basics: classes, objects, attributes, methods, inheritance
A class is a blueprint defining attributes and methods; an object (instance) is a concrete value produced by calling the class, and each instance has its own attribute storage.
Constructors initialize new instances: init(self, ...) in Python, or a method named after the class in Java; Python's self and Java's this refer to the current instance.
Instance attributes are set per object (usually in the constructor) and are independent; class attributes are defined on the class and shared by all instances unless shadowed.
A method is a function defined inside a class; Python passes the instance as the first parameter self explicitly, while Java and JavaScript supply this implicitly.
Inheritance: class Child(Parent) or class Child extends Parent gives the child all parent attributes and methods; a subclass overrides a method by redefining it with the same name.
super() or super references the parent implementation, typically called at the start of an overridden constructor or method to reuse rather than replace parent behavior.
Encapsulation restricts direct access to internal state: Python uses _ and __ naming conventions, Java uses private/protected modifiers, and access goes through getters and setters.
Polymorphism lets the same method call behave differently per class; Python resolves it by duck typing at runtime, Java by method dispatch on the declared type hierarchy.
Composition (has-a: an object holding another object) is often preferred to deep inheritance (is-a), since long chains make behavior hard to trace and change.
Error handling, debugging, and basic testing practices
Structure: try/except/finally in Python and try/catch/finally in Java and JavaScript; the finally block always runs, even when an exception propagates or a return executes.
Catch the most specific exception type first and order handlers from specific to general; a bare except or catch (Exception) swallows bugs and hides the real failure site.
raise or throw signals an error deliberately; catching, logging, and re-raising preserves the original traceback and stack context.
Common runtime errors: NameError or ReferenceError (undefined name), TypeError (wrong type), IndexError or out-of-range (bad index), KeyError (missing dict key), ZeroDivisionError, NullPointerException.
A traceback is read bottom-up: the final line gives the exception type and message, and the lines above list the call stack with the innermost frame last.
Debugging techniques: print or log intermediate values, assert invariants, and bisect either the code (comment out blocks) or the history (git bisect) to find the first failing point.
A unit test follows arrange-act-assert: set up inputs, call exactly one behavior, and compare the result with an expected value; tests must be independent and deterministic.
assert condition, message raises AssertionError when the condition is false; Python disables asserts under the -O flag, so they must not be used for input validation.
Test edge cases: empty input, a single element, duplicates, negatives, zero, and maximum size; line coverage only shows executed code, not whether behavior is correct.
File handling and use of standard libraries
open(path, mode) modes: 'r' read (default, fails if missing), 'w' truncate or create, 'a' append, 'x' create and fail if it exists; append 'b' for binary and 't' for text.
Use a context manager, with open(path) as f:, so the file is closed automatically on normal exit and on exception; otherwise call f.close() explicitly.
Reading: f.read() returns the whole file as one string, f.readline() one line, and iterating over f yields lines that still contain the trailing newline, so call .strip().
Writing: f.write(text) returns the number of characters written and adds no newline; f.writelines(list) writes strings back to back without inserting separators.
Pass encoding='utf-8' explicitly when opening text files; binary mode returns bytes objects, which must be decoded before string operations.
Build paths with os.path.join or pathlib.Path rather than hard-coded '/' or backslash; relative paths resolve against the process's current working directory, not the script's folder.
Frequently used standard modules: math, random, datetime, json, csv, re, collections (deque, Counter, defaultdict), os, sys, and pathlib.
sys.argv is the list of command-line arguments, where sys.argv[0] is the script name and sys.argv[1:] are the user-supplied arguments.
JSON: json.dumps returns a string and json.dump writes to a file object; json.loads parses a string and json.load reads a file; objects that are not JSON-serializable raise TypeError.
Algorithms and problem solving: searching, sorting, and simple complexity reasoning
Linear search checks elements in order, runs in O(n), and works on unsorted data; binary search runs in O(log n) but requires the data to be sorted first.
Binary search maintains low and high indices, compares the target with the element at the midpoint, and moves one boundary past the midpoint; the loop continues while low <= high.
Bubble, selection, and insertion sort are O(n squared) comparison sorts; insertion sort degrades to O(n) when the input is already nearly sorted.
Merge sort is divide-and-conquer with O(n log n) time in all cases, is stable, and needs O(n) auxiliary space; quicksort averages O(n log n) but degrades to O(n squared) with bad pivots on sorted input.
Big-O keeps the dominant term and drops constants and lower-order terms, so 3n squared + 5n + 7 becomes O(n squared); it describes growth, not absolute speed.
Growth order from fastest to slowest: O(1) < O(log n) < O(n) < O(n log n) < O(n squared) < O(2 to the n) < O(n factorial).
Hash map operations average O(1) but degrade to O(n) per operation when many keys collide or the load factor grows, which is why tables resize.
Space complexity counts extra memory beyond the input: in-place sorts use O(1) auxiliary space, merge sort uses O(n), and recursion uses stack space proportional to depth.
Naive recursive Fibonacci recomputes subproblems and runs in O(2 to the n); caching results (memoization) reduces it to O(n) time with O(n) space.
Development tooling and version control basics
git init creates a repository, git clone copies a remote one including history, and git status reports staged, unstaged, and untracked changes.
The staging area (index) is what a commit records: git add stages changes, git commit -m 'message' snapshots them, git diff shows unstaged changes, and git diff --staged shows staged ones.
Branches are movable pointers to commits: git branch lists them, git switch -c name (or git checkout -b name) creates and switches, and HEAD points at the current branch's tip.
git merge joins branches and creates a merge commit when histories diverged, preserving both lines; git rebase replays commits onto a new base and rewrites their hashes, so shared branches should not be rebased.
git pull is git fetch followed by a merge; git push uploads local commits; merge conflicts appear between <<<<<<<, =======, and >>>>>>> markers and are resolved by editing and re-running git add.
.gitignore lists patterns of untracked files Git should skip; files already tracked stay tracked until removed with git rm --cached.
History tools: git log --oneline lists commits, git revert creates a new commit that undoes an earlier one safely, and git reset --hard moves the branch pointer and discards uncommitted work.
Every commit is identified by a SHA hash of its content and metadata; a detached HEAD means HEAD points directly at a commit rather than at a branch.
Dependency isolation: a Python venv or Node node_modules folder keeps per-project packages separate, with versions pinned in requirements.txt or package.json.