https://github.com/jferrl/ecommerce-kata
Tell dont ask kata
https://github.com/jferrl/ecommerce-kata
Last synced: about 1 year ago
JSON representation
Tell dont ask kata
- Host: GitHub
- URL: https://github.com/jferrl/ecommerce-kata
- Owner: jferrl
- License: mit
- Created: 2025-04-08T14:05:56.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-04-08T14:14:30.000Z (about 1 year ago)
- Last Synced: 2025-04-08T15:24:42.846Z (about 1 year ago)
- Language: Go
- Size: 6.84 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Go Refactoring Workshop: Tell Don't Ask, Rich Domain Models & Deep Modules
This repository demonstrates the application of key software design principles through a practical refactoring exercise of a Go e-commerce application.
## 🎯 Learning Goals
This workshop focuses on three important software design principles:
1. **Tell, Don't Ask**
A principle that encourages telling objects what to do rather than asking them for data and making decisions outside. This reduces coupling and improves encapsulation.
2. **Rich Domain Models (vs. Anemic Domain Models)**
Moving beyond data-only objects toward entities that encapsulate both data and behavior, enforcing their own business rules and invariants.
3. **Deep Modules**
As described in "A Philosophy of Software Design" by John Ousterhout, deep modules provide powerful functionality while hiding implementation complexity behind simple interfaces.
## 🔍 The Example: E-commerce Order System
The repository contains a simplified e-commerce order processing system with:
- Products with inventory management
- Users with payment information
- Order creation and processing
- Payment handling
## 💡 Key Refactorings Demonstrated
### Tell, Don't Ask
**Before:**
```go
// Checking conditions outside the object
if product.StockQuantity < quantity {
return errors.New("insufficient stock")
}
product.StockQuantity -= quantity
```
**After:**
```go
// Telling the object what to do
err := product.DecreaseStock(quantity)
if err != nil {
return err
}
```
### Rich Domain Model
**Before:**
```go
// Anemic domain model - just data
type Order struct {
ID string
UserID string
Items []OrderItem
TotalAmount float64
Status string
PaymentStatus string
CreatedAt time.Time
}
// Business logic in services
func (os *OrderService) ProcessOrder(orderID string) error {
// ... logic for processing order
}
```
**After:**
```go
// Rich domain model with behavior
type Order struct {
// Same fields as before
}
// Business logic in domain objects
func (o *Order) Process() error {
if o.Status != "PENDING" {
return errors.New("order already processed")
}
if o.PaymentStatus != "PAID" {
return errors.New("cannot process unpaid order")
}
o.Status = "PROCESSED"
return nil
}
```
### Deep Modules
**Before:**
- Shallow services with minimal functionality
- High coupling between services
- Implementation details exposed
**After:**
- Domain repositories that abstract storage concerns
- Meaningful interfaces that hide complexity
- Clear separation of domain and infrastructure concerns
## 🚀 How to Use This Repository
1. Start by examining the code in `before/main.go` to identify issues
2. Study the refactored implementation in the `after/` directory
3. Complete the exercises in the `exercises/` directory
4. Refer to the documentation for deeper understanding
## 📚 Further Reading
- "A Philosophy of Software Design" by John Ousterhout
- "Domain-Driven Design" by Eric Evans
- "Clean Architecture" by Robert C. Martin
## 🔗 Additional Resources
- [Tell Don't Ask Principle](https://martinfowler.com/bliki/TellDontAsk.html)
- [Anemic Domain Model](https://martinfowler.com/bliki/AnemicDomainModel.html)
- [John Ousterhout's lectures on software design](https://milkov.tech/assets/psd.pdf)
## 📋 Contributing
Feel free to submit pull requests with additional examples, exercises, or documentation improvements!