From d6246545d7bc8ffe4ac3057fb8a583b4b4ff8601 Mon Sep 17 00:00:00 2001 From: Stephanie Gredell Date: Tue, 3 Jun 2025 12:13:30 -0700 Subject: [PATCH] initial commit --- cost.py | 315 +++++++++ game.html | 765 ++++++++++++++++++++ internals/simulation/simulation.go | 286 ++++++++ main.go | 144 +--- old.html | 1051 ++++++++++++++++++++++++++++ static/index.html | 1047 +++++++++++++++++++++++++++ 6 files changed, 3493 insertions(+), 115 deletions(-) create mode 100644 cost.py create mode 100644 game.html create mode 100644 internals/simulation/simulation.go create mode 100644 old.html create mode 100644 static/index.html diff --git a/cost.py b/cost.py new file mode 100644 index 0000000..590c99e --- /dev/null +++ b/cost.py @@ -0,0 +1,315 @@ +from typing import NamedTuple, Dict, Tuple +from enum import Enum + + +class LoadBalancerSpec(NamedTuple): + capacity: float # e.g. float('inf') + baseLatency: int # ms + cost: int + + +class WebServerSmall(NamedTuple): + capacity: int + baseLatency: int + penaltyPerRPS: float + cost: int + + +class WebServerMedium(NamedTuple): + capacity: int + baseLatency: int + penaltyPerRPS: float + cost: int + + +class CacheStandard(NamedTuple): + capacity: int + baseLatency: int + penaltyPer10RPS: float + hitRates: Dict[str, float] + cost: int + + +class CacheLarge(NamedTuple): + capacity: int + baseLatency: int + penaltyPer10RPS: float + hitRates: Dict[str, float] + cost: int + + +class DbReadReplica(NamedTuple): + readCapacity: int # RPS + baseReadLatency: int # ms + penaltyPer10RPS: float + cost: int + + +class ComponentSpec(NamedTuple): + loadBalancer: LoadBalancerSpec + webServerSmall: WebServerSmall + webServerMedium: WebServerMedium + cacheStandard: CacheStandard + cacheLarge: CacheLarge + dbReadReplica: DbReadReplica + + +class Design(NamedTuple): + numWebServerSmall: int + numWebServerMedium: int + cacheType: str # Either "cacheStandard" or "cacheLarge" + cacheTTL: str + numDbReplicas: int + promotionDelaySeconds: int + + +class Level(NamedTuple): + id: int + description: str + targetRPS: int + maxP95Latency: int + maxMonthlyCost: int + requiredAvailability: int + failureEvents: list + componentSpec: ComponentSpec + simulatedDurationSeconds: int + + +class CacheType(Enum): + STANDARD = "cacheStandard" + LARGE = "cacheLarge" + + +class LevelSimulator: + def __init__(self, level: Level, design: Design): + self.level = level + self.design = design + self.specs = self.level.componentSpec + + def compute_cost(self) -> int: + s = self.specs + d = self.design + + cost_lb = s.loadBalancer.cost + cost_ws_small = d.numWebServerSmall * s.webServerSmall.cost + cost_ws_medium = d.numWebServerMedium * s.webServerMedium.cost + + if d.cacheType == CacheType.STANDARD.value: + cost_cache = s.cacheStandard.cost + else: + cost_cache = s.cacheLarge.cost + + # “1” here stands for the master; add d.numDbReplicas for replicas + cost_db = s.dbReadReplica.cost * (1 + d.numDbReplicas) + + return cost_lb + cost_ws_small + cost_ws_medium + cost_cache + cost_db + + def compute_rps(self) -> Tuple[float, float]: + """ + Returns (hits_rps, misses_rps) for a read workload of size level.targetRPS. + """ + s = self.specs + d = self.design + + total_rps = self.level.targetRPS + + if d.cacheType == CacheType.STANDARD.value: + hit_rate = s.cacheStandard.hitRates[d.cacheTTL] + else: + hit_rate = s.cacheLarge.hitRates[d.cacheTTL] + + hits_rps = total_rps * hit_rate + misses_rps = total_rps * (1 - hit_rate) + return hits_rps, misses_rps + + def compute_latencies(self) -> Dict[str, float]: + """ + Computes: + - L95_ws (worst P95 among small/medium, given misses_rps) + - L95_cache (baseLatency) + - L95_db_read (based on misses_rps and replicas) + - L95_total_read = miss_path (since misses are slower) + """ + s = self.specs + d = self.design + + # 1) First compute hits/misses + _, misses_rps = self.compute_rps() + + # 2) Web server P95 + cap_small = s.webServerSmall.capacity + cap_medium = s.webServerMedium.capacity + + weighted_count = d.numWebServerSmall + (2 * d.numWebServerMedium) + + if weighted_count == 0: + L95_ws = float("inf") + else: + load_per_weighted = misses_rps / weighted_count + + L95_ws_small = 0.0 + if d.numWebServerSmall > 0: + if load_per_weighted <= cap_small: + L95_ws_small = s.webServerSmall.baseLatency + else: + L95_ws_small = ( + s.webServerSmall.baseLatency + + s.webServerSmall.penaltyPerRPS + * (load_per_weighted - cap_small) + ) + + L95_ws_medium = 0.0 + # <<== FIXED: change “> 00” to “> 0” + if d.numWebServerMedium > 0: + if load_per_weighted <= cap_medium: + L95_ws_medium = s.webServerMedium.baseLatency + else: + L95_ws_medium = ( + s.webServerMedium.baseLatency + + s.webServerMedium.penaltyPerRPS + * (load_per_weighted - cap_medium) + ) + + L95_ws = max(L95_ws_small, L95_ws_medium) + + # 3) Cache P95 + if d.cacheType == CacheType.STANDARD.value: + L95_cache = s.cacheStandard.baseLatency + else: + L95_cache = s.cacheLarge.baseLatency + + # 4) DB read P95 + read_cap = s.dbReadReplica.readCapacity + base_read_lat = s.dbReadReplica.baseReadLatency + pen_per10 = s.dbReadReplica.penaltyPer10RPS + + num_reps = d.numDbReplicas + if num_reps == 0: + if misses_rps <= read_cap: + L95_db_read = base_read_lat + else: + excess = misses_rps - read_cap + L95_db_read = base_read_lat + pen_per10 * (excess / 10.0) + else: + load_per_rep = misses_rps / num_reps + if load_per_rep <= read_cap: + L95_db_read = base_read_lat + else: + excess = load_per_rep - read_cap + L95_db_read = base_read_lat + pen_per10 * (excess / 10.0) + + # 5) End-to-end P95 read = miss_path + L_lb = s.loadBalancer.baseLatency + miss_path = L_lb + L95_ws + L95_db_read + L95_total_read = miss_path + + return { + "L95_ws": L95_ws, + "L95_cache": L95_cache, + "L95_db_read": L95_db_read, + "L95_total_read": L95_total_read, + } + def compute_availability(self) -> float: + """ + If failureEvents=[], just return 100.0. + Otherwise: + - For each failure (e.g. DB master crash at t_crash), + if numDbReplicas==0 → downtime = sim_duration - t_crash + else if design has auto_failover: + downtime = failover_delay + else: + downtime = sim_duration - t_crash + - availability = (sim_duration - total_downtime) / sim_duration * 100 + """ + sim_duration = self.level.simulatedDurationSeconds # you’d need this field + total_downtime = 0 + for event in self.level.failureEvents: + t_crash = event["time"] + if event["type"] == "DB_MASTER_CRASH": + if self.design.numDbReplicas == 0: + total_downtime += (sim_duration - t_crash) + else: + # assume a fixed promotion delay (e.g. 5s) + delay = self.design.promotionDelaySeconds + total_downtime += delay + # (handle other event types if needed) + return (sim_duration - total_downtime) / sim_duration * 100 + + def validate(self) -> dict: + """ + 1) Cost check + 2) Throughput checks (cache, DB, WS) + 3) Latency check + 4) Availability check (if there are failureEvents) + Return { "pass": True, "metrics": {...} } or { "pass": False, "reason": "..." }. + """ + total_cost = self.compute_cost() + if total_cost > self.level.maxMonthlyCost: + return { "pass": False, "reason": f"Budget ${total_cost} > ${self.level.maxMonthlyCost}" } + + hits_rps, misses_rps = self.compute_rps() + + # Cache capacity + cache_cap = ( + self.specs.cacheStandard.capacity + if self.design.cacheType == CacheType.STANDARD.value + else self.specs.cacheLarge.capacity + ) + if hits_rps > cache_cap: + return { "pass": False, "reason": f"Cache overloaded ({hits_rps:.1f} RPS > {cache_cap})" } + + # DB capacity + db_cap = self.specs.dbReadReplica.readCapacity + if self.design.numDbReplicas == 0: + if misses_rps > db_cap: + return { "pass": False, "reason": f"DB overloaded ({misses_rps:.1f} RPS > {db_cap})" } + else: + per_rep = misses_rps / self.design.numDbReplicas + if per_rep > db_cap: + return { + "pass": False, + "reason": f"DB replicas overloaded ({per_rep:.1f} RPS/replica > {db_cap})" + } + + # WS capacity + total_ws_cap = ( + self.design.numWebServerSmall * self.specs.webServerSmall.capacity + + self.design.numWebServerMedium * self.specs.webServerMedium.capacity + ) + if misses_rps > total_ws_cap: + return { + "pass": False, + "reason": f"Web servers overloaded ({misses_rps:.1f} RPS > {total_ws_cap})" + } + + # Latency + lat = self.compute_latencies() + if lat["L95_total_read"] > self.level.maxP95Latency: + return { + "pass": False, + "reason": f"P95 too high ({lat['L95_total_read']:.1f} ms > {self.level.maxP95Latency} ms)" + } + + # Availability (only if failureEvents is nonempty) + availability = 100.0 + if self.level.failureEvents: + availability = self.compute_availability() + if availability < self.level.requiredAvailability: + return { + "pass": False, + "reason": f"Availability too low ({availability:.1f}% < " + f"{self.level.requiredAvailability}%)" + } + + # If we reach here, all checks passed + return { + "pass": True, + "metrics": { + "cost": total_cost, + "p95": lat["L95_total_read"], + "achievedRPS": self.level.targetRPS, + "availability": ( + 100.0 if not self.level.failureEvents else availability + ) + } + } diff --git a/game.html b/game.html new file mode 100644 index 0000000..8302862 --- /dev/null +++ b/game.html @@ -0,0 +1,765 @@ + + + + + + System Design Canvas Game + + + +
+
+
Level Constraints
+
🎯 Target RPS:
+
⏱️ Max P95 Latency:
+
💸 Max Cost:
+
🔒 Availability:
+
+ +
+
Simulation Results
+
✅ Cost:
+
⚡ P95 Latency:
+
📈 Achieved RPS:
+
🛡️ Availability:
+
+
+ + +
+ + + + + + + +
+

Node Properties

+
+ +
+
+ +
+
+ +
+ +
+
+ + + + + diff --git a/internals/simulation/simulation.go b/internals/simulation/simulation.go new file mode 100644 index 0000000..290e31f --- /dev/null +++ b/internals/simulation/simulation.go @@ -0,0 +1,286 @@ +package simulation + +import ( + "math" +) + +type LoadBalancerSpec struct { + Capacity float64 + BaseLatency int + Cost int +} + +type WebServerSmall struct { + Capacity int + BaseLatency int + PenaltyPerRPS float64 + Cost int +} + +type WebServerMedium struct { + Capacity int + BaseLatency int + PenaltyPerRPS float64 + Cost int +} + +type CacheStandard struct { + Capacity int + BaseLatency int + PenaltyPer10RPS float64 + HitRates map[string]float64 + Cost int +} + +type CacheLarge struct { + Capacity int + BaseLatency int + PenaltyPer10RPS float64 + HitRates map[string]float64 + Cost int +} + +type DbReadReplica struct { + ReadCapacity int // RPS + BaseReadLatency int // ms + PenaltyPer10RPS float64 + Cost int +} + +type ComponentSpec struct { + LoadBalancer LoadBalancerSpec + WebServerSmall WebServerSmall + WebServerMedium WebServerMedium + CacheStandard CacheStandard + CacheLarge CacheLarge + DbReadReplica DbReadReplica +} + +type Design struct { + NumWebServerSmall int + NumWebServerMedium int + CacheType CacheType // Enum (see below) + CacheTTL string + NumDbReplicas int + PromotionDelaySeconds int +} + +type FailureEvent struct { + Type string + Time int +} +type Level struct { + ID int + Description string + TargetRPS int + MaxP95Latency int + MaxMonthlyCost int + RequiredAvailability int + FailureEvents []FailureEvent + ComponentSpec ComponentSpec + SimulatedDurationSeconds int +} + +type Metrics struct { + Cost int `json:"cost"` + P95 float64 `json:"p95"` + AchievedRPS int `json:"achievedRPS"` + Availability float64 `json:"availability"` +} + +type EvaluationResult struct { + Pass bool `json:"pass"` + Metrics Metrics `json:"metrics"` +} + +type Latencies struct { + L95WS float64 + L95Cache float64 + L95DBRead float64 + L95TotalRead float64 +} + +type ValidationMetrics struct { + Cost int + P95 float64 + AchievedRPS int + Availability float64 +} +type ValidationResults struct { + Pass bool + Reason *string + Metrics *ValidationMetrics +} + +type CacheType string + +const ( + CacheStandardType CacheType = "cacheStandard" + CacheLargeType CacheType = "cacheLarge" +) + +type LevelSimulator struct { + Level Level + Design Design + Specs ComponentSpec +} + +func (ls *LevelSimulator) ComputeCost() int { + s := ls.Specs + d := ls.Design + + costLb := s.LoadBalancer.Cost + costWSSmall := d.NumWebServerSmall * s.WebServerSmall.Cost + costWSMedium := d.NumWebServerMedium * s.WebServerSmall.Cost + var costCache int + + if d.CacheType == CacheStandardType { + costCache = s.CacheStandard.Cost + } else { + costCache = s.CacheLarge.Cost + } + + costDB := s.DbReadReplica.Cost * (1 + d.NumDbReplicas) + + return costLb + costWSSmall + costWSMedium + costCache + costDB +} + +func (ls *LevelSimulator) ComputeRPS() (float64, float64) { + s := ls.Specs + d := ls.Design + l := ls.Level + + totalRPS := l.TargetRPS + + var hitRate float64 + if d.CacheType == CacheStandardType { + hitRate = s.CacheStandard.HitRates[d.CacheTTL] + } else if d.CacheType == CacheLargeType { + hitRate = s.CacheLarge.HitRates[d.CacheTTL] + } else { + hitRate = 0.0 + } + + hitRPS := float64(totalRPS) * hitRate + missesRPS := float64(totalRPS) * (1 - hitRate) + return hitRPS, missesRPS +} + +func (ls *LevelSimulator) ComputeLatencies() Latencies { + s := ls.Specs + d := ls.Design + + _, missesRPS := ls.ComputeRPS() + + capSmall := s.WebServerSmall.Capacity + capMedium := s.WebServerMedium.Capacity + + weightedCount := d.NumWebServerSmall + (2 * d.NumWebServerSmall) + + var L95WS float64 + if weightedCount == 0 { + L95WS = math.Inf(1) + } else { + loadPerWeighted := missesRPS / float64(weightedCount) + + L95WSSmall := 0.0 + if d.NumWebServerSmall > 0 { + if loadPerWeighted <= float64(capSmall) { + L95WSSmall = float64(s.WebServerSmall.BaseLatency) + } else { + L95WSSmall = (float64(s.WebServerSmall.BaseLatency) + s.WebServerSmall.PenaltyPerRPS*(loadPerWeighted-float64(capSmall))) + } + } + + L95WSMedium := 0.0 + if d.NumWebServerMedium > 0 { + if loadPerWeighted <= float64(capMedium) { + L95WSMedium = float64(s.WebServerSmall.BaseLatency) + } else { + L95WSMedium = (float64(s.WebServerSmall.BaseLatency) + s.WebServerMedium.PenaltyPerRPS*(loadPerWeighted-float64(capMedium))) + } + } + + L95WS = math.Max(L95WSSmall, L95WSMedium) + } + + var L95Cache float64 + if d.CacheType == CacheStandardType { + L95Cache = float64(s.CacheStandard.BaseLatency) + } else if d.CacheType == CacheLargeType { + L95Cache = float64(s.CacheLarge.BaseLatency) + } else { + L95Cache = 0.0 + } + + readCap := s.DbReadReplica.ReadCapacity + baseReadLat := s.DbReadReplica.BaseReadLatency + penPer10 := s.DbReadReplica.PenaltyPer10RPS + + numReps := d.NumDbReplicas + var L95DbRead float64 + + if numReps == 0 { + if missesRPS <= float64(readCap) { + L95DbRead = float64(baseReadLat) + } else { + excess := missesRPS - float64(readCap) + L95DbRead = float64(baseReadLat) + penPer10*(excess/10.0) + } + } else { + loadPerRep := missesRPS / float64(numReps) + if loadPerRep <= float64(readCap) { + L95DbRead = float64(baseReadLat) + } else { + loadPerRep := missesRPS / float64(numReps) + if loadPerRep <= float64(readCap) { + L95DbRead = float64(baseReadLat) + } else { + excess := loadPerRep - loadPerRep - float64(readCap) + L95DbRead = float64(baseReadLat) + penPer10*(excess/10.0) + } + } + } + + LLb := s.LoadBalancer.BaseLatency + missPath := LLb + int(L95WS) + int(L95DbRead) + L95TotalRead := missPath + + return Latencies{ + L95WS: L95WS, + L95Cache: L95Cache, + L95DBRead: L95DbRead, + L95TotalRead: float64(L95TotalRead), + } +} + +func (ls *LevelSimulator) ComputeAvailability() float64 { + simDuration := ls.Level.SimulatedDurationSeconds + totalDownTime := 0 + for _, event := range ls.Level.FailureEvents { + tCrash := event.Time + if event.Type == "DB_MASTER_CRASH" { + if ls.Design.NumDbReplicas == 0 { + totalDownTime += (simDuration - tCrash) + } else { + delay := ls.Design.PromotionDelaySeconds + totalDownTime += delay + } + } + } + + return (float64(simDuration) - float64(totalDownTime)) / float64(simDuration) * 100 +} + +func (ls *LevelSimulator) Validate() ValidationResults { + totalCost := ls.ComputeCost() + if totalCost > ls.Level.MaxMonthlyCost { + return ValidationResults{ + Pass: false, + Metrics: Metrics{ + Cost: totalCost, + P95: la, + }, + } + } +} diff --git a/main.go b/main.go index 43d1ce5..38c1c0b 100644 --- a/main.go +++ b/main.go @@ -1,133 +1,47 @@ package main import ( - "fmt" + "context" + "html/template" "net/http" "os" - "strconv" - "strings" - - "github.com/gofrs/uuid" + "os/signal" + "time" ) -const startupMessage = `                                ▄▄           ▄  ▄▄                               -                                 ▄▄           ▄▄    ▄                            -                                ▄              ▄▄▄    ▄                          -                                  ▄ ▄          ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄          ▄▄▄▄▄▄▄  -                                 ▄ ▄  ▄▄  ▄▄▄▄       ▄        ▄▄▄▄▄▄           ▄ -  ▄            ▄   ▄▄▄   ▄       ▄   ▄▄▄▄▄▄▄▄       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ -            ▄  ▄    ▄ ▄  ▄  ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄        ▄▄▄▄ ▄▄    ▄▄▄  ▄▄        ▄▄  - ▄      ▄      ▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄    ▄   ▄   ▄▄▄  ▄ ▄▄   ▄ ▄▄▄▄▄▄       ▄    -               ▄    ▄▄  ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄    ▄▄  ▄▄▄▄▄▄▄▄▄▄▄▄      -                                     ▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄ ▄   ▄  ▄▄▄         ▄       -                                            ▄▄ ▄▄  ▄   ▄▄▄▄▄▄▄ ▄▄▄▄▄▄ ▄▄▄        -            ▄                               ▄▄     ▄  ▄     ▄▄▄▄▄▄   ▄           -               ▄  ▄   ▄▄      ▄   ▄  ▄▄▄▄     ▄▄▄▄▄▄▄▄       ▄▄▄▄  ▄▄ ▄          -                 ▄  ▄▄    ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄  ▄▄                ▄▄           -                                    ▄▄               ▄▄▄▄▄▄ ▄▄▄▄▄▄               -` - -func logRequest(r *http.Request) { - uri := r.RequestURI - method := r.Method - fmt.Println("Got request!", method, uri) -} +var tmpl = template.Must(template.ParseFiles("static/index.html")) func main() { - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - logRequest(r) - fmt.Fprintf(w, "Hello! you've requested %s\n", r.URL.Path) - }) + mux := http.NewServeMux() + mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) + mux.HandleFunc("/", index) + srv := &http.Server{ + Addr: ":8080", + Handler: mux, + } - http.HandleFunc("/cached", func(w http.ResponseWriter, r *http.Request) { - logRequest(r) - maxAgeParams, ok := r.URL.Query()["max-age"] - if ok && len(maxAgeParams) > 0 { - maxAge, _ := strconv.Atoi(maxAgeParams[0]) - w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", maxAge)) - } - responseHeaderParams, ok := r.URL.Query()["headers"] - if ok { - for _, header := range responseHeaderParams { - h := strings.Split(header, ":") - w.Header().Set(h[0], strings.TrimSpace(h[1])) - } - } - statusCodeParams, ok := r.URL.Query()["status"] - if ok { - statusCode, _ := strconv.Atoi(statusCodeParams[0]) - w.WriteHeader(statusCode) - } - requestID := uuid.Must(uuid.NewV4()) - fmt.Fprint(w, requestID.String()) - }) + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) + defer stop() - http.HandleFunc("/headers", func(w http.ResponseWriter, r *http.Request) { - logRequest(r) - keys, ok := r.URL.Query()["key"] - if ok && len(keys) > 0 { - fmt.Fprint(w, r.Header.Get(keys[0])) - return - } - headers := []string{} - headers = append(headers, fmt.Sprintf("host=%s", r.Host)) - for key, values := range r.Header { - headers = append(headers, fmt.Sprintf("%s=%s", key, strings.Join(values, ","))) - } - fmt.Fprint(w, strings.Join(headers, "\n")) - }) + go func() { + srv.ListenAndServe() + }() - http.HandleFunc("/env", func(w http.ResponseWriter, r *http.Request) { - logRequest(r) - keys, ok := r.URL.Query()["key"] - if ok && len(keys) > 0 { - fmt.Fprint(w, os.Getenv(keys[0])) - return - } - envs := []string{} - envs = append(envs, os.Environ()...) - fmt.Fprint(w, strings.Join(envs, "\n")) - }) + <-ctx.Done() + stop() - http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) { - logRequest(r) - codeParams, ok := r.URL.Query()["code"] - if ok && len(codeParams) > 0 { - statusCode, _ := strconv.Atoi(codeParams[0]) - if statusCode >= 200 && statusCode < 600 { - w.WriteHeader(statusCode) - } - } - requestID := uuid.Must(uuid.NewV4()) - fmt.Fprint(w, requestID.String()) - }) + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() - port := os.Getenv("PORT") - if port == "" { - port = "80" - } - - for _, encodedRoute := range strings.Split(os.Getenv("ROUTES"), ",") { - if encodedRoute == "" { - continue - } - pathAndBody := strings.SplitN(encodedRoute, "=", 2) - path, body := pathAndBody[0], pathAndBody[1] - http.HandleFunc("/"+path, func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, body) - }) - } + srv.Shutdown(shutdownCtx) +} - bindAddr := fmt.Sprintf(":%s", port) - lines := strings.Split(startupMessage, "\n") - fmt.Println() - for _, line := range lines { - fmt.Println(line) +func index(w http.ResponseWriter, r *http.Request) { + data := struct { + Title string + }{ + Title: "Title", } - fmt.Println() - fmt.Printf("==> Server listening at %s 🚀\n", bindAddr) - if err := http.ListenAndServe(bindAddr, nil); err != nil { - panic(err) - } + tmpl.Execute(w, data) } diff --git a/old.html b/old.html new file mode 100644 index 0000000..8fe9584 --- /dev/null +++ b/old.html @@ -0,0 +1,1051 @@ + + + + + + The System Design Game - Interactive Browser-Based Learning + + + +
+ +
+ +
+
+
+
+

Master System Design Through Interactive Challenges

+

Stop memorizing. Start building. Learn system design by solving real-world problems in your browser.

+

Level up your architecture skills through our interactive, browser-based system design platform. No installation required - just open your browser and start designing.

+
+ +
+

🚀 Get Early Access

+
+ + +
+
+ ✅ You're in! We'll notify you when beta access is available. +
+

🔥 Be the first to know when we launch

+
+
+
+
+ +
+
+

The Problem Every Engineer Faces

+
+
+
😵
+

System Design Interviews Are Brutal

+

You can code, but when asked to design Instagram or Netflix, you freeze. Theory doesn't prepare you for the real thing.

+
+
+
📚
+

Learning Resources Suck

+

Books are boring. Videos are passive. You need hands-on practice with real constraints and trade-offs.

+
+
+
+

No Time for Side Projects

+

Building distributed systems takes months. You need a way to practice system design without the overhead.

+
+
+
+
+ +
+
+

Learn System Design The Right Way

+
+
+
+
+
+
+
+
+
https://systemdesigngame.com/challenges/url-shortener
+
+
+
PREVIEW
+
+
+ +
    +
  • +
    URL Shortener
    +
    Easy
    +
  • +
  • +
    Chat System
    +
    Medium
    +
  • +
  • +
    Video Streaming
    +
    Hard
    +
  • +
+
+
+
+
Requirements
+
Design
+
Metrics
+
Code
+
+ +
+
Load Balancer
+
API Server
+
Database
+
Cache
+
CDN
+
+ +
+
API Server
+
Database
+
Cache
+
+
+
+ +
+
+
1,250
+
Requests/sec
+
+
+
45ms
+
Latency
+
+
+
99.2%
+
Availability
+
+
+ +
+
Reset
+
Test Load
+
Submit
+
+
+
+
+
+ +
    +
  • +
    🎯
    +
    +

    Interactive Browser Experience

    +

    Drag-and-drop components to build your system architecture. No installation required - works in any modern browser.

    +
    +
  • +
  • +
    +
    +

    Real-Time Feedback

    +

    See how your design performs under load. Get instant metrics on throughput, latency, and availability.

    +
    +
  • +
  • +
    🏆
    +
    +

    Progressive Difficulty

    +

    Start with simple systems, work up to complex distributed architectures. Master one concept at a time.

    +
    +
  • +
  • +
    🤝
    +
    +

    Learn With Others

    +

    Compare your solutions with different approaches. Discuss trade-offs and learn from the community.

    +
    +
  • +
+
+
+
+ +
+
+

How It Works

+
+
+
1
+
📋
+

Choose a Challenge

+

Select from various system design scenarios like URL shorteners, chat systems, or video streaming platforms.

+
+
+
2
+
🔍
+

Analyze Requirements

+

Review functional and non-functional requirements to understand the problem constraints.

+
+
+
3
+
🎨
+

Design Your Solution

+

Drag and drop components to build your architecture. Connect services and define relationships.

+
+
+
4
+
🧪
+

Test Under Load

+

Simulate real-world traffic and see how your system performs. Identify bottlenecks and failure points.

+
+
+
+
+ +
+
+

Frequently Asked Questions

+
+
+
When will the beta be available?
+
We're currently in development and aiming to launch the beta in the coming months. Sign up for the waitlist to be notified as soon as it's ready.
+
+
+
Do I need to install anything to use the System Design Game?
+
No! The entire game runs in your browser. As long as you have a modern web browser (Chrome, Firefox, Safari, Edge), you're good to go.
+
+
+
What kind of system design challenges will be available?
+
We're planning a wide range of challenges from URL shorteners and chat systems to social networks and video streaming platforms. We'll start with fundamental challenges and add more complex scenarios over time.
+
+
+
Is this suitable for beginners?
+
Yes! We're designing the game with progressive difficulty levels. Beginners can start with simpler challenges that introduce core concepts, while experienced engineers can tackle more complex distributed systems.
+
+
+
Will there be a cost to use the platform?
+
We plan to offer both free and premium tiers. The free tier will include access to basic challenges, while the premium tier will unlock advanced scenarios, detailed analytics, and additional features.
+
+
+
+
+ +
+
+

Ready to Level Up Your System Design Skills?

+

Join the waitlist and be the first to know when our interactive browser-based platform launches.

+
+ + + +
+
+
+ + + + + + diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..b6753c9 --- /dev/null +++ b/static/index.html @@ -0,0 +1,1047 @@ + + + + + + The System Design Game - Interactive Browser-Based Learning + + + +
+ +
+ +
+
+
+
+

Master System Design Through Interactive Challenges

+

Stop memorizing. Start building. Learn system design by solving real-world problems in your browser.

+

Level up your architecture skills through our interactive, browser-based system design platform. No installation required - just open your browser and start designing.

+
+ +
+

🚀 Get Early Access

+
+ + + +
+
+ ✅ You're in! We'll notify you when beta access is available. +
+

🔥 Be the first to know when we launch

+
+
+
+
+ +
+
+

The Problem Every Engineer Faces

+
+
+
😵
+

System Design Interviews Are Brutal

+

You can code, but when asked to design Instagram or Netflix, you freeze. Theory doesn't prepare you for the real thing.

+
+
+
📚
+

Learning Resources Suck

+

Books are boring. Videos are passive. You need hands-on practice with real constraints and trade-offs.

+
+
+
+

No Time for Side Projects

+

Building distributed systems takes months. You need a way to practice system design without the overhead.

+
+
+
+
+ +
+
+

Learn System Design The Right Way

+
+
+
+
+
+
+
+
+
https://systemdesigngame.com/challenges/url-shortener
+
+
+
PREVIEW
+
+
+ +
    +
  • +
    URL Shortener
    +
    Easy
    +
  • +
  • +
    Chat System
    +
    Medium
    +
  • +
  • +
    Video Streaming
    +
    Hard
    +
  • +
+
+
+
+
Requirements
+
Design
+
Metrics
+
Code
+
+ +
+
Load Balancer
+
API Server
+
Database
+
Cache
+
CDN
+
+ +
+
API Server
+
Database
+
Cache
+
+
+
+ +
+
+
1,250
+
Requests/sec
+
+
+
45ms
+
Latency
+
+
+
99.2%
+
Availability
+
+
+ +
+
Reset
+
Test Load
+
Submit
+
+
+
+
+
+ +
    +
  • +
    🎯
    +
    +

    Interactive Browser Experience

    +

    Drag-and-drop components to build your system architecture. No installation required - works in any modern browser.

    +
    +
  • +
  • +
    +
    +

    Real-Time Feedback

    +

    See how your design performs under load. Get instant metrics on throughput, latency, and availability.

    +
    +
  • +
  • +
    🏆
    +
    +

    Progressive Difficulty

    +

    Start with simple systems, work up to complex distributed architectures. Master one concept at a time.

    +
    +
  • +
  • +
    🤝
    +
    +

    Learn With Others

    +

    Compare your solutions with different approaches. Discuss trade-offs and learn from the community.

    +
    +
  • +
+
+
+
+ +
+
+

How It Works

+
+
+
1
+
📋
+

Choose a Challenge

+

Select from various system design scenarios like URL shorteners, chat systems, or video streaming platforms.

+
+
+
2
+
🔍
+

Analyze Requirements

+

Review functional and non-functional requirements to understand the problem constraints.

+
+
+
3
+
🎨
+

Design Your Solution

+

Drag and drop components to build your architecture. Connect services and define relationships.

+
+
+
4
+
🧪
+

Test Under Load

+

Simulate real-world traffic and see how your system performs. Identify bottlenecks and failure points.

+
+
+
+
+ +
+
+

Frequently Asked Questions

+
+
+
When will the beta be available?
+
We're currently in development and aiming to launch the beta in the coming months. Sign up for the waitlist to be notified as soon as it's ready.
+
+
+
Do I need to install anything to use the System Design Game?
+
No! The entire game runs in your browser. As long as you have a modern web browser (Chrome, Firefox, Safari, Edge), you're good to go.
+
+
+
What kind of system design challenges will be available?
+
We're planning a wide range of challenges from URL shorteners and chat systems to social networks and video streaming platforms. We'll start with fundamental challenges and add more complex scenarios over time.
+
+
+
Is this suitable for beginners?
+
Yes! We're designing the game with progressive difficulty levels. Beginners can start with simpler challenges that introduce core concepts, while experienced engineers can tackle more complex distributed systems.
+
+
+
Will there be a cost to use the platform?
+
We plan to offer both free and premium tiers. The free tier will include access to basic challenges, while the premium tier will unlock advanced scenarios, detailed analytics, and additional features.
+
+
+
+
+ +
+
+

Ready to Level Up Your System Design Skills?

+

Join the waitlist and be the first to know when our interactive browser-based platform launches.

+
+ + + +
+
+
+ + + + + +