Skip to content

2.7 Language Theory & Low-Level

2.6 DevOps Practices | Home | Next: 2.8 Field-Specific Knowledge


Compiled vs. Interpreted Languages

  • Compiled languages (C, C++, Rust, Go): Source code is translated by a compiler to machine code or intermediate code; the executable runs independently. Fast execution, longer develop-compile-run cycle.
  • Interpreted languages (Python, Ruby, traditional JavaScript): An interpreter reads and executes source code line by line with no compilation step. Fast feedback, slower execution than compiled.
  • Hybrid languages (Java, C#): Compiled to intermediate code (bytecode/IL), then compiled to machine code at runtime by a JIT (Just-In-Time) compiler within a virtual machine (JVM/CLR). Balances portability and performance.

Type Systems

Static vs. Dynamic refers to when types are checked; Strong vs. Weak refers to how strictly type rules are enforced. These two dimensions form a quadrant:

Static checking (compile-time) Dynamic checking (runtime)
Strong typing Java, C#, Rust, TypeScript Python, Ruby, Elixir
Weak typing C, C++ JavaScript, PHP, Perl

Definitions: - Static typing: Variable types are checked at compile-time, before the code is executed. TypeScript: function foo(a: number) will reject a string at compile time. - Dynamic typing: Variable types are checked on the fly, as the code is executed. PHP: function foo($a) only knows what type $a is at runtime. - Strong typing: Never implicitly converts a variable or value's type. Python: 1 + "2" throws TypeError: unsupported operand type(s) for +: 'int' and 'str'. - Weak typing: The interpreter or compiler attempts to make the best of what it is given by performing implicit type coercions. JavaScript: 1 + "2" returns "12" (auto-converts the number to a string and concatenates).

Note that many languages don't sit cleanly in one quadrant. C is statically weak-typed (compile-time checked but allows implicit void* conversions); Python is dynamically strong-typed (runtime checked but never allows implicit type coercion).

Regular Expressions (Regex)

Regular expressions describe string matching patterns with native support in almost all programming languages. Core elements: - Literals: abc matches the exact string "abc". - Character classes: [a-z] matches any lowercase letter; \d matches any digit. - Quantifiers: * (zero or more), + (one or more), ? (zero or one), {n,m} (n to m times). - Anchors: ^ (start of line), $ (end of line), \b (word boundary). - Groups and capture: (pattern) extracts the matched substring. - Common use cases: form validation, log parsing, data extraction, search and replace.

Lazy Loading

Defer the creation of objects, loading of data, or initialization of resources until the moment they are actually needed. Core benefits: - Reduce startup time: Load only what's needed for the first screen. - Save memory: Don't load it if it's never used. - Improve user experience: Load on demand instead of making the user wait. - Typical implementations: code splitting at the route level (frontend), lazy-loaded associations in ORMs, scroll-based image loading, virtual lists.

Profiling

Profiling is a form of dynamic program analysis that measures a program's runtime behavior—where time is spent, where memory is used, and how frequently functions are called.

Three types based on output: - Flat profiler: Shows average call times for each function, without breaking down by caller context. - Call-graph profiler: Shows call times, frequencies, and the call-chains involved based on the callee. - Input-sensitive profiler: Relates performance measures to features of the input workloads (input size, input values), characterizing how performance scales as a function of input.

Two data collection approaches: - Event-based: Inserts hooks at function entry/exit points. Precise but high overhead; may cause observer effects (heisenbugs). - Statistical (sampling): Probes the call stack at regular intervals using operating system interrupts. Provides a statistical approximation with minimal overhead and near-zero impact on the target program.

Principle: Measure first, then optimize. Never optimize based on guesses.

Concurrency Fundamentals

  • Race Condition: Multiple threads/processes accessing shared resources simultaneously, with the final result depending on execution order. The most dangerous type of concurrency bug—hard to reproduce, hard to debug. Countermeasures: locks, atomic operations, immutable data structures.
  • Deadlock: Thread A holds Lock 1 and waits for Lock 2; Thread B holds Lock 2 and waits for Lock 1—mutual waiting, permanent blocking. Four necessary conditions: mutual exclusion, hold and wait, no preemption, circular wait. Countermeasures: consistent lock ordering, timeout mechanisms, deadlock detection.
  • Mutual Exclusion: Ensuring only one thread at a time can access a critical section. Implementation mechanisms: mutex locks, semaphores, read-write locks. Finer granularity yields higher concurrency but also higher complexity.

Sources

  • Cameron Pavey — Understanding Types; Static vs Dynamic, Strong vs Weak: https://medium.com/@cpave3/understanding-types-static-vs-dynamic-strong-vs-weak-88a4e1f0ed5f
  • Wikipedia — Profiling (computer programming): https://en.wikipedia.org/wiki/Profiling_(computer_programming)

2.6 DevOps Practices | Home | Next: 2.8 Field-Specific Knowledge