Language Design Principles

Encapsulation

The internal representation of an object is hidden
The hiding of data implementation by restricting access to accessors and mutators
Prevents outside users from setting values to invalid or inconsistent states
Reduces system complexity

Abstraction

Code to interfaces instead of to detailed implementations
Decompose complex systems into smaller components to manage complexity

Inheritance

Reuse code by establishing an object hierarchy

Polymorphism

Literally, one name with many forms

Examples Of Polymorphism

Overloading

You can have several methods with the same name and different parameter lists
The correct method is determined at compile-time
(The return type does not differentiate the method signatures)

Overriding

A derived class can override a base class method
The correct method is determined at run-time

Programming Design Principles

These are the SOLID principles.

Single Responsibility

A class should have only one responsibility.
Therefore, it will have only one reason to change.

For example, class Calculator should not format its outputs for display.

Open/Closed

A class should be open for extension and closed for modification.
Similarly, make a class easy to extend so it does not have to be modified.

The goal is to design modules such that their behavior can be extended without modifying their source code.

For example, you might use the Decorator Pattern when writing a "discount price" module, instead of one class that contains all the discounts. The first design can be extended, the second requires editing the module when requirements change.

Liskov Substitution

Derived classes can be substituted for their base classes.

That means that anything you can call on the base class, and anything you can pass the base class into, will also work with any derived class.

Don't break base class functionality when writing derived classes.

Ex from Robert Martin: if you have base class Bird with Flying methods, do not make derived class Penguin under Bird because Penguins cannot fly.

(This principle is named for Barbara Liskov, who introduced the idea in 1987)

Interface Segregation

Clients should not have to implement interfaces they do not use.

For example, interface IShape should not include a method Volume() because 2D shapes do not have a volume but would be forced to implement the method.

Segregate (separate) the methods into as many different interfaces as makes sense.

Dependency Inversion

High level models should not depend on low level models.

For example, a PasswordReminder class does not care what sort of database it accesses, so it should accept a database connection as an argument instead of creating its own. It should also be accepting the base class DBConnection rather than the more specific derived class MySQLConnection.

This will also make test cases much easier to write.
Declarative Programming

A paradigm or style in which the language expresses the logic of a computation without describing its control flow. This is an abstraction, specific implementations of the logic exist within the language.

Ex: SQL
Ex: Regular Expressions
Ex: LINQ

The focus is on WHAT must be accomplished rather than the details of HOW.

These languages also Lack Side-Effects or, in other words, is Referentially Transparent. They also frequently have a clear correspondence to mathematical logic.

Imperative Programming

Uses statements that change a program's state.

Procedural Programming is a subset of Imperative Programming.

Referential Transparency

A function is referentially transparent if every duplicate call to the function produces duplicate results.

Ex: Console.ReadLine() is opaque because calling it several times will produce different results

Ex: "5 + 5" is transparent because it always produces "10"
Passing Parameters

This section describes different ways programming languages handle passing arguments/parameters into functions/methods.

Categories

There are two common ways to divide programming languages.

(1) Pass-by-value vs Pass-by-reference
In this case, the pass-by-reference umbrella includes both pass-by-reference and pass-by-object-reference.

(2) Pass-by-value vs Pass-by-reference vs Pass-by-object-reference

Pass By Value

Pass-by-value means pass a copy into the method. Any change to the parameter in the method will not affect the argument that was passed in.

Primitives in Java and C# are passed by value. That includes data types like int, string, and bool.


//C#
using System;
class Program
{
    static void Main(string[] args)
    {
        int x = 5;
        Console.WriteLine(x); //outputs 5

        IncrementInt(x);
        Console.WriteLine(x); //outputs 5 still

        Console.ReadLine();
    }

    public static void IncrementInt(int y) //x is the argument being passed in to y, the parameter
    {
        y += 1; //only the local copy of x (called y) is edited
    }
}

The data types called "primitives" in Java and C# are all "immutable objects" in Python. They are technically passed-by-object-reference, but the behavior is de-facto pass-by-value, because all edit operations cause the object to be re-instantiated.


 #Python
x = 5
print(x) #outputs 5

incrementInt(x)
print(x) #outputs 5 still

def incrementInt(y): #x is the argument being passed in to y, the parameter
    y += 1 #only the local copy of x (called y) is edited

What are called "primitives" in C#, are all immutable objects in Python. Technically, Python does not use pass-by-value, but the behavior is the same for types like int, string, and bool.

Pass By Object Reference

Pass-by-object-reference means to pass copy of the pointer (aka reference) to the object. Most operations on the parameter will affect the original argument.

Objects in Java and C# are passed by object reference (although this is commonly called simply pass-by-reference).


//C#
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        List<int> x = new List<int>() { 1, 2, 3 };
        Console.WriteLine(x.Count); //outputs 3

        AppendToList(x);
        Console.WriteLine(x.Count); //outputs 4

        ClearList(x);
        Console.WriteLine(x.Count); //outputs 0

        InitializeList(x);
        Console.WriteLine(x.Count); //outputs 0 still

        Console.ReadLine();
    }

    public static void AppendToList(List<int> y)
    {
        y.Add(4); //operations on the object affect the original argument
    }

    public static void ClearList(List<int> y)
    {
        y.Clear(); //operations on the object affect the original argument
    }

    public static void InitializeList(List<int> y)
    {
        y = new List<int>() { 1, 2, 3, 4, 5, 6, 7 }; //instantiation edits the pointer y, and does not affect the original argument
        //now x and y are pointing to difference objects, so any operations on y will not affect x
    }
}

Everything is an object in Python, so everything is passed-by-object-reference. Immutable objects (integers, string, booleans, etc) are technically passed-by-object-reference, but since all edit operations actually re-instantiate the object, they are de-facto pass-by-value.

In Python, collections like list, set, and dictionary are all mutable objects, so they have the expected pass-by-object-reference behavior.

x = [1, 2, 3]
print(len(x)) #outputs 3

appendToList(x)
print(len(x)) #outputs 4

clearList(x)
print(len(x)) #outputs 0

initializeList(x)
print(len(x)) #outputs 0 still

def appendToList(y):
    y.append(4)

def clearList(y):
    y.clear()
    
def initializeList(y):
    y = [1, 2, 3, 4, 5, 6, 7]

Pass By Reference

This definition will differentiate pass-by-reference from pass-by-object-reference. The term pass-by-reference is very frequently used loosely to mean either definition.

Pass-by-reference means everything you do to the parameter affects the original argument, even instantiation.

In C#, you can specify pass-by-reference.

//C#
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        List<int> x = new List<int>() { 1, 2, 3 };
        Console.WriteLine(x.Count); //outputs 3

        AppendToList(x);
        Console.WriteLine(x.Count); //outputs 4

        ClearList(x);
        Console.WriteLine(x.Count); //outputs 0

        InitializeList(x);
        Console.WriteLine(x.Count); //outputs 0 still

        InitializeList(ref x);
        Console.WriteLine(x.Count); //outputs 7

        Console.ReadLine();
    }

    public static void AppendToList(List<int> y)
    {
        y.Add(4); //operations on the object affect the original argument
    }

    public static void ClearList(List<int> y)
    {
        y.Clear(); //operations on the object affect the original argument
    }

    public static void InitializeList(List<int> y)
    {
        y = new List<int>() { 1, 2, 3, 4, 5, 6, 7 }; //instantiation edits the pointer y, and does not affect the original argument
        //now x and y are pointing to difference objects, so any operations on y will not affect x
    }

    public static void InitializeList(ref List<int> y)
    {
        y = new List<int>() { 1, 2, 3, 4, 5, 6, 7 }; //instantiation affects the original argument
    }
}

You cannot specify pass-by-reference in Python, as far as I know.

Cyclomatic Complexity

A software metric related to the complexity of the program. A measure of the linearly independent paths through a program's source code.

Ex: A to B to C to D
    Cyclomatic Complexity equals 1 because there is only 1 path

Ex: A to B to D
    A to C to D
    Cyclomatic complexity equals 2 because there are 2 paths
    
Generally, in a control flow graph, complexity = edges - nodes + 2*loops
(loops are called Connected Components)
Continuous

Continuous Integration

Developers continuously merge they commits into the main branch, so that merge conflicts appear quickly and at smaller sizes than if you wait a while to do this.

Ideally, every developer does a fresh merge from main to their branch, resolves conflicts, then merges up to main.

Continuous Delivery

Continuous Integration PLUS automated testing that runs when the main branch is updated PLUS an one-button push to production process.

Your product is always ready to push to production, whenever you need it.

Continuous Deployment

Continuous Delivery BUT if all automated test pass THEN every update to main is automatically pushed to production.
CAP Theorem

The CAP theorem for distributed computing, published by Eric Brewer:

It is not possible for a distributed computer system to simultaneously provide Consistency, Availability, and Partition Tolerance. At most, two of these can be provided at a time.

Consistency: all nodes see the same data at the same time.

Availability: every request receives a FAILED or SUCCEEDED response.

Partition Tolerance: the system continues to operate despite partial system failure or arbitrary message loss.
Twelve-Factor App Principles

Principles for building software-as-a-service applications. The goal is portability and resilience when deployed to the web.

Codebase

There should be only one codebase for a deployed service.

Dependencies

All dependencies should be declared explicitly, including dependencies on system tools and libraries.

Config

Configuration that varies between deployments should be stored in the environment.

Backing Services

??
All backing services are treated as attached resources and attached and detached by the execution environment.

Build, Release, Run

The delivery pipeline should strictly consist of Build, Release, Run.

Processes

Applications should be deployed as stateless processes. Persistent data should be stored on a backing service.

Port Binding

Self-contained services should make themselves available to other services by specified ports.

Concurrency

??
Concurrency is advocated by scaling individual processes.

Disposability

Fast startup and shutdown support a robust and resilient system.

Dev/Prod Parity

All environments should be as similar as possible.

Logs

Applications should produce logs as event streams and leave aggregation to the execution environment.

Admin Processes

Admin tasks should be included in source control and be packaged with the application.
Design Patterns

The original 23 design patterns were described by the Gang of Four: Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.

Creational Patterns
    Abstract Factory
    Builder
    Factory Method
    Prototype
    Singleton
    
Structural Patterns
    Adapter
    Bridge
    Composite
    Decorator
    Facade
    Flyweight
    Proxy
    
Behavioral Patterns
    Chain of Responsibility
    Command
    Interpreter
    Iterator
    Mediator
    Memento
    Observer
    State
    Strategy
    Template Method
    Visitor

Strategy

(similar to State)
Make algorithms interchangeable by creating an Inteface for them
Let your class reference the Interface type, so any implementation of the algorithm can be set
Allows you to easily change class behavior

State

(similar to Strategy)
Allow an object to change its behavior as its internal state changes, by changing what instance of an interface or derivation of a base class is used for an action

Observer

This is how events work
A publisher class allows any subscriber class to subscribe to its events
When an event occurs, the publisher alerts all of its subscribers

Decorator

When you have many possible versions of a class that can occur in any combination, like toppings on a pizza
Make a base class, with none of the options, and derive from it for each option
Let each derived option contain an object of the base class

Now you can wrap the base with layers of derived options, to any depth
Methods can recursively drill into the layers

Factory

Create a static factory class that will return a variety of derived types of the same base type
The factory class can handle the details of instantiating the derived classes

Abstract Factory

An extension of the Factory pattern.

When you have a family of related objects, and there is more than one level of categorization for the objects, you can create a factory for each level and let the client use any of them.


//products
public abstract class DisplayLanguage {...}
public abstract class English : DisplayLanguage {...}
public abstract class Japanese : DisplayLanguage {...}
public class Roman : English {...} //normal english
public class Brail : English {...} //brail encoded english
public class Kanji : Japanese {...} //logographic chinese characters
public class Hiragana : Japanese {...} //phonetic characters

//factories
public abstract class DisplayLanguageFactory 
{ 
    public DisplayLanguage Create(); 
}

public class EnglishFactory : DisplayLanguageFactory
{
    public English Create()
    {
        //can return Roman or Brail object
    }
}

public class JapaneseFactory : DisplayLanguageFactory
{
    public Japanese Create()
    {
        //can return Kanji or Hiragana object
    }
}

Singleton

Ensures that there will only ever be one instance of a class used throughout an entire application

C# implementation:

public class Singleton
{
    private static Singleton _instance;

    //Singleton.Instance is the only way to retrieve an instance of a Singleton
    public static Singleton Instance {
        get {
            if(_instance == null)
            {
                _instance = new Singleton();
            }
            return _instance;
        }
    }

    //private constructor
    private Singleton()
    {
    }
}

Command

Encapsulates a request as an object, so that you can pass, queue, log, undo, or redo it
Decouples the requestor of an action from the object that performs the action

Adapter

(similar to Facade)
A layer between a client API and your own code
So your code all references the adapter, and only the adapter references 3rd party code
This protects most of your code from changes in the 3rd party code

Facade

(similar to Adapter)
Create a single interface between your code and all 3rd party code
Your code will see a single object in the place of a myriad of client interfaces

Proxy

An adapter whose purpose is to either limit access to some operations of the original class, or to control when expensive operations are run

Template Method

Defines an order of operations, while letting the details of each step by variable


public abstract class TemplateExample
{
    public void TemplateMethod()
    {
        Step1();
        Step2();
        Step3();
    }
    
    public virtual void Step1() {}
    public virtual void Step2() {}
    public virtual void Step3() {}
}

Iterator

Access the elements of an aggregate object sequentially, without exposing its underlying representation

Composite

An individual object and a collection of those objects are treated uniformally

For example, modeling a folder and file tree

Memento

Allows you to save the state of an object, perhaps to restore the state later

Specification

Allows business rules to be combined by chaining them together with business logic.


interface ISpecification
{
    bool IsSatisfiedBy(object candidate);
    ISpecification And(ISpecification other);
    ISpecification Or(ISpecification other);
    //other logical operators...
}

abstract class CompositeSpecification : ISpecification
{
    public abstract bool IsSatisfiedBy(object candidate);
    
    public ISpecification And(ISpecification other)
    {
        return new AndSpecification(this, other);
    }
    
    public ISpecification Or(ISpecification other)
    {
        return new OrSpecification(this, other);
    }
}

public class AndSpecification : CompositeSpecification
{
    private ISpecification leftCondition;
    private ISpecification rightCondition;
    
    public AndSpecification(ISpecification left, ISpecification right)
    {
        leftCondition = left;
        rightCondition = right;
    }
    
    public override bool IsSatisfiedBy(object candidate)
    {
        return (leftCondition.IsSatisfiedBy(candidate) && rightCondition.IsSatisfiedBy(candidate));
    }
}

//OrSpecification class...

//sample business rule
public class IsAdminSpecification : CompositeSpecification
{
    public bool IsSatisfiedBy(object candidate)
    {
        return ((candidate is User) && (candidate as User).Type == "Admin");
    }
}

Bridge

You have two or more categories that combine to create an exponential number of possibilities. Each unique combination has a different implementation. A basic inheritance hierarchy gets out of hand fast.

The Bridge pattern divides this into an interface hierarchy and an implementation hierarchy.

Bridge is similar to Adapter pattern. The difference is that Bridge is designed upfront to allow abstraction and implementation to vary independently, while Adapter is retrofitted to let unrelated classes work together.

Ex: 2 types of thread scheduler X 3 software platforms

Basic hierarchy

class ThreadScheduler { ... }

class PreemptiveThreadScheduler : ThreadScheduler { ... }
class TimeSlicedThreadScheduler : ThreadScheduler { ... }

class UnixPTS : PreemptiveThreadScheduler { ... }
class WindowsPTS : PreemptiveThreadScheduler { ... }
class JavaVirtualMachinePTS : PreemptiveThreadScheduler { ... }

class UnixTSTS : TimeSlicedThreadScheduler { ... }
class WindowsTSTS : TimeSlicedThreadScheduler { ... }
class JavaVirtualMachineTSTS : TimeSlicedThreadScheduler { ... }

Bridge hierarchy:

interface IThreadScheduler
{
    IPlatform platform;
    void CallMethodA();
    void CallMethodB();
}

class PreemptiveThreadScheduler : IThreadScheduler
{
    public PreemptiveThreadScheduler(IPlatform p)
    {
        platform = p;
    }
    public void CallMethodA()
    {
        platform.MethodA();
    }
    public void CallMethodB()
    {
        platform.MethodB();
    }
}

//class TimeSlicedThreadScheduler ...

interface IPlatform
{
    void MethodA();
    void MethodB();
}

class UnixPlatform : IPlatform
{
    public void MethodA() { ... }
    public void MethodB() { ... }
}

//class WindowsPlatform ...

//class JavaVirtualMachinePlatform ...

Hardware example:
    IToggle can be a wall switch, a pull chain, a light sensor, etc
    IDevice can be a lamp, a radio, a tv, etc
    
Flyweight

You have a very large number of expensive objects. Break the objects into two parts: the expensive shared part, and the cheap variable part.

The flyweight contains the expensive part.
The lightweight parts are removed entirely; they are handled by the client.


public class Factory
{
    private List<Flyweight> repository;
    //returns a shared object
    public Flyweight GetFlyweight();
}

public class Flyweight
{
    //private expensive stuff
    
    //public methods accept the lightweight variable parts as arguments
}

The client calls getFlyweight(). When the client needs something specific, it passes specifics to the flyweight methods. The flyweight combines its shared expensive data with the lightweight variable data from the client to perform operations.

Ex: a webpage loads images, which are memory-intensive
    when an image is shown multiple times on the same page (such as with a tiled background) then you have one Flyweight for the shared image and a list of locations
    
Builder

Separate the construction of a complex object from its representation. The same construction process can create different representations.

This can solve at least two types of problems.

1) It's a response to the Telescoping Constructor Anti-pattern - when the increase of combinations of object constructor parameters leads to an exponential number of constructors. Instead, the Builder receives each parameter linearly and returns one final object.

2) Used to create flat data objects (xml, sql, ...) where the final product is not easily edited. The builder keeps it in an easy to edit format until you are done, then generates the final format.

Builders are good candidate for fluent interfaces due to the linear input of options.


//problem 1
public class Director
{
    private Builder builder;
    
    public void Construct()
    {
        builder.BuildPart();
    }
}

public class Builder
{
    public void AddOptionA() { ... }
    public void AddOptionB() { ... }
    public void AddOptionC() { ... }
    public Result GetResult() { ... }
}


//problem 2
public class Director
{
    private Builder builder;
    
    public void Construct()
    {
        builder.BuildPart();
    }
}

public abstract class Builder
{
    public void BuildPart();
}

public class XmlBuilder : Builder
{
    public void BuildPart() { ... }
    public Xml GetResult() { ... }
}

public class JsonBuilder : Builder
{
    public void BuildPart() { ... }
    public Json GetResult() { ... }
}

Prototype

Initiate an object with default values, clone it repeatedly. The prototype could be a concrete object or an abstract object.

Chain Of Responsibility

Avoid coupling of the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

Marker Interface

Aka Tagging Interface

Requires a language with run-time type information available about objects. This is a means to associate metadata with a class in languages without that explicit support.

Create an empty interface.
The code tests for the presence of the interface on an object at decision points.


if(myObject is IEmptyInterface) { ... }

This is unnecessary in C# and Java, which both support Annotations (Custom Attributes).

Pipes And Filters

A pipeline is a chain of processing elements where the output of element N is the input of element N+1.

Connecting elements into a pipeline is analogous to Function Composition (combining simple functions into more complicated operations).

Linux operations like Grep, Sed, and Awk are designed to be used this way.

Compound Patterns

Larger design patterns made up of several basic patterns

Model View Controller

Separation of duties

Model: the actual data
View: a particular way of looking at the data, possibly a summary
Controller: handles user actions and updates Model and View as needed
Analysis Patterns

From Martin Fowler's "Analysis Patterns" on the conceptual structure of business processes that are applicable to many domains because they share the similarities of being businesses.

These notes are a first sketch of the concepts.

Accountability

When one party or organization is responsible to another. Applicable to organizational structure, contracts, employment, etc.

Party: an individual or an organization. A group of any size that acts as a whole.
    E.g. a Party can have a phone number, address, email, bank accounts, taxes, etc
    
Organization Hierarchy

//Business model
Sales Offices report to Divisions report to Regions report to Operating Unit

//Object model
public abstract class Organization //or interface Organization
{
    Organization parent;
    List<Organization> subsidiaries;
}

class OperatingUnit : Organization { ... } //parent must remain null
classs Region : Organization { ... } //parent must be an OperatingUnit
class Division : Organization { ... } //parent must be a Region
class SalesOffice : Organization { ... } //parent must be a Division

Often there are two more overlapping hiearchies within one organization. You can track both hiearchies in one object, or break them into entirely different objects.

public abstract class Organization
{
    Organization salesParent;
    List<Organization> salesSubsidiaries;
    
    Organization productParent;
    List<Organization> productSubsidiaries;
}
Exception Handling Patterns

[source: Exception handling patterns]

Considerations

Throwing an exception is a control structure (like if or goto) in the sense that it causes control of the program to shift, sometimes dramatically. The method throwing the exception has no information about where control will return to.

Throwing an exception is a very slow operation, comparatively. It should be used sparingly.

In general, do not use exceptions as intentional flow control. And throw exceptions as little as possible.

Naming Exceptions

Describe the problem, why is the exception being thrown.

Use a standard naming format. Do not create both "XNotFoundException" and "NoSuchYException" in the same project.

Do not make exception specific to a class.
If you see the exception hierarchy closely matching your class hierarchy, you are probably not generalizing your exceptions by behavior enough.

Example:
Consider ArrayIndexOutOfBoundsException => IndexOutOfBoundsException => RangeException. The first is specific to arrays only, the last is general to many situations.

Example:
ClassNotFoundException, MethodNotFoundException, and FieldNotFoundException could all be generalized to MissingException. When the exception occurs, the context it occurs in will fill in the rest of the details.

Example:
It does not make sense to name a field in class Person "PersonFirstName". You simply call it "FirstName" because it being within class Person provides context.
Similarly, the code that catches an exception will know a lot about the context of the exception based on what operation was just attempted.

Some major categories of exceptions are:
- logical errors in the program (for example, the program is in an impossible state)
- resource failures (for example, a file cannot be read)
- user errors (for example, the user input is poorly formatted)
- configuration errors (for example, invalid configuration)

Refine Exceptions

When you start creating exceptions types for your project, begin with general categories. For instance, you could start with a single Exception class named for your project that all other exceptions you throw will derive from.

As work continues and you find places where a more specific exception makes sense, create sub classes.

Consider how users of your service will want to group exceptions together to catch them.

When To Raise Exceptions

In general, exceptions should only be raised for exceptional (unusual) conditions. The normal operation of a method should not rely on exceptions.

When to raise exceptions:
- your method encounters unusual conditions it cannot handle
- a client service has breached its obligations (such as passing badly formatted data)
- your method cannot fulfill its obligations

Make sure to always "clean up" before throwing an exception.
For instance, release all locks on files and close all database connections.
For instance, leave the current object in a consistent state, not a partially altered state. Satisfying this condition leads you to putting all validations steps first (anything that could produce an exception) and all data altering steps last.

When To Catch Exceptions

Exceptions do not have to be caught right away. Only catch the exception in methods that have enough information and options to do something about the problem.

Seeing many "try/catch" pairs throughout your code may mean that you need to refactor out some of that logic. It may be serving little purpose, while cluttering the code.

On the other hand, don't let the exception propagate so high up that the context of the exception is lost.

In general, do not write "catch(Exception e) { }", which will catch any exception type at all. Find out what specific exceptions could occur during an operation, and then catch them specifically.

Converting Exceptions

If a service you are using (or a layer of your own project that might as well be a service)
throws a variety of detailed exceptions, it often makes sense to convert those lower-level
or third-party exceptions into the exceptions of the current layer.

Information from the lower level exception can be included in the higher level exception when it is appropriate.

Example:
Lower level message IOException("Disk is full") may be converted to a higher level DataException("Cannot save customer record: Disk is full.")

Security Door Pattern

You have an operation that will be used internally and from clients.

Make one private method that does the operation. It assumes that all necessary validations, data formatting checks, etc have already been done. You can use this method internally.

Make one public method that runs validations, data formatting checks, etc and only calls the private method if everything checks out. Clients will use this method.

Bouncer Pattern

A method that will either throw an exception or do nothing. This is the same pattern as an Assert statement, and is frequently used for validation.

Benefits are reuse of code (if it will be called from many places) and self-documentation (if called from few places). The name of the bouncer method describes its purpose.


private void ValidateFormat(string text, string detailForMessage)
{
    if(notFormattedRight(text))
        throw new FormatException("message" + detailForMessage);
}

Alternatives To Exceptions

Error Avoidance: check conditions before trying an operation.
For example, check if a value is 0 before dividing by that value.
For example, check how much money is in a customer's account before withdrawing money.
There are many reasons you should not always do this: primarily duplication of logic, and the conditions may change between checking and executing.

Null Object: a object of the expected type that contains no data. All normal operations work on the NullObject, so it will not cause "null exceptions" to be thrown.
This is usually implemented as a Singleton pattern, ensuring that all instances of the NullObject are the same object, so it is easy to check if what you have is the NullObject.

Error Values: return a special value indicating an error occurred. This is useful in cases where the error is minor and can be ignored.
This can be much easier to unit test than exceptions.
This can also encourage nested if statements, which is bad.

Pass Error Handler: pass an error handler method into the method that might need it.
This can be much easier to unit test, because the error handling code is already in its own method.

Use Assertions: cause the program to fail until the problem is solved by a person. This is for errors that the program absolutely cannot handle.

Bottom Propagation: a special value that does not cause errors when operated on, but also generally does not change value when operated on. This does imply that anything is really wrong, just that a edge has been hit.
Similar to NullObject.