Software Engineering

Collections

You Can't Buy Integration

Don't Call Yourself A Programmer, And Other Career Advice

  • 90% of programming jobs are in creating Line of Business software.
  • Engineers are hired to create business value, not to program things.
  • Add revenue. Reduce costs. Those are your only goals.

Eight tips to Write Functions like a Senior Developer

  • Do one thing and do it well
  • Never use flag arguments
  • Prefer exceptions over error codes
  • Make separation between command and query

Architecture

  • Domain-centric Architectures (Clean and Hexagonal) for Dummies
  • BBC Online Uses Serverless to Scale Extremely Fast
  • Islands Architecture
  • HN: Modules, not microservices
    • I just want to point out that for the second problem (scalability of CPU/memory/io), microservices almost always make things worse.
    • I was working at Amazon when they started transitioning from monolith to microservices, and the big win there was locality of data and caching.
    • Microservices are less efficient, but are still more scalable.
    • I am working on a project that uses a microservice architecture to make the individual components scalable and separate the concerns. However one of the unexpected consequences is that we are now doing a lot of network calls between these microservices, and this has actually become the main speed bottleneck for our program, especially since some of these services are not even in the same data center. We are now attempting to solve this with caches and doing batch requests, but all of this created additional overhead that could have all been avoided by not using microservices.
      This experience has strongly impacted my view of microservices and for all personal projects I will develop in the future I will stick with a monolith until much later instead of starting with microservices.
  • Kernighan and Pike were right: Do one thing, and do it well
  • It's not microservice or monolith; it's cognitive load you need to understand first
    • “Instead of choosing between a monolithic architecture or a microservices architecture, design the software to fit the maximum team cognitive load”
    • If you have only one team, consider adjusting your architecture to match the team’s capacity. Favour monolithic, cohesive and modular architectures.
    • If you have multiple teams, consider doing microservices or similar type of architectures so they can work independently.
    • The types of communication boundaries change significantly between single and multiple team architectures. Single teams are optimized to communicate via the codebase, documentation, discussions and design meetings. Multiple teams are better optimized to communicate via well-designed APIs (or libraries) that abstract the complexities of their domains.

Thread-per-core

The thread-per-core architecture for Rust async programs has been controversial. While it promises better performance and ease of implementation, it may only achieve one, not both. A share-nothing approach keeps data in separate core caches but is complex to implement transactionally. Research showed this approach reduced tail latencies over a shared approach. However, the experiments did not test dynamic work imbalances that could appear in practice. Work-stealing may help address imbalances while still keeping some data pinned to cores, achieving both performance and utilization benefits. The debate focuses on balancing work-stealing with shared state rather than ease of implementation claims.

The debate isn't about thread-per-core work stealing executors, it's whether async/await is a good abstraction for it in Rust. And the more async code I write the more I feel that it's leaky and hard to program against.

Algorithms

Hexagonal Grids

This guide discusses different approaches to representing hexagonal grids in code, including cube, axial, offset, and doubled coordinates.

  • Each system has tradeoffs in terms of simplicity for algorithms and storage.
  • Axial coordinates are recommended for algorithms as they allow basic math operations.
  • Offset coordinates may be better for storage.

Approximate timing for various operations on a typical PC

execute typical instruction1/1,000,000,000 sec = 1 nanosec
fetch from L1 cache memory0.5 nanosec
branch misprediction5 nanosec
fetch from L2 cache memory7 nanosec
Mutex lock/unlock25 nanosec
fetch from main memory100 nanosec
send 2K bytes over 1Gbps network20,000 nanosec
read 1MB sequentially from memory250,000 nanosec
fetch from new disk location (seek)8,000,000 nanosec
read 1MB sequentially from disk20,000,000 nanosec
send packet US to Europe and back150 milliseconds = 150,000,000 nanosec

Crypto


Children
  1. 1x Programming
  2. Base64 Encoding, Explained
  3. Clean Architecture on Frontend
  4. Fast-Paced Multiplayer (Part II): Client-Side Prediction and Server Reconciliation
  5. Fast-Paced Multiplayer (Part III): Entity Interpolation
  6. Fast-Paced Multiplayer (Part IV): Lag Compensation
  7. Feature Sliced Design
  8. How Pinterest scaled to 11 million users with only 6 engineers
  9. In defense of simple architectures
  10. L8 Explains Career of Software Engineers
  11. Master the Art of Caching for System Design Interviews: A Complete Guide
  12. PIDs: Creating Stable Control in Games
  13. Programming as Theory Building
  14. Refactoring
  15. Services By Lifecycle
  16. The Entity Service Antipattern
  17. Tidy First? Kent Beck on Refactoring
  18. What Sets an Exceptional Programmer Apart From an Ordinary Programmer
  19. What the heck is the edge anyway?