S

Single Responsibility Principle (SRP) – A class should have only one reason to be changed.

O

Open-Closed Principle (OCP) – A class should be open to extension but closed to modification

L

Liskov Substitution Principle (LSP) – You should be able to replace a class with a subclass without the calling code knowing about the change

I

Interface Segregation Principle (ISP) – Many specific interfaces are better than a single, all-encompassing interface

D

Dependency Inversion Principle (DIP) – Code should depend upon abstractions, not concrete implementations

 

 

The Twelve-Factor App (12factor.net)

 

I. Codebase

One codebase tracked in revision control, many deploys

II. Dependencies

Explicitly declare and isolate dependencies

A twelve-factor app never relies on implicit existence of system-wide packages.

 

 You do not assume that certain libraries or packages are already installed on the system where the application will be deployed. Instead, you include all necessary dependencies within the application's deployment package.

Instead, you include all necessary dependencies in your project configuration and manage them using a dependency management tool like Maven or Gradle.

III. Config

Store config in the environment

In a Java application, you might have configuration properties such as database connection settings, API keys, or other environment-specific variables. Instead of hardcoding these values directly into your code, you can store them as environment variables.


public class AppConfig {

    public static void main(String[] args) {

        String databaseUrl = System.getenv("DATABASE_URL");

        String apiKey = System.getenv("API_KEY");

 

    }

}

export DATABASE_URL=jdbc:mysql://localhost:3306/mydatabase

export API_KEY=your-api-key

IV. Backing services

Treat backing services as attached resources

 

Backing Services, suggests treating backing services, such as databases, caches, or message queues, as attached resources. This means that your application should interact with these services over the network and treat them as external resources. By doing so, you can easily swap out or scale these services independently of your application.


deploy of the twelve-factor app should be able to swap out a local MySQL database with one managed by a third party (such as Amazon RDS) without any changes to the app’s code. Likewise, a local SMTP server could be swapped with a third-party SMTP service without code changes.

V. Build, release, run

Strictly separate build and run stages

 

# Build the application

mvn clean package

 

# Run the application

java -jar target/myapp-1.0-SNAPSHOT.jar

VI. Processes

Execute the app as one or more stateless processes

 

The sixth factor, Processes, suggests executing your application as one or more stateless processes. This means that your application should be designed to run as independent, stateless processes that can be scaled horizontally. By avoiding statefulness, you can easily scale your application by adding more processes and distributing the load.

 

The twelve-factor app never assumes that anything cached in memory or on disk will be available on a future request or job. Even when running only one process, a restart will usually wipe out all local state. Sticky sessions are a violation of twelve-factor and should never be used or relied upon. Session state data is a good candidate for a datastore that offers time-expiration, such as Memcached or Redis

 

In Java, you can design stateless processes by following principles such as:

 

Avoid storing session state in the application server. Instead, use session management techniques like tokens or cookies to maintain user sessions.

Utilize distributed caching mechanisms like Redis or Memcached to store shared data that can be accessed by multiple processes.

Design the application to be horizontally scalable, where multiple instances of the application can be deployed and load-balanced to handle incoming requests.

VII. Port binding

Export services via port binding

The twelve-factor app is completely self-contained and does not rely on runtime injection of a webserver

Instead of relying on a pre-configured web server provided by the runtime environment (e.g., Apache HTTP Server or Nginx), the twelve-factor app bundles its own web server component and binds it to a port to serve HTTP requests.

 

VIII. Concurrency

Scale out via the process model

 

Concurrency, emphasizes scaling out via the process model. This means that the application should be designed to handle concurrency by scaling out horizontally, where multiple instances of the application can run simultaneously to handle concurrent requests. By adopting a concurrent model, the application can effectively utilize available resources and improve performance.

 

IX. Disposability

Maximize robustness with fast startup and graceful shutdown

 

Processes should also be robust against sudden death.

Processes shut down gracefully when they receive a SIGTERM signal from the process manager. 

The ninth factor, Disposability, emphasizes maximizing robustness with fast startup and graceful shutdown. This means that the application should be designed to start up quickly and gracefully shut down when necessary.

 

In Java, you can achieve fast startup and graceful shutdown by following practices such as:

·        Minimize the application's startup time by optimizing dependencies, reducing initialization steps, and utilizing caching mechanisms.

·        Implement proper error handling and recovery mechanisms to gracefully handle failures and shutdowns.

·        Utilize containerization technologies like Docker to package the application and its dependencies, allowing for easy deployment and scaling.


X. Dev/prod parity

 

Keep development, staging, and production as similar as possible

Keep as small as possible on time gap, personnel gap and tools gap.

Using the same versions of libraries, frameworks, and dependencies in all environments.

Replicating the production environment's infrastructure, such as databases, caching systems, and message queues, in the development and staging environments.

Automating the deployment process to ensure consistency and reduce the chance of human error.

XI. Logs

Treat logs as event streams

XII. Admin processes

Run admin/management tasks as one-off processes

 

This means that administrative or management tasks, such as database migrations, backups, or system maintenance, should be executed as separate, one-off processes rather than being bundled with the application code. By separating admin processes, you can ensure that they don't interfere with the normal operation of the application and can be easily managed and monitored.

 

 

Legacy procedural programming are following speheti coding style

Object oriented programming

Bad method

Object oriented Encapsulation

Abstraction. Expose the relevant properties and methods only

Inheritance : eliminate redundant code

is a relation

manager is an employee

car is a vehicle

 

 

Encapsulation : We group related variables and functions together

Abstraction : We hide the details and complexity and show only the essentials


https://youtu.be/3FP1XbVVn0M?t=610

 


 

 

 

 

 

 


// 4. Interface Segregation Principle (ISP)

//  bad example

interface Worker {
   
void work();
   
void eat();
}

class Human implements Worker {
   
public void work() {
       
System.out.println("Human working");
    }

   
public void eat() {
       
System.out.println("Human eating");
    }
}

class Robot implements Worker {
   
public void work() {
       
System.out.println("Robot working");
    }

   
public void eat() {
       
// Unnecessary implementation for a Robot
   
}
}

 

// 4. Interface Segregation Principle (ISP)
// good example

interface Workable {
   
void work();
}

interface Eatable {
   
void eat();
}

class Human implements Workable, Eatable {
   
public void work() {
       
System.out.println("Human working");
    }

   
public void eat() {
       
System.out.println("Human eating");
    }
}

class Robot implements Workable {
   
public void work() {
       
System.out.println("Robot working");
    }
}

 


// 5. Dependency Inversion Principle (DIP)
//  bad example

class MechanicalKeyboard {
   
public void type() {
       
System.out.println("Typing on mechanical keyboard");
    }
}

class Computer {
   
private MechanicalKeyboard keyboard;

   
public Computer() {
       
this.keyboard = new MechanicalKeyboard();
    }

   
public void type() {
       
keyboard.type();
    }
}


// 5. Dependency Inversion Principle (DIP)
//  good example

interface Keyboard {
   
void type();
}

class MechanicalKeyboard implements Keyboard {
   
public void type() {
       
System.out.println("Typing on mechanical keyboard");
    }
}

class Computer {
   
private Keyboard keyboard;

   
public Computer(Keyboard keyboard) {
       
this.keyboard = keyboard;
    }

   
public void type() {
       
keyboard.type();
    }
}

// Now, the Computer class depends on the Keyboard interface rather than a specific implementation.
// This allows you to change the keyboard type easily without modifying the Computer class,
// adhering to the Dependency Inversion Principle.