119
architectural distributed systems

Microservices

Reference Wikipedia ↗
Microservices — deployment diagram
Plate 119 deployment diagram

Microservices is an architectural style that structures an application as a collection of loosely coupled, independently deployable services. Each service typically focuses on a specific business capability, communicates through well-defined APIs, and can be developed and scaled independently. This contrasts with monolithic applications where all functionality is bundled into a single process.

The core principle of microservices is to break down a large, complex application into smaller, manageable parts. This approach offers benefits like increased agility, improved scalability, technology diversity, and fault isolation. However, it also introduces complexities related to distributed system management, inter-service communication, and data consistency.

Usage

Microservices are commonly used in:

  • Large-scale web applications: Where independent scaling of different features is crucial (e.g., user authentication, product catalog, shopping cart).
  • E-commerce platforms: To manage separate services for ordering, payments, shipping, and inventory.
  • Streaming services: Handling video encoding, content delivery, user accounts, and recommendation engines as independent services.
  • Cloud-native applications: Leveraging the scalability and resilience of cloud platforms.
  • Continuous Delivery/Deployment (CI/CD) pipelines: Enabling faster and more frequent releases of individual services.

Examples

  • Netflix: A prime example of microservices architecture. They migrated from a monolithic application to an architecture composed of hundreds of microservices, each responsible for a specific function like user profiling, video streaming, or recommendation algorithms. This allowed them to scale efficiently and handle massive traffic.
  • Spotify: Uses microservices to manage different aspects of its music streaming service. Services handle user authentication, music catalog, search, payment processing, and social features. This allows for independent updates and scaling of each component without impacting the entire platform.
  • Amazon: Amazon’s retail platform is built on microservices. Each service handles a specific part of the shopping experience, such as product listings, order management, or customer reviews. This allows Amazon to rapidly innovate and deploy new features.
  • Uber: Utilizes microservices for core functionalities like rider matching, fare calculation, payment processing, and driver management. This architecture supports their global scale and real-time demands.

Specimens

15 implementations
Specimen 119.01 Dart View specimen ↗

The Microservices pattern structures an application as a collection of loosely coupled, independently deployable services, modeled around a business domain. Each service owns its data and communicates via lightweight mechanisms, often a RESTful API. This example demonstrates a simplified implementation with two microservices: product_service and order_service. They communicate via HTTP requests. Dart’s asynchronous capabilities (async/await) and its support for HTTP clients make it well-suited for this pattern. The use of separate functions to represent service endpoints and a simple data model keeps the code clean and focused, aligning with Dart’s emphasis on readability and maintainability.

// product_service.dart
import 'dart:convert';
import 'package:http/http.dart' as http;

class Product {
  final String id;
  final String name;
  final double price;

  Product({required this.id, required this.name, required this.price});

  factory Product.fromJson(Map<String, dynamic> json) {
    return Product(
      id: json['id'],
      name: json['name'],
      price: json['price'].toDouble(),
    );
  }
}

Future<Product> getProduct(String id) async {
  final response = await http.get(Uri.parse('http://localhost:8081/products/$id'));
  if (response.statusCode == 200) {
    return Product.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to load product');
  }
}

// order_service.dart
import 'dart:convert';
import 'package:http/http.dart' as http;

class Order {
  final String orderId;
  final String productId;
  final int quantity;

  Order({required this.orderId, required this.productId, required this.quantity});

  factory Order.fromJson(Map<String, dynamic> json) {
    return Order(
      orderId: json['orderId'],
      productId: json['productId'],
      quantity: json['quantity'],
    );
  }
}

Future<void> createOrder(Order order) async {
  final response = await http.post(
    Uri.parse('http://localhost:8082/orders'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode(order),
  );
  if (response.statusCode != 201) {
    throw Exception('Failed to create order');
  }
}

// main.dart
import 'package:microservices_dart/product_service.dart';
import 'package:microservices_dart/order_service.dart';

void main() async {
  try {
    final product = await getProduct('123');
    print('Product: ${product.name}, Price: ${product.price}');

    final order = Order(orderId: '456', productId: product.id, quantity: 2);
    await createOrder(order);
    print('Order created successfully!');
  } catch (e) {
    print('Error: $e');
  }
}