Disagree-and-Commit Stories With a Design Twist
A 4-question set where each behavioral disagree-and-commit story gets a design follow-up that proves the commit was reversible. The pattern I lean on when an interviewer wants to see both sides of the same call.
By @lilyadeyemi
December 29, 2025
·
Updated August 11, 2026
529 views
4
4.4 (9)
Behavioral prompt: "Tell me about a time you disagreed with a senior on architecture but committed to their plan anyway." Design twist: "Now show me the abstraction you wrote so the team could swap implementations later if they were wrong." Show the strategy pattern I drew.
The room
I sketched the swap on the board:
storage = LocalStorage() # ship the senior's pick
client.save(storage, payload) # works today
storage = S3Storage() # swap one line, same call signature
client.save(storage, payload) # works tomorrow if we were wrongfrom typing import Protocol
class Storage(Protocol):
def save(self, key: str, blob: bytes) -> None: ...
def load(self, key: str) -> bytes: ...
class LocalStorage:
def __init__(self, root: str): self.root = root
def save(self, key, blob):
with open(f"{self.root}/{key}", "wb") as f: f.write(blob)
def load(self, key):
with open(f"{self.root}/{key}", "rb") as f: return f.read()
class S3Storage:
def __init__(self, bucket, client): self.bucket, self.client = bucket, client
def save(self, key, blob): self.client.put_object(Bucket=self.bucket, Key=key, Body=blob)
def load(self, key): return self.client.get_object(Bucket=self.bucket, Key=key)["Body"].read()
def upload(storage: Storage, key: str, blob: bytes) -> None:
storage.save(key, blob)Behavioral prompt: "Tell me about disagreeing on a deadline and committing to it anyway." Design twist: "Show me the feature flag you used to keep options open." Sketch the percentage-rollout flag I drew.
The room
I drew the rollout:
flag = FeatureFlag("new_checkout", percentage=10)
flag.enabled_for("user-100") # hash bucket 7 -> True
flag.enabled_for("user-101") # hash bucket 73 -> False
flag.set_percentage(50) # crank later without a deployimport hashlib
class FeatureFlag:
def __init__(self, name: str, percentage: int = 0):
self.name = name
self.percentage = percentage
def set_percentage(self, percentage: int) -> None:
if not 0 <= percentage <= 100:
raise ValueError("percentage out of range")
self.percentage = percentage
def enabled_for(self, user_id: str) -> bool:
h = hashlib.md5(f"{self.name}:{user_id}".encode()).hexdigest()
bucket = int(h[:8], 16) % 100
return bucket < self.percentageBehavioral prompt: "Tell me about disagreeing on choice of queue technology and committing to the team's pick." Design twist: "Show me how you isolated the choice so the rest of the codebase did not care." Draw the producer interface I used.
The room
I drew a thin wrapper on the board:
producer = QueueProducer.from_config(settings) # could be Kafka, SQS, or in-memory
producer.publish("order.created", {"id": 42})
# Three callers in the codebase, one wrapper, one config flag.from typing import Protocol
from dataclasses import dataclass
class QueueProducer(Protocol):
def publish(self, topic: str, payload: dict) -> None: ...
class KafkaProducer:
def __init__(self, client): self.client = client
def publish(self, topic, payload):
self.client.send(topic, payload)
class SqsProducer:
def __init__(self, client, queue_url):
self.client = client
self.queue_url = queue_url
def publish(self, topic, payload):
self.client.send_message(
QueueUrl=self.queue_url,
MessageBody=str(payload),
MessageAttributes={"topic": {"StringValue": topic, "DataType": "String"}},
)
@dataclass
class Settings:
backend: str
kafka_client: object = None
sqs_client: object = None
sqs_queue_url: str = ""
def from_config(settings: Settings) -> QueueProducer:
if settings.backend == "kafka":
return KafkaProducer(settings.kafka_client)
if settings.backend == "sqs":
return SqsProducer(settings.sqs_client, settings.sqs_queue_url)
raise ValueError(f"unknown backend: {settings.backend}")Behavioral prompt: "Tell me about disagreeing on a data model decision." Design twist: "Show me the migration strategy you would have used to flip the model later." Walk through the dual-write pattern I sketched.
The room
I drew a dual-write step on the board:
write_user(old_schema, new_schema, user) # writes to both stores
read_user(old_schema, user_id) # reads from old, the source of truth today
# After backfill + verification, flip read_user to new_schema, keep old write live.def write_user(old_store, new_store, user):
old_store.save(user)
try:
new_store.save(transform(user))
except Exception as err:
# Never block the primary write on the secondary.
log_double_write_failure(user.id, err)
def read_user(store, user_id):
return store.load(user_id)
def transform(user):
return {"uid": user.id, "name": user.full_name(), "email": user.email}
def log_double_write_failure(uid, err):
print(f"dual-write to new_store failed for {uid}: {err}")