Repository and unit of work
Picture
Let a notebook service ask a repository for notes. The repository owns how those notes are stored and queried.
Predict
Does having a repository automatically make multiple writes transactional?
Walk through the small example
No, define the unit of work. Storage access and transaction boundaries are separate responsibilities.
Mental model and complete Python solution
MemoryNotes implements a small save/get boundary. UnitOfWork stages a complete working copy, then commits it explicitly; exceptions leave the original state untouched. This demonstrates the atomic grouping concept in one process, not a concurrency-safe database transaction. A production repository should not hide query costs, isolation requirements, or pagination behind misleading collection-like methods.
What the function promises: This local unit of work supports explicit commit of in-memory note changes. Exiting without commit discards the draft. Concurrent transactions are not supported.
class MemoryNotes:
def __init__(self):
self.data = {}
def get(self, key):
return self.data.get(key)
class UnitOfWork:
def __init__(self, repository):
self.repository = repository
def __enter__(self):
self.draft = self.repository.data.copy()
return self
def save(self, key, value):
self.draft[key] = value
def commit(self):
self.repository.data = self.draft.copy()
def __exit__(self, kind, value, traceback):
return False
repo = MemoryNotes()
with UnitOfWork(repo) as work:
work.save("a", "idea")
assert repo.get("a") is None
with UnitOfWork(repo) as work:
work.save("a", "idea")
work.commit()
assert repo.get("a") == "idea"
Work and storage: O(number of notes) copying per unit of work in this teaching implementation. Real databases use different transactional storage mechanisms.
When to recognize it: A memory repository checks domain behavior without a live database. It is useful only if its relevant semantics match the real adapter.
Check before applying it: A repository abstraction cannot replace explicit isolation, concurrency, and transaction guarantees.
Change one rule
Two units of work start from the same snapshot and both commit. What can go wrong?
See what changes
The later commit can overwrite the earlier update. A real implementation needs optimistic version checks, locking, or suitable database isolation rather than unconditional snapshot replacement.
Connect
Keep changes from spreading everywhere: Separate domain responsibility from a concrete storage detail.
Choose storage from reads and writes: A real database adds indexes, isolation, and transactional behavior.