Skip to content

Commit 283141e

Browse files
committed
docs: expand convert-to-marimo skill with function extraction guidance
Add detailed guidance on: - Naming functions to document intent (replacing comments) - Decomposing monolithic functions by stage - Splitting large cells so intermediate results are visible - Extracting reusable helpers into their own cells - Parameterizing functions to avoid globals Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent 698a7cb commit 283141e

1 file changed

Lines changed: 126 additions & 8 deletions

File tree

  • .claude/skills/convert-to-marimo

.claude/skills/convert-to-marimo/SKILL.md

Lines changed: 126 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,131 @@ Results update when the user changes either input.
231231

232232
## Phase 6: Code Quality
233233

234+
### Name things to document intent
235+
236+
Well-named functions and variables replace comments. If you find yourself writing a comment to explain what a block of code does, that is a signal to extract it into a named function instead.
237+
238+
**Before:**
239+
```python
240+
# Filter sentences containing our keyword and build records for Pinecone
241+
results = []
242+
for i, row in enumerate(dataset.filter(lambda x: any(k in x["text"] for k in keywords))):
243+
results.append({"id": str(i), "chunk_text": row["text"], "lang": row["lang"]})
244+
```
245+
246+
**After:**
247+
```python
248+
def filter_by_keywords(dataset, keywords):
249+
return dataset.filter(lambda x: any(k in x["text"] for k in keywords))
250+
251+
def to_records(sentences, id_prefix=""):
252+
return [
253+
{"id": f"{id_prefix}{i}", "chunk_text": s["text"], "lang": s["lang"]}
254+
for i, s in enumerate(sentences)
255+
]
256+
257+
filtered = filter_by_keywords(dataset, keywords)
258+
records = to_records(filtered)
259+
```
260+
261+
The second version reads like a description of what is happening. The function names are the documentation.
262+
263+
### Decompose monolithic functions by stage
264+
265+
Jupyter notebooks often have one large function that loads, filters, transforms, and formats data all at once. Split it along its natural stages — each stage becomes a function with a clear name and a clear input/output contract.
266+
267+
**Identify stages by asking:** at what points does the data change shape or purpose?
268+
269+
Example decomposition:
270+
```
271+
prepare_sentences(dataset, keywords) → one big function doing everything
272+
273+
becomes:
274+
275+
filter_pairs(dataset, keywords) → returns filtered HF dataset (pairs)
276+
extract_sentences(pairs, lang) → returns single-language HF dataset
277+
to_records(sentences, column) → returns list of Pinecone record dicts
278+
```
279+
280+
Each stage can be shown, inspected, and explained independently. Each can be reused or replaced without touching the others.
281+
282+
### Split large cells to make intermediate results visible
283+
284+
Marimo cells produce output. A single cell that does five things produces one output — or none. Splitting at stage boundaries lets each step show its result, which helps readers understand what changed and why.
285+
286+
**Rule of thumb:** if a cell produces a value worth seeing (a filtered dataset, a record list, a search result), that value should be the last expression in its own cell.
287+
288+
```python
289+
# Too much in one cell — intermediate state invisible
290+
filtered = filter_pairs(tatoeba, keywords)
291+
english = extract_sentences(filtered, lang="en")
292+
records = to_records(english, column="sentence")
293+
index.upsert_records(records=records, namespace=namespace)
294+
```
295+
296+
```python
297+
# Split: each step's output is inspectable
298+
# Cell 1
299+
filtered_pairs = filter_pairs(tatoeba, keywords=keywords)
300+
301+
# Cell 2 — reader can see what was extracted
302+
english = extract_sentences(filtered_pairs, lang="en")
303+
mo.ui.table(english, page_size=5)
304+
305+
# Cell 3 — reader can see the record format before upserting
306+
records = to_records(english, column="sentence")
307+
mo.ui.table(records, page_size=5)
308+
309+
# Cell 4 — upsert is its own step
310+
for start in mo.status.progress_bar(range(0, len(records), batch_size)):
311+
index.upsert_records(records=records[start:start + batch_size], namespace=namespace)
312+
```
313+
314+
### Extract reusable helpers into their own cells
315+
316+
If a function is called more than once, or could reasonably be called with different arguments, give it its own cell. Readers can read the definition once, then see it used cleanly at each call site.
317+
318+
The search notebook pattern is a good model:
319+
320+
```python
321+
# One cell defines the helper
322+
def search(query, top_k=10, lang=None):
323+
results = index.search(
324+
namespace=namespace,
325+
top_k=top_k,
326+
inputs={"text": query},
327+
filter={"lang": {"$eq": lang}} if lang else None,
328+
)
329+
return print_results(query, results)
330+
331+
# Subsequent cells are just clean call sites
332+
search("I want to go to the park and relax")
333+
search("Quiero ir al parque a relajarme")
334+
search("The park is crowded today", lang="en")
335+
```
336+
337+
### Parameterize functions — avoid globals
338+
339+
Converted notebooks often have functions that silently close over global variables (`keywords`, `index`, `namespace`). This makes the function hard to reuse and hides dependencies.
340+
341+
**Before (globals):**
342+
```python
343+
keywords = ["park"]
344+
345+
def prepare_sentences(dataset):
346+
return dataset.filter(lambda x: any(k in x["translation"]["en"] for k in keywords))
347+
```
348+
349+
**After (explicit parameter):**
350+
```python
351+
def prepare_sentences(dataset, keywords=None):
352+
if keywords:
353+
return dataset.filter(lambda x: any(k in x["translation"]["en"] for k in keywords))
354+
return dataset
355+
```
356+
357+
The exception: functions that close over `index` and `namespace` in a "search" helper are reasonable — they're scoped to the notebook, and the closure reads naturally.
358+
234359
### Remove over-explaining comments
235360

236361
Only comment on the non-obvious WHY — not on what the code does. Delete comments like:
@@ -239,14 +364,7 @@ Only comment on the non-obvious WHY — not on what the code does. Delete commen
239364
- `# flatten and shuffle for ease of use`
240365
- `# Here, we create a record for each sentence in the dataset`
241366

242-
Keep comments that explain constraints, workarounds, or non-obvious choices.
243-
244-
### Decompose monolithic functions
245-
246-
If the converted notebook has a large function doing multiple things, split it:
247-
- Separate filtering from reshaping from formatting
248-
- Name each function after its single responsibility
249-
- Parameterize functions properly — avoid globals captured by closures
367+
Keep comments that explain constraints, workarounds, or non-obvious choices — especially when a behaviour might surprise a reader (e.g. why a version is pinned, why a parameter is omitted).
250368

251369
### Avoid multiply-defined variables across cells
252370

0 commit comments

Comments
 (0)