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)
One codebase tracked in revision control, many deploys 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. 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 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 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.
Strictly separate build and run stages
# Build the application mvn clean package
# Run the application java -jar target/myapp-1.0-SNAPSHOT.jar 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. 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.
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.
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.
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. Treat logs as event streams 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.