Table of Contents

charlie deck

@bigblueboo • AI researcher & creative technologist

Back to index

Street Coder: The rules to break and how to break them

Book Cover

Authors: Sedat Kapanoglu Tags: software engineering, pragmatism, career development, best practices Publication Year: 2022

Overview

I wrote this book to fill the gap between what you learn in school or a boot camp and what you actually need to survive and thrive in the professional software development world—what I call ‘the streets.’ Formal education gives you theory, but it often lacks the context of what truly matters when deadlines are tight and bosses are unreasonable. Self-taught programmers learn through trial and error but may miss some foundational knowledge that could save them from those very errors. This book is the street lore I wish I had when I started. It’s for the developer who has learned the rules and is now ready to understand why, when, and how to break them. My goal is to equip you with a questioning and practical mindset. We tackle well-known paradigms, anti-patterns, and seemingly ‘bad’ practices that can be incredibly useful in the right context. This isn’t about blindly following dogma; it’s about understanding the tradeoffs. The professional world values one thing above all: [[throughput]]. Counterintuitively, good design, solid theory, and clean code are not academic exercises but the very tools that boost your long-term throughput. This book is designed to be a perspective changer. It will show you how to challenge established best practices, prioritize practicality, and make pragmatic decisions that get the job done without accumulating crippling [[technical debt]]. It’s for the developer who understands that our craft is more than just typing code; it’s about solving problems efficiently in a complex and often chaotic environment.

Book Distillation

1. To the streets

In the professional world, or ‘the streets,’ your throughput is what matters most. Elegant design, algorithmic knowledge, and high-quality code are not goals in themselves; they are crucial tools that directly impact how much you can deliver over time. A [[Street Coder]] is a pragmatic developer, molded by real-world experience, who is results-driven, questions established norms, and embraces the complexity and ambiguity inherent in modern software development.

Key Quote/Concept:

The Street Coder: A developer whose skills are forged in the fires of professional experience, valuing practical results and high throughput over rigid adherence to theory. They understand that good technical practices are a means to an end: shipping working software.

2. Practical theory

Computer science theory is not just for academics; it’s a practical survival tool. Understanding [[Big-O notation]] helps you foresee performance bottlenecks before they happen. Knowing how data structures like arrays, lists, and dictionaries work internally allows you to make intelligent tradeoffs. Types are not a chore; they are a powerful, free tool for ensuring correctness through [[proof of validity]], making code self-documenting, and gaining performance, especially when you understand the critical difference between reference and value types.

Key Quote/Concept:

Proof of Validity: Using custom types (classes or structs) to encapsulate and validate data at the point of creation. Instead of passing a raw integer for a post ID, you pass a PostId object whose constructor guarantees the ID is always valid. This eliminates the need for repeated validation checks throughout the codebase.

3. Useful anti-patterns

Dogma creates blind spots. Some so-called ‘bad practices’ are incredibly useful in the right context. Don’t be afraid to break working code to fight [[code rigidity]] and refactor tangled dependencies. Sometimes, repeating yourself is better than creating a complex, over-engineered abstraction that violates concern boundaries. Inventing your own simple API as a wrapper around a complex external library can save you from being tightly coupled to its design.

Key Quote/Concept:

The Happy Path: A coding style that flattens complex If/Else structures. It involves handling all error conditions and edge cases with early return statements at the top of a function. This leaves the main, successful logic—the ‘happy path’—as a clean, unindented flow at the end, making the function’s primary purpose much easier to read.

4. Tasty testing

Testing isn’t a chore to be endured; it’s a tool for increasing your confidence and development speed. The goal is to find the sweet spot between cost and risk, which often means focusing on automated unit tests. Forget rigid dogmas like [[TDD]]; write tests when they provide the most value, which is often after you have a working prototype. Use the type system to your advantage to eliminate entire classes of tests, such as null checks, range checks, and invalid value checks.

Key Quote/Concept:

Choosing the Right Testing Methodology: This is a mental model for balancing the cost (time to implement and run) against the risk (likelihood and impact of failure) of a feature. It helps you decide whether to use manual tests, full unit tests, testing in production, or even no tests at all for a given scenario.

5. Rewarding refactoring

Refactoring is the art of changing code’s internal structure to reduce rigidity and prepare for future evolution, without changing its external behavior. Large architectural changes should never be done in one shot; they must be incremental. Start by identifying components, estimating risk, and extracting common, low-risk code into shared projects. Use [[dependency injection]] to break tight coupling, which makes it easier to swap out implementations and refactor components in isolation.

Key Quote/Concept:

The Prestige: A three-step refactoring illusion for large architectural changes. 1) The Pledge: The initial, monolithic code. 2) The Turn: Extracting a common component into a separate, shared library without breaking the build. 3) The Prestige: Introducing the new architecture and making the old one seamlessly disappear by depending on the shared component.

6. Security by scrutiny

Security is a subset of reliability. It’s not just about hackers; it’s about people, processes, and creating a [[threat model]]. Always design with security in mind by practicing the principle of least privilege. You can avoid the most common attacks by using established tools: use parameterized queries to prevent [[SQL injection]], proper output encoding to stop [[XSS]], and anti-forgery tokens to mitigate [[CSRF]]. Never roll your own crypto, and always store secrets outside of your source code.

Key Quote/Concept:

Pocket-Sized Threat Model: A practical process of identifying your assets (database, source code), servers, information sensitivity, and access paths (who can access what). This isn’t about achieving perfect security but about prioritizing risks and making informed decisions, like realizing the CEO’s email is a primary attack vector.

7. Opinionated optimization

Premature optimization is the root of all learning. Start optimization from the top down by identifying the correct problem before diving into code. Beware of hidden [[nested loops]] in properties and LINQ expressions. Understand low-level CPU concepts to write faster code: favor memory alignment, design for cache locality, break instruction dependency chains for pipelining, and use [[SIMD]] for parallel data processing. Make I/O faster with buffering and non-blocking with async/await.

Key Quote/Concept:

Performance vs. Responsiveness: These are not the same thing. Raw performance is about computational speed, while responsiveness is about user perception. A responsive application might be technically slower (e.g., using CPU cycles to render a progress bar) but provides a much better user experience than a faster application with a frozen UI.

8. Palatable scalability

Scalability is about maintaining responsiveness as load increases. The biggest enemy of scalability is locking. Prefer lock-free data structures or techniques like [[double-checked locking]]. Embrace eventual consistency, as strict consistency is a major bottleneck. Don’t hold database connections open for the life of a request; open and close them per-query to maximize connection pool utilization. Use asynchronous I/O to conserve threads, which is far more scalable than simply adding more threads. And respect the monolith; it can scale massively and is far simpler than a premature microservices architecture.

Key Quote/Concept:

Double-Checked Locking: An optimization pattern to reduce lock contention. It involves first checking for an object’s existence without a lock. Only if it’s null does the code enter a lock to perform a second check and the potential initialization. This avoids the overhead of acquiring a lock on every single access.

9. Living with bugs

Bugs are an inevitable part of software development. Triage them based on priority (business impact) and severity (customer impact), and accept that some bugs are ‘won’t fix.’ Don’t just catch exceptions; handle them with purpose. Design for [[exception resiliency]] so your application can recover from a crash without entering a corrupt state. Ditch the step-by-step debugger for more efficient methods like printf() debugging, dump diving, and [[advanced rubber-duck debugging]].

Key Quote/Concept:

Advanced Rubber-Duck Debugging: Using a tool like a Stack Overflow draft to solve a problem. The process of clearly articulating the problem, what you’ve tried, and what you expect is often enough to force you to see the solution yourself, without ever needing to actually post the question.


Generated using Google GenAI

Essential Questions

1. What defines a ‘Street Coder,’ and how does this mindset differ from a purely academic or self-taught approach?

A [[Street Coder]] is a developer forged in the professional world—’the streets’—where the ultimate measure of success is [[throughput]]. This mindset is a pragmatic synthesis of formal education and self-taught experience. Unlike a purely academic developer who might prioritize theoretical elegance, a Street Coder understands that computer science principles are not ends in themselves, but tools to increase delivery speed and quality over the long term. Unlike a purely self-taught programmer who might lack foundational knowledge, a Street Coder appreciates how understanding [[Big-O notation]] or the difference between value and reference types can prevent costly real-world mistakes. The core of the Street Coder philosophy is a relentless focus on results, a willingness to question established dogma, and an understanding that our craft is about solving complex problems under pressure. It’s about knowing the rules of software development so you can understand when and how to break them effectively, without accumulating crippling [[technical debt]]. This perspective bridges the gap between theory and the chaotic reality of shipping software.

2. Why does the book advocate for questioning and sometimes breaking established ‘best practices’ and so-called ‘anti-patterns’?

I advocate for questioning established norms because blind adherence to dogma creates rigidity and blind spots. The professional world is messy, and a rule that works perfectly in one context can be a hindrance in another. The book’s purpose is to arm you with a critical mindset, not a new set of rigid rules. We explore ‘useful anti-patterns’ to demonstrate that practices often labeled as ‘bad’—like repeating yourself (DRY violations) or inventing your own simple API instead of using a complex library—can be pragmatic, effective solutions in specific scenarios. For instance, a simple copy-paste might be better than creating a premature, overly complex abstraction that crosses concern boundaries. The goal is not to promote bad code, but to encourage a deep understanding of [[tradeoffs]]. A Street Coder knows that ‘best practice’ is context-dependent. By understanding the ‘why’ behind a rule, you gain the wisdom to know when it applies and, more importantly, when a supposedly ‘bad’ practice is the most direct path to a robust, maintainable solution.

3. How does the book connect low-level computer science theory to the high-level goal of maximizing developer throughput?

The central argument is that theory is not an academic exercise; it’s a practical survival tool that directly boosts your long-term [[throughput]]. I show this by demystifying concepts and grounding them in real-world consequences. For example, understanding [[Big-O notation]] isn’t about passing an interview; it’s about foreseeing how a seemingly innocent nested loop will cripple your application’s performance as data grows, saving you days of debugging later. Knowing the internal workings of a dictionary versus a list allows you to make intelligent choices that prevent performance bottlenecks. Similarly, understanding low-level CPU concepts like cache locality or [[SIMD]] isn’t about premature optimization; it’s about writing code that is naturally faster because it works with the hardware, not against it. By framing theory as a set of tools for building faster, more reliable, and more scalable software, the book demonstrates that a solid theoretical foundation is the most effective way to increase the amount of value you can deliver over time.

Key Takeaways

1. Prioritize Throughput, but Wield Good Practices as Its Tools

The single most important metric on ‘the streets’ is your [[throughput]]—how much working software you can deliver over time. However, this isn’t an excuse for sloppy work. Counterintuitively, the path to high throughput is paved with good design, solid theory, and clean code. These aren’t academic ideals to be pursued for their own sake; they are pragmatic tools that prevent regressions, reduce maintenance time, and make future changes easier. A poorly designed system might allow for a quick initial delivery, but it creates [[technical debt]] that grinds future development to a halt. A Street Coder understands this tradeoff and invests in quality not as a matter of principle, but as a strategic decision to maintain high velocity over the entire life of a project. The goal is always to ship, and good engineering practices are simply the most effective way to do that consistently.

Practical Application: An AI product engineer is asked to quickly build a prototype for a new feature. Instead of hacking it together with no structure, they spend a little extra time defining clear interfaces between the data processing logic and the API layer. This allows them to ship the prototype quickly, but when the feature is approved, they can scale the data processing part or swap out the model without having to rewrite the entire service, thus maintaining high [[throughput]] into the production phase.

2. Challenge Dogma: So-Called ‘Bad’ Practices Can Be Pragmatic Solutions

The software industry is filled with dogma, from rigid adherence to design patterns to the vilification of ‘anti-patterns.’ I argue that context is king, and a practice is only ‘bad’ if it’s applied in the wrong situation. The book provides numerous examples where breaking the rules is the right call. For instance, the ‘Don’t Repeat Yourself’ (DRY) principle is useful, but not when it leads to a complex, tightly-coupled abstraction that is harder to maintain than two separate, slightly repetitive pieces of code. Similarly, the ‘Happy Path’ coding style intentionally flattens complex If/Else blocks by using multiple ‘bad’ early return statements. This makes the function’s primary purpose clearer and easier to read. A Street Coder’s value lies in their ability to analyze tradeoffs and choose the simplest, most effective solution, even if it contradicts conventional wisdom.

Practical Application: A developer is building a simple data transformation script. The ‘by-the-book’ approach would be to create a generic, reusable transformation engine. However, recognizing that the requirements are simple and unlikely to change, they opt to write two separate, slightly repetitive functions. This avoids creating a complex abstraction, makes the code easier for others to understand immediately, and gets the job done faster. They have pragmatically chosen a ‘DRY violation’ to increase clarity and reduce complexity.

3. Leverage the Type System as a Free, Powerful Tool for Correctness

In strongly-typed languages, the type system is often seen as a chore—bureaucracy that slows down development. I present it as one of your most powerful allies. It’s a free, automated linter that catches entire classes of bugs at compile time, long before they reach production. The concept of [[Proof of Validity]] is key here: by wrapping a primitive value like an integer in a custom type (e.g., a PostId class), you can enforce validation rules in the constructor. Once a PostId object exists, you know it’s valid everywhere it’s used, eliminating the need for repetitive validation checks. This makes the code safer, more self-documenting, and easier to reason about. Using specific types like TimeSpan or Uri instead of generic strings provides the same benefits, preventing bugs and making intent clear. This isn’t about academic purity; it’s about doing less work and building more reliable software.

Practical Application: An AI engineer is designing an API that accepts a user ID. Instead of passing the ID as a raw integer int userId, they define a UserId struct. The UserId constructor validates that the integer is positive. Now, any function that accepts a UserId object doesn’t need to re-validate it. This prevents bugs where an invalid ID (e.g., -1) could be passed deep into the system, and it makes the function signatures more descriptive.

Suggested Deep Dive

Chapter: Chapter 3: Useful anti-patterns

Reason: This chapter best encapsulates the book’s core philosophy of pragmatic, critical thinking. It directly challenges the dogmas that many developers are taught and encourages a deeper understanding of tradeoffs. For an AI product engineer, who must constantly balance innovation, speed, and reliability, the ability to discern when a ‘best practice’ is actually a hindrance is a critical skill. This chapter provides the mental models to make those nuanced decisions.

Key Vignette

Opening the Black Box

One day in 1993, a friend asked me to install a sound card in my PC. I had never opened my PC case before and was afraid I’d damage it. My friend’s response resonated with me: ‘You have to open it to see how it works.’ My anxiety was caused by ignorance, not incapability. Opening the case revealed its simplicity—just a board and some slots. This became my motto for dealing with complexity: open the box, look at the parts, and demystify the technology you depend on.

Memorable Quotes

One thing is clear in the streets: your throughput is what matters most. Nobody cares about your elegant design, your knowledge of algorithms, or your high-quality code. All they care about is how much you can deliver in a given time.

— Page 26, Chapter 1: To the streets

How does a project get to be a year late? … One day at a time.

— Page 29, Chapter 1: To the streets

If the code makes you afraid to break it, it’s badly designed code. That doesn’t mean good code doesn’t break, but when it does, it’s much easier to glue the pieces back together.

— Page 81, Chapter 3: Useful anti-patterns

Chapter 7 shows some hard-core optimization techniques, shamelessly recommends premature optimization, and describes a methodical approach to fixing performance problems.

— Page 20, About this book

The moral of the story is that life in the streets is full of unwelcome surprises.

— Page 32, Chapter 1: To the streets

Comparative Analysis

I wrote ‘Street Coder’ to fill a specific gap in a developer’s library, positioning it as a pragmatic companion to more dogmatic or theoretical works. It shares a philosophical kinship with ‘The Pragmatic Programmer’ by Andrew Hunt and David Thomas, emphasizing craftsmanship, adaptability, and a focus on practical results. However, ‘Street Coder’ adopts a more contrarian and informal tone, explicitly encouraging the reader to question and even break established rules, a stance that is more direct than the ‘tips’ format of its predecessor. In contrast to a book like Robert C. Martin’s ‘Clean Code,’ which presents a fairly prescriptive methodology for writing good code, my book argues that ‘cleanliness’ is context-dependent and that so-called ‘anti-patterns’ can be valuable tools. While ‘Clean Code’ provides rules to follow, ‘Street Coder’ provides the reasoning to know when to ignore them. It also draws on foundational texts like Fred Brooks’ ‘The Mythical Man-Month,’ but translates their high-level management insights into concrete, everyday coding practices for the individual developer. My unique contribution is this focus on ‘street lore’—the hard-won, often counterintuitive wisdom that bridges the gap between formal knowledge and professional effectiveness.

Reflection

This book is the distillation of wisdom I wish I had when I started my career—a guide to navigating the messy, high-pressure world of professional software development. Its greatest strength is its relentless pragmatism. I intentionally push back against the industry’s tendency to treat ‘best practices’ as immutable laws. The goal is to empower developers to think for themselves, to understand the ‘why’ behind the ‘what,’ and to make informed decisions based on tradeoffs rather than dogma. However, this contrarian stance could be a potential weakness if misinterpreted. A novice developer might see the chapter on ‘Useful anti-patterns’ as a license to write sloppy code, missing the crucial point that you must first understand the rules deeply to know how to break them effectively. My perspective is undeniably shaped by my self-taught background and experience building a large-scale system from scratch; I value what works in practice over what is theoretically elegant. This book isn’t an objective, factual textbook; it’s an opinionated, battle-tested survival guide. Its significance lies not in providing definitive answers, but in teaching developers how to ask the right questions to thrive on ‘the streets.’

Flashcards

Card 1

Front: What is the primary metric of success for a ‘Street Coder’?

Back: [[Throughput]]: The amount of working software delivered over a given period. Good design and clean code are tools to maximize long-term throughput.

Card 2

Front: What is the concept of [[Proof of Validity]]?

Back: Using custom types (classes or structs) to encapsulate and validate data at the point of creation. This ensures that an object, once created, is always in a valid state, eliminating the need for repeated validation checks.

Card 3

Front: What is ‘The Happy Path’ coding style?

Back: A technique to improve readability by handling all error conditions and edge cases with early return statements at the top of a function. This leaves the main, successful logic—the ‘happy path’—as a clean, unindented flow at the end.

Card 4

Front: What is ‘The Prestige’ in the context of refactoring?

Back: A three-step method for large architectural changes: 1) The Pledge (the original monolithic code), 2) The Turn (extracting a common component into a shared library without breaking anything), 3) The Prestige (introducing the new architecture that depends on the shared component, making the old one ‘disappear’).

Card 5

Front: What is the key difference between [[Performance vs. Responsiveness]]?

Back: Performance is the raw computational speed of a task. Responsiveness is the user’s perception of speed. A responsive application provides feedback (like a progress bar) and may be technically slower but provides a better user experience.

Card 6

Front: What is [[Double-Checked Locking]]?

Back: An optimization pattern to reduce lock contention. It involves checking for an object’s existence without a lock first. Only if it’s null does the code enter a lock to perform a second check and the potential initialization, avoiding lock overhead on every access.

Card 7

Front: What is [[Advanced Rubber-Duck Debugging]]?

Back: Using a tool like a Stack Overflow draft to solve a problem. The act of clearly articulating the problem, what you’ve tried, and what you expect is often enough to reveal the solution yourself, without ever needing to post the question.


Generated using Google GenAI

I used Jekyll and Bootstrap 4 to build this.