cli-dev-tip 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dev_tip/data/tips.yaml ADDED
@@ -0,0 +1,2070 @@
1
+ # =============================================================================
2
+ # Python tips
3
+ # =============================================================================
4
+
5
+ - id: python-001
6
+ topic: python
7
+ title: Use enumerate() instead of range(len())
8
+ body: >
9
+ Instead of `for i in range(len(items))`, use `for i, item in enumerate(items)`.
10
+ It's more Pythonic and gives you both the index and value.
11
+ example: |
12
+ for i, name in enumerate(names, start=1):
13
+ print(f"{i}. {name}")
14
+ level: beginner
15
+ source: https://docs.python.org/3/library/functions.html#enumerate
16
+
17
+ - id: python-002
18
+ topic: python
19
+ title: f-strings support expressions and formatting
20
+ body: >
21
+ f-strings can contain any valid Python expression, including method calls,
22
+ math, and format specifiers.
23
+ example: |
24
+ name = "world"
25
+ print(f"{'hello':>10} {name.upper()}")
26
+ print(f"pi = {3.14159:.2f}")
27
+ level: beginner
28
+ source: https://docs.python.org/3/reference/lexical_analysis.html#f-strings
29
+
30
+ - id: python-003
31
+ topic: python
32
+ title: Use pathlib for file paths
33
+ body: >
34
+ The pathlib module provides an object-oriented interface for filesystem paths.
35
+ It's cross-platform and more readable than os.path.
36
+ example: |
37
+ from pathlib import Path
38
+ config = Path.home() / ".config" / "app" / "settings.toml"
39
+ config.parent.mkdir(parents=True, exist_ok=True)
40
+ level: intermediate
41
+ source: https://docs.python.org/3/library/pathlib.html
42
+
43
+ - id: python-004
44
+ topic: python
45
+ title: Walrus operator for assignment expressions
46
+ body: >
47
+ The := operator assigns and returns a value in one expression.
48
+ Useful in while loops and comprehensions.
49
+ example: |
50
+ # Read lines until empty
51
+ while (line := input("Enter text: ")) != "":
52
+ print(f"You said: {line}")
53
+ level: intermediate
54
+ source: https://peps.python.org/pep-0572/
55
+
56
+ - id: python-005
57
+ topic: python
58
+ title: Use collections.Counter for counting
59
+ body: >
60
+ Counter is a dict subclass for counting hashable objects. It has helpful
61
+ methods like most_common() and supports arithmetic operations.
62
+ example: |
63
+ from collections import Counter
64
+ words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
65
+ counts = Counter(words)
66
+ print(counts.most_common(2)) # [('apple', 3), ('banana', 2)]
67
+ level: beginner
68
+ source: https://docs.python.org/3/library/collections.html#collections.Counter
69
+
70
+ - id: python-006
71
+ topic: python
72
+ title: Use contextlib for custom context managers
73
+ body: >
74
+ The @contextmanager decorator lets you write context managers as simple
75
+ generator functions instead of full classes with __enter__/__exit__.
76
+ example: |
77
+ from contextlib import contextmanager
78
+ import time
79
+
80
+ @contextmanager
81
+ def timer(label):
82
+ start = time.perf_counter()
83
+ yield
84
+ print(f"{label}: {time.perf_counter() - start:.3f}s")
85
+
86
+ with timer("query"):
87
+ run_query()
88
+ level: intermediate
89
+ source: https://docs.python.org/3/library/contextlib.html
90
+
91
+ - id: python-007
92
+ topic: python
93
+ title: Use dataclasses for simple data containers
94
+ body: >
95
+ The @dataclass decorator auto-generates __init__, __repr__, __eq__ and more.
96
+ Saves boilerplate for classes that mainly hold data.
97
+ example: |
98
+ from dataclasses import dataclass
99
+
100
+ @dataclass
101
+ class Point:
102
+ x: float
103
+ y: float
104
+ label: str = ""
105
+ level: beginner
106
+ source: https://docs.python.org/3/library/dataclasses.html
107
+
108
+ - id: python-008
109
+ topic: python
110
+ title: Use __slots__ for memory-efficient classes
111
+ body: >
112
+ Defining __slots__ prevents creation of __dict__ per instance,
113
+ reducing memory usage significantly for classes with many instances.
114
+ example: |
115
+ class Point:
116
+ __slots__ = ("x", "y")
117
+ def __init__(self, x, y):
118
+ self.x = x
119
+ self.y = y
120
+ level: advanced
121
+ source: https://docs.python.org/3/reference/datamodel.html#slots
122
+
123
+ - id: python-009
124
+ topic: python
125
+ title: Use functools.lru_cache for memoization
126
+ body: >
127
+ The @lru_cache decorator caches function results based on arguments.
128
+ Great for expensive computations with repeated inputs.
129
+ example: |
130
+ from functools import lru_cache
131
+
132
+ @lru_cache(maxsize=128)
133
+ def fib(n):
134
+ if n < 2:
135
+ return n
136
+ return fib(n - 1) + fib(n - 2)
137
+ level: intermediate
138
+ source: https://docs.python.org/3/library/functools.html#functools.lru_cache
139
+
140
+ - id: python-010
141
+ topic: python
142
+ title: Use structural pattern matching
143
+ body: >
144
+ Python 3.10 introduced match/case statements for structural pattern matching.
145
+ It can destructure objects, match types, and handle complex conditions.
146
+ example: |
147
+ match command.split():
148
+ case ["quit"]:
149
+ exit()
150
+ case ["go", direction]:
151
+ move(direction)
152
+ case ["get", item] if item in inventory:
153
+ pick_up(item)
154
+ case _:
155
+ print("Unknown command")
156
+ level: advanced
157
+ source: https://peps.python.org/pep-0636/
158
+
159
+ - id: python-011
160
+ topic: python
161
+ title: Use itertools for efficient looping
162
+ body: >
163
+ The itertools module provides memory-efficient tools for working with
164
+ iterators. chain, product, groupby, and islice cover most use cases.
165
+ example: |
166
+ from itertools import chain, islice
167
+
168
+ # Flatten multiple lists
169
+ all_items = list(chain([1, 2], [3, 4], [5]))
170
+
171
+ # Take first 5 items from any iterable
172
+ first_five = list(islice(range(1000000), 5))
173
+ level: intermediate
174
+ source: https://docs.python.org/3/library/itertools.html
175
+
176
+ - id: python-012
177
+ topic: python
178
+ title: Use dict.get() with a default value
179
+ body: >
180
+ dict.get(key, default) returns the default instead of raising KeyError
181
+ when the key is missing. Cleaner than try/except for simple lookups.
182
+ example: |
183
+ config = {"debug": True}
184
+ # Instead of: config["timeout"] if "timeout" in config else 30
185
+ timeout = config.get("timeout", 30)
186
+ level: beginner
187
+ source: https://docs.python.org/3/library/stdtypes.html#dict.get
188
+
189
+ - id: python-013
190
+ topic: python
191
+ title: Use zip() to iterate multiple sequences
192
+ body: >
193
+ zip() pairs up elements from multiple iterables. In Python 3.10+
194
+ use strict=True to catch length mismatches.
195
+ example: |
196
+ names = ["Alice", "Bob", "Charlie"]
197
+ scores = [95, 87, 92]
198
+
199
+ for name, score in zip(names, scores, strict=True):
200
+ print(f"{name}: {score}")
201
+ level: beginner
202
+ source: https://docs.python.org/3/library/functions.html#zip
203
+
204
+ - id: python-014
205
+ topic: python
206
+ title: Use __init_subclass__ for plugin patterns
207
+ body: >
208
+ __init_subclass__ runs when a class is subclassed. Perfect for auto-registering
209
+ plugins without metaclasses or decorators.
210
+ example: |
211
+ class Plugin:
212
+ registry = {}
213
+ def __init_subclass__(cls, name=None, **kwargs):
214
+ super().__init_subclass__(**kwargs)
215
+ Plugin.registry[name or cls.__name__] = cls
216
+
217
+ class JSONLoader(Plugin, name="json"):
218
+ pass
219
+
220
+ print(Plugin.registry) # {"json": <class 'JSONLoader'>}
221
+ level: advanced
222
+ source: https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__
223
+
224
+ - id: python-015
225
+ topic: python
226
+ title: Use typing.Protocol for structural subtyping
227
+ body: >
228
+ Protocol defines interfaces by structure, not inheritance. A class matches
229
+ if it has the right methods — no need to explicitly subclass.
230
+ example: |
231
+ from typing import Protocol
232
+
233
+ class Closable(Protocol):
234
+ def close(self) -> None: ...
235
+
236
+ def cleanup(resource: Closable) -> None:
237
+ resource.close()
238
+
239
+ # Any object with a close() method works — no inheritance needed
240
+ level: advanced
241
+ source: https://docs.python.org/3/library/typing.html#typing.Protocol
242
+
243
+ # =============================================================================
244
+ # Git tips
245
+ # =============================================================================
246
+
247
+ - id: git-001
248
+ topic: git
249
+ title: Use git stash to save work in progress
250
+ body: >
251
+ `git stash` saves your uncommitted changes and reverts to a clean working
252
+ directory. Use `git stash pop` to restore them later.
253
+ example: |
254
+ git stash
255
+ git checkout main
256
+ # do some work
257
+ git checkout feature-branch
258
+ git stash pop
259
+ level: beginner
260
+ source: https://git-scm.com/docs/git-stash
261
+
262
+ - id: git-002
263
+ topic: git
264
+ title: Interactive rebase to clean up commits
265
+ body: >
266
+ Use `git rebase -i` to squash, reorder, or edit commits before pushing.
267
+ Keeps your branch history clean and logical.
268
+ example: |
269
+ git rebase -i HEAD~3
270
+ # In the editor, change 'pick' to 'squash' or 'fixup'
271
+ level: intermediate
272
+ source: https://git-scm.com/docs/git-rebase
273
+
274
+ - id: git-003
275
+ topic: git
276
+ title: Use git bisect to find bugs
277
+ body: >
278
+ `git bisect` performs a binary search through your commit history to find
279
+ the exact commit that introduced a bug.
280
+ example: |
281
+ git bisect start
282
+ git bisect bad # current commit is broken
283
+ git bisect good v1.0.0 # this tag was working
284
+ # git checks out middle commit, you test, then:
285
+ git bisect good # or git bisect bad
286
+ level: advanced
287
+ source: https://git-scm.com/docs/git-bisect
288
+
289
+ - id: git-004
290
+ topic: git
291
+ title: Amend the last commit message
292
+ body: >
293
+ Made a typo in your last commit message? Use `--amend` to fix it.
294
+ Only do this before pushing.
295
+ example: |
296
+ git commit --amend -m "fix: correct validation logic"
297
+ level: beginner
298
+ source: https://git-scm.com/docs/git-commit
299
+
300
+ - id: git-005
301
+ topic: git
302
+ title: Use git log --oneline for a compact history
303
+ body: >
304
+ The --oneline flag shows each commit on a single line with just the
305
+ short hash and message. Add --graph for a visual branch view.
306
+ example: |
307
+ git log --oneline --graph --all
308
+ level: beginner
309
+ source: https://git-scm.com/docs/git-log
310
+
311
+ - id: git-006
312
+ topic: git
313
+ title: Cherry-pick commits from other branches
314
+ body: >
315
+ `git cherry-pick` applies the changes from specific commits onto your
316
+ current branch. Useful for backporting fixes.
317
+ example: |
318
+ git cherry-pick abc1234
319
+ # Apply multiple commits
320
+ git cherry-pick abc1234 def5678
321
+ level: intermediate
322
+ source: https://git-scm.com/docs/git-cherry-pick
323
+
324
+ - id: git-007
325
+ topic: git
326
+ title: Use git worktree for parallel work
327
+ body: >
328
+ `git worktree` lets you check out multiple branches simultaneously in
329
+ separate directories, sharing the same repo.
330
+ example: |
331
+ git worktree add ../hotfix hotfix-branch
332
+ cd ../hotfix
333
+ # work on hotfix without stashing your feature work
334
+ level: advanced
335
+ source: https://git-scm.com/docs/git-worktree
336
+
337
+ - id: git-008
338
+ topic: git
339
+ title: Use git diff --staged to see what you'll commit
340
+ body: >
341
+ `git diff` shows unstaged changes, but `git diff --staged` shows exactly
342
+ what will be included in the next commit.
343
+ example: |
344
+ git add src/main.py
345
+ git diff --staged # shows only staged changes
346
+ level: beginner
347
+ source: https://git-scm.com/docs/git-diff
348
+
349
+ - id: git-009
350
+ topic: git
351
+ title: Use git reflog to recover lost commits
352
+ body: >
353
+ The reflog records every time HEAD changes. Even after a hard reset or
354
+ deleted branch, you can find and restore lost commits.
355
+ example: |
356
+ git reflog
357
+ # Find the lost commit hash, then:
358
+ git checkout -b recovery abc1234
359
+ level: advanced
360
+ source: https://git-scm.com/docs/git-reflog
361
+
362
+ - id: git-010
363
+ topic: git
364
+ title: Partial staging with git add -p
365
+ body: >
366
+ `git add -p` lets you interactively select which hunks of a file to stage.
367
+ Great for splitting changes into logical commits.
368
+ example: |
369
+ git add -p src/main.py
370
+ # For each hunk, press: y (stage), n (skip), s (split)
371
+ level: intermediate
372
+ source: https://git-scm.com/docs/git-add
373
+
374
+ - id: git-011
375
+ topic: git
376
+ title: Use git blame to find who changed a line
377
+ body: >
378
+ `git blame` shows who last modified each line of a file and in which
379
+ commit. Use -L to narrow down to specific lines.
380
+ example: |
381
+ git blame src/main.py
382
+ # Blame specific lines
383
+ git blame -L 10,20 src/main.py
384
+ # Ignore whitespace changes
385
+ git blame -w src/main.py
386
+ level: beginner
387
+ source: https://git-scm.com/docs/git-blame
388
+
389
+ - id: git-012
390
+ topic: git
391
+ title: Set up git aliases for common commands
392
+ body: >
393
+ Git aliases save keystrokes for frequently used commands.
394
+ Define them in your global git config.
395
+ example: |
396
+ git config --global alias.co checkout
397
+ git config --global alias.br branch
398
+ git config --global alias.st status
399
+ git config --global alias.lg "log --oneline --graph --all"
400
+ # Now use: git co main, git lg
401
+ level: beginner
402
+ source: https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases
403
+
404
+ - id: git-013
405
+ topic: git
406
+ title: Use git switch and git restore
407
+ body: >
408
+ Modern Git split checkout into two commands. `git switch` changes branches,
409
+ `git restore` discards file changes. Less ambiguous than checkout.
410
+ example: |
411
+ # Switch branches (instead of git checkout main)
412
+ git switch main
413
+ git switch -c new-feature # create + switch
414
+
415
+ # Restore files (instead of git checkout -- file)
416
+ git restore src/main.py
417
+ git restore --staged src/main.py # unstage
418
+ level: intermediate
419
+ source: https://git-scm.com/docs/git-switch
420
+
421
+ - id: git-014
422
+ topic: git
423
+ title: Use git commit --fixup for clean history
424
+ body: >
425
+ `--fixup` creates a commit that marks itself as a fix for a previous
426
+ commit. Then `rebase --autosquash` merges them automatically.
427
+ example: |
428
+ # Fix something that should have been in abc1234
429
+ git commit --fixup abc1234
430
+ # Later, squash fixups automatically
431
+ git rebase -i --autosquash main
432
+ level: advanced
433
+ source: https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---fixupamaborgrewordltcommitgt
434
+
435
+ - id: git-015
436
+ topic: git
437
+ title: Use git diff with word-level granularity
438
+ body: >
439
+ `--word-diff` shows changes at the word level instead of whole lines.
440
+ Makes it much easier to spot small changes in prose or config files.
441
+ example: |
442
+ git diff --word-diff
443
+ # Colored inline changes
444
+ git diff --word-diff=color
445
+ # Custom word regex (useful for code)
446
+ git diff --word-diff-regex='[a-zA-Z_]+|.'
447
+ level: intermediate
448
+ source: https://git-scm.com/docs/git-diff
449
+
450
+ # =============================================================================
451
+ # Docker tips
452
+ # =============================================================================
453
+
454
+ - id: docker-001
455
+ topic: docker
456
+ title: Use multi-stage builds for smaller images
457
+ body: >
458
+ Multi-stage builds let you use one stage for building and another for the
459
+ final image. This keeps your production image small and clean.
460
+ example: |
461
+ FROM node:20 AS builder
462
+ WORKDIR /app
463
+ COPY . .
464
+ RUN npm ci && npm run build
465
+
466
+ FROM node:20-slim
467
+ COPY --from=builder /app/dist ./dist
468
+ CMD ["node", "dist/index.js"]
469
+ level: intermediate
470
+ source: https://docs.docker.com/build/building/multi-stage/
471
+
472
+ - id: docker-002
473
+ topic: docker
474
+ title: Use .dockerignore to speed up builds
475
+ body: >
476
+ A .dockerignore file prevents unnecessary files from being sent to the
477
+ Docker daemon during builds, making them faster.
478
+ example: |
479
+ # .dockerignore
480
+ node_modules
481
+ .git
482
+ *.md
483
+ .env
484
+ level: beginner
485
+ source: https://docs.docker.com/build/building/context/#dockerignore-files
486
+
487
+ - id: docker-003
488
+ topic: docker
489
+ title: Use HEALTHCHECK in your Dockerfile
490
+ body: >
491
+ HEALTHCHECK tells Docker how to verify your container is still working.
492
+ Orchestrators use this to restart unhealthy containers.
493
+ example: |
494
+ HEALTHCHECK --interval=30s --timeout=3s \
495
+ CMD curl -f http://localhost:8080/health || exit 1
496
+ level: intermediate
497
+ source: https://docs.docker.com/reference/dockerfile/#healthcheck
498
+
499
+ - id: docker-004
500
+ topic: docker
501
+ title: Pin image versions in production
502
+ body: >
503
+ Always use specific image tags instead of `latest` in production.
504
+ This ensures reproducible builds and deployments.
505
+ example: |
506
+ # Bad
507
+ FROM python:latest
508
+ # Good
509
+ FROM python:3.12-slim@sha256:abc123...
510
+ level: beginner
511
+ source: https://docs.docker.com/build/building/best-practices/
512
+
513
+ - id: docker-005
514
+ topic: docker
515
+ title: Use COPY --chown to avoid extra RUN layers
516
+ body: >
517
+ Instead of COPY + RUN chown (which creates two layers), use the --chown
518
+ flag to set ownership in a single layer.
519
+ example: |
520
+ # Instead of:
521
+ COPY app/ /app/
522
+ RUN chown -R appuser:appuser /app
523
+ # Use:
524
+ COPY --chown=appuser:appuser app/ /app/
525
+ level: intermediate
526
+ source: https://docs.docker.com/reference/dockerfile/#copy
527
+
528
+ - id: docker-006
529
+ topic: docker
530
+ title: Use docker compose watch for live reload
531
+ body: >
532
+ Docker Compose Watch automatically syncs file changes and rebuilds containers
533
+ during development, without manual restarts.
534
+ example: |
535
+ # compose.yaml
536
+ services:
537
+ web:
538
+ build: .
539
+ develop:
540
+ watch:
541
+ - action: sync
542
+ path: ./src
543
+ target: /app/src
544
+ level: intermediate
545
+ source: https://docs.docker.com/compose/how-tos/file-watch/
546
+
547
+ - id: docker-007
548
+ topic: docker
549
+ title: Use docker system prune to free disk space
550
+ body: >
551
+ Docker can accumulate unused images, containers, and volumes over time.
552
+ `docker system prune` cleans up everything that's not in use.
553
+ example: |
554
+ # Remove unused data
555
+ docker system prune
556
+ # Also remove unused volumes
557
+ docker system prune --volumes
558
+ # See disk usage first
559
+ docker system df
560
+ level: beginner
561
+ source: https://docs.docker.com/reference/cli/docker/system/prune/
562
+
563
+ - id: docker-008
564
+ topic: docker
565
+ title: Order Dockerfile layers for better caching
566
+ body: >
567
+ Docker caches each layer. Put rarely-changing instructions (like installing
568
+ dependencies) before frequently-changing ones (like copying source code).
569
+ example: |
570
+ FROM python:3.12-slim
571
+ WORKDIR /app
572
+ # Dependencies change rarely - cached
573
+ COPY requirements.txt .
574
+ RUN pip install -r requirements.txt
575
+ # Source changes often - not cached
576
+ COPY . .
577
+ level: beginner
578
+ source: https://docs.docker.com/build/cache/
579
+
580
+ - id: docker-009
581
+ topic: docker
582
+ title: Use build arguments for flexible images
583
+ body: >
584
+ ARG lets you pass build-time variables to your Dockerfile. Useful for
585
+ version numbers, environment selection, and conditional logic.
586
+ example: |
587
+ ARG PYTHON_VERSION=3.12
588
+ FROM python:${PYTHON_VERSION}-slim
589
+ ARG ENV=production
590
+ RUN if [ "$ENV" = "development" ]; then pip install debugpy; fi
591
+ level: intermediate
592
+ source: https://docs.docker.com/reference/dockerfile/#arg
593
+
594
+ - id: docker-010
595
+ topic: docker
596
+ title: Use docker exec to debug running containers
597
+ body: >
598
+ `docker exec` runs a command inside a running container. Essential for
599
+ debugging and inspecting container state.
600
+ example: |
601
+ # Open a shell in a running container
602
+ docker exec -it mycontainer /bin/sh
603
+ # Check environment variables
604
+ docker exec mycontainer env
605
+ # View logs inside container
606
+ docker exec mycontainer cat /var/log/app.log
607
+ level: beginner
608
+ source: https://docs.docker.com/reference/cli/docker/container/exec/
609
+
610
+ - id: docker-011
611
+ topic: docker
612
+ title: Use docker compose profiles for environments
613
+ body: >
614
+ Profiles let you define services that only start when explicitly requested.
615
+ Useful for debug tools, monitoring, or test databases.
616
+ example: |
617
+ # compose.yaml
618
+ services:
619
+ app:
620
+ build: .
621
+ debug:
622
+ image: busybox
623
+ profiles: ["debug"]
624
+ mailhog:
625
+ image: mailhog/mailhog
626
+ profiles: ["debug"]
627
+
628
+ # docker compose --profile debug up
629
+ level: intermediate
630
+ source: https://docs.docker.com/compose/how-tos/profiles/
631
+
632
+ - id: docker-012
633
+ topic: docker
634
+ title: Run as non-root user for security
635
+ body: >
636
+ Containers run as root by default. Create a non-root user to limit
637
+ the blast radius if your container is compromised.
638
+ example: |
639
+ FROM python:3.12-slim
640
+ RUN groupadd -r app && useradd -r -g app app
641
+ WORKDIR /app
642
+ COPY --chown=app:app . .
643
+ USER app
644
+ CMD ["python", "main.py"]
645
+ level: intermediate
646
+ source: https://docs.docker.com/build/building/best-practices/#user
647
+
648
+ - id: docker-013
649
+ topic: docker
650
+ title: Use docker logs to troubleshoot containers
651
+ body: >
652
+ `docker logs` shows stdout/stderr from a container. Use --follow to
653
+ stream in real time and --since to filter by time.
654
+ example: |
655
+ # View all logs
656
+ docker logs mycontainer
657
+ # Stream logs in real time
658
+ docker logs -f mycontainer
659
+ # Last 100 lines from past hour
660
+ docker logs --tail 100 --since 1h mycontainer
661
+ level: beginner
662
+ source: https://docs.docker.com/reference/cli/docker/container/logs/
663
+
664
+ - id: docker-014
665
+ topic: docker
666
+ title: Use tmpfs mounts for sensitive data
667
+ body: >
668
+ tmpfs mounts exist only in memory and are never written to disk.
669
+ Use them for secrets, temp files, or build caches.
670
+ example: |
671
+ # CLI
672
+ docker run --tmpfs /tmp:rw,noexec,nosuid myimage
673
+
674
+ # compose.yaml
675
+ services:
676
+ app:
677
+ tmpfs:
678
+ - /tmp
679
+ - /run
680
+ level: advanced
681
+ source: https://docs.docker.com/engine/storage/tmpfs/
682
+
683
+ - id: docker-015
684
+ topic: docker
685
+ title: Use docker network for container communication
686
+ body: >
687
+ Containers on the same Docker network can reach each other by service name.
688
+ No need to publish ports for inter-container communication.
689
+ example: |
690
+ # compose.yaml - app reaches db at "db:5432"
691
+ services:
692
+ app:
693
+ build: .
694
+ environment:
695
+ DATABASE_URL: postgresql://user:pass@db:5432/mydb
696
+ db:
697
+ image: postgres:16
698
+ level: beginner
699
+ source: https://docs.docker.com/engine/network/
700
+
701
+ # =============================================================================
702
+ # SQL tips
703
+ # =============================================================================
704
+
705
+ - id: sql-001
706
+ topic: sql
707
+ title: Use COALESCE to handle NULL values
708
+ body: >
709
+ COALESCE returns the first non-NULL value from a list of arguments.
710
+ Great for providing default values in queries.
711
+ example: |
712
+ SELECT name, COALESCE(nickname, name) AS display_name
713
+ FROM users;
714
+ level: beginner
715
+ source: https://www.postgresql.org/docs/current/functions-conditional.html
716
+
717
+ - id: sql-002
718
+ topic: sql
719
+ title: Use CTEs for readable complex queries
720
+ body: >
721
+ Common Table Expressions (WITH clauses) let you break complex queries
722
+ into named, readable steps.
723
+ example: |
724
+ WITH active_users AS (
725
+ SELECT * FROM users WHERE last_login > NOW() - INTERVAL '30 days'
726
+ )
727
+ SELECT department, COUNT(*) FROM active_users
728
+ GROUP BY department;
729
+ level: intermediate
730
+ source: https://www.postgresql.org/docs/current/queries-with.html
731
+
732
+ - id: sql-003
733
+ topic: sql
734
+ title: Use EXPLAIN ANALYZE to debug slow queries
735
+ body: >
736
+ EXPLAIN ANALYZE runs the query and shows the actual execution plan
737
+ with timing information. Essential for performance tuning.
738
+ example: |
739
+ EXPLAIN ANALYZE
740
+ SELECT * FROM orders
741
+ WHERE customer_id = 42
742
+ ORDER BY created_at DESC;
743
+ level: advanced
744
+ source: https://www.postgresql.org/docs/current/using-explain.html
745
+
746
+ - id: sql-004
747
+ topic: sql
748
+ title: Use EXISTS instead of IN for subqueries
749
+ body: >
750
+ EXISTS can be faster than IN for correlated subqueries because it
751
+ stops scanning once a match is found.
752
+ example: |
753
+ -- Instead of: WHERE id IN (SELECT user_id FROM orders)
754
+ SELECT * FROM users u
755
+ WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);
756
+ level: intermediate
757
+ source: https://www.postgresql.org/docs/current/functions-subquery.html
758
+
759
+ - id: sql-005
760
+ topic: sql
761
+ title: Use window functions for running totals
762
+ body: >
763
+ Window functions perform calculations across rows related to the current
764
+ row, without collapsing them into groups like GROUP BY.
765
+ example: |
766
+ SELECT
767
+ date,
768
+ revenue,
769
+ SUM(revenue) OVER (ORDER BY date) AS running_total,
770
+ AVG(revenue) OVER (ORDER BY date ROWS 6 PRECEDING) AS moving_avg_7d
771
+ FROM daily_sales;
772
+ level: advanced
773
+ source: https://www.postgresql.org/docs/current/tutorial-window.html
774
+
775
+ - id: sql-006
776
+ topic: sql
777
+ title: Use DISTINCT ON for top-per-group queries
778
+ body: >
779
+ PostgreSQL's DISTINCT ON returns the first row for each unique value
780
+ of the specified columns. Simpler than window function alternatives.
781
+ example: |
782
+ -- Get the most recent order per customer
783
+ SELECT DISTINCT ON (customer_id)
784
+ customer_id, order_id, created_at, total
785
+ FROM orders
786
+ ORDER BY customer_id, created_at DESC;
787
+ level: intermediate
788
+ source: https://www.postgresql.org/docs/current/sql-select.html#SQL-DISTINCT
789
+
790
+ - id: sql-007
791
+ topic: sql
792
+ title: Use partial indexes for filtered queries
793
+ body: >
794
+ A partial index only indexes rows matching a WHERE condition. Smaller
795
+ and faster than a full index for queries that always filter the same way.
796
+ example: |
797
+ -- Only index active users (most queries filter on active)
798
+ CREATE INDEX idx_active_users ON users (email)
799
+ WHERE is_active = true;
800
+ level: advanced
801
+ source: https://www.postgresql.org/docs/current/indexes-partial.html
802
+
803
+ - id: sql-008
804
+ topic: sql
805
+ title: Use LATERAL joins for row-dependent subqueries
806
+ body: >
807
+ LATERAL lets a subquery reference columns from preceding FROM items.
808
+ Think of it as a SQL foreach loop.
809
+ example: |
810
+ SELECT u.name, recent.title
811
+ FROM users u
812
+ CROSS JOIN LATERAL (
813
+ SELECT title FROM posts
814
+ WHERE posts.user_id = u.id
815
+ ORDER BY created_at DESC LIMIT 3
816
+ ) AS recent;
817
+ level: advanced
818
+ source: https://www.postgresql.org/docs/current/queries-table-expressions.html#QUERIES-LATERAL
819
+
820
+ - id: sql-009
821
+ topic: sql
822
+ title: Use RETURNING to get affected rows
823
+ body: >
824
+ The RETURNING clause returns data from rows modified by INSERT, UPDATE,
825
+ or DELETE, saving you an extra SELECT query.
826
+ example: |
827
+ INSERT INTO users (name, email)
828
+ VALUES ('Alice', 'alice@example.com')
829
+ RETURNING id, created_at;
830
+
831
+ UPDATE orders SET status = 'shipped'
832
+ WHERE status = 'pending'
833
+ RETURNING id, customer_id;
834
+ level: intermediate
835
+ source: https://www.postgresql.org/docs/current/dml-returning.html
836
+
837
+ - id: sql-010
838
+ topic: sql
839
+ title: Use CASE for conditional logic in queries
840
+ body: >
841
+ CASE expressions let you add if/else logic directly in SQL queries.
842
+ Works in SELECT, WHERE, ORDER BY, and aggregate functions.
843
+ example: |
844
+ SELECT name,
845
+ CASE
846
+ WHEN age < 18 THEN 'minor'
847
+ WHEN age < 65 THEN 'adult'
848
+ ELSE 'senior'
849
+ END AS age_group,
850
+ COUNT(*) FILTER (WHERE status = 'active') AS active_count
851
+ FROM users
852
+ GROUP BY name, age;
853
+ level: beginner
854
+ source: https://www.postgresql.org/docs/current/functions-conditional.html
855
+
856
+ - id: sql-011
857
+ topic: sql
858
+ title: Use UPSERT to insert or update in one statement
859
+ body: >
860
+ INSERT ... ON CONFLICT handles the common "insert if new, update if exists"
861
+ pattern in a single atomic statement.
862
+ example: |
863
+ INSERT INTO counters (page, hits)
864
+ VALUES ('home', 1)
865
+ ON CONFLICT (page)
866
+ DO UPDATE SET hits = counters.hits + 1;
867
+ level: intermediate
868
+ source: https://www.postgresql.org/docs/current/sql-insert.html#SQL-ON-CONFLICT
869
+
870
+ - id: sql-012
871
+ topic: sql
872
+ title: Use generate_series for test data
873
+ body: >
874
+ generate_series() creates rows on the fly. Perfect for generating test data,
875
+ filling date gaps, or creating sequences.
876
+ example: |
877
+ -- Generate dates for the past 30 days
878
+ SELECT date::date
879
+ FROM generate_series(
880
+ NOW() - INTERVAL '30 days', NOW(), '1 day'
881
+ ) AS date;
882
+
883
+ -- Generate 1000 test users
884
+ INSERT INTO users (name, email)
885
+ SELECT 'user_' || n, 'user' || n || '@test.com'
886
+ FROM generate_series(1, 1000) AS n;
887
+ level: intermediate
888
+ source: https://www.postgresql.org/docs/current/functions-srf.html
889
+
890
+ - id: sql-013
891
+ topic: sql
892
+ title: Use jsonb for flexible schema data
893
+ body: >
894
+ PostgreSQL's jsonb stores JSON in a binary format with full indexing
895
+ support. Perfect for semi-structured data alongside regular columns.
896
+ example: |
897
+ CREATE TABLE events (
898
+ id serial PRIMARY KEY,
899
+ type text NOT NULL,
900
+ data jsonb NOT NULL
901
+ );
902
+
903
+ -- Query nested JSON
904
+ SELECT data->>'email' FROM events
905
+ WHERE data @> '{"role": "admin"}';
906
+
907
+ -- Index for fast lookups
908
+ CREATE INDEX idx_events_data ON events USING gin (data);
909
+ level: advanced
910
+ source: https://www.postgresql.org/docs/current/datatype-json.html
911
+
912
+ - id: sql-014
913
+ topic: sql
914
+ title: Use transactions to group related changes
915
+ body: >
916
+ Wrap related INSERT/UPDATE/DELETE statements in a transaction so they
917
+ either all succeed or all roll back together.
918
+ example: |
919
+ BEGIN;
920
+ UPDATE accounts SET balance = balance - 100 WHERE id = 1;
921
+ UPDATE accounts SET balance = balance + 100 WHERE id = 2;
922
+ COMMIT;
923
+ -- If anything fails, both changes are rolled back
924
+ level: beginner
925
+ source: https://www.postgresql.org/docs/current/tutorial-transactions.html
926
+
927
+ - id: sql-015
928
+ topic: sql
929
+ title: Use string_agg to concatenate grouped rows
930
+ body: >
931
+ string_agg() combines multiple row values into a single delimited string
932
+ within a GROUP BY. Useful for comma-separated lists.
933
+ example: |
934
+ SELECT department,
935
+ string_agg(name, ', ' ORDER BY name) AS members
936
+ FROM employees
937
+ GROUP BY department;
938
+ -- Result: "Engineering" | "Alice, Bob, Charlie"
939
+ level: beginner
940
+ source: https://www.postgresql.org/docs/current/functions-aggregate.html
941
+
942
+ # =============================================================================
943
+ # Linux tips
944
+ # =============================================================================
945
+
946
+ - id: linux-001
947
+ topic: linux
948
+ title: Use ctrl+r for reverse history search
949
+ body: >
950
+ Press ctrl+r in your terminal to search through your command history.
951
+ Keep pressing ctrl+r to cycle through matches.
952
+ example: |
953
+ # Press ctrl+r, then type 'docker'
954
+ # It will find your last command containing 'docker'
955
+ (reverse-i-search)`docker': docker compose up -d
956
+ level: beginner
957
+ source: https://www.gnu.org/software/bash/manual/bash.html
958
+
959
+ - id: linux-002
960
+ topic: linux
961
+ title: Use xargs to pass stdin as arguments
962
+ body: >
963
+ xargs reads items from stdin and executes a command with those items
964
+ as arguments. Combine with find or grep for powerful pipelines.
965
+ example: |
966
+ # Delete all .pyc files
967
+ find . -name "*.pyc" | xargs rm
968
+ # Run tests for changed files
969
+ git diff --name-only | grep test | xargs pytest
970
+ level: intermediate
971
+ source: https://man7.org/linux/man-pages/man1/xargs.1.html
972
+
973
+ - id: linux-003
974
+ topic: linux
975
+ title: Use tee to write to file and stdout
976
+ body: >
977
+ The tee command reads from stdin and writes to both stdout and a file.
978
+ Useful for logging command output while still seeing it.
979
+ example: |
980
+ # Save build output to file while watching it
981
+ make build 2>&1 | tee build.log
982
+ level: intermediate
983
+ source: https://man7.org/linux/man-pages/man1/tee.1.html
984
+
985
+ - id: linux-004
986
+ topic: linux
987
+ title: Use watch to repeat a command
988
+ body: >
989
+ The watch command runs a command repeatedly and displays the output.
990
+ Great for monitoring changing values.
991
+ example: |
992
+ # Watch pod status every 2 seconds
993
+ watch -n 2 kubectl get pods
994
+ # Watch disk usage
995
+ watch df -h
996
+ level: beginner
997
+ source: https://man7.org/linux/man-pages/man1/watch.1.html
998
+
999
+ - id: linux-005
1000
+ topic: linux
1001
+ title: Use curly braces for quick file operations
1002
+ body: >
1003
+ Brace expansion generates multiple strings from a pattern. Useful for
1004
+ creating backups, renaming, or operating on similar paths.
1005
+ example: |
1006
+ # Create a backup
1007
+ cp config.yaml{,.bak}
1008
+ # Create multiple directories
1009
+ mkdir -p project/{src,tests,docs}
1010
+ # Rename extension
1011
+ mv app.{js,ts}
1012
+ level: beginner
1013
+ source: https://www.gnu.org/software/bash/manual/bash.html#Brace-Expansion
1014
+
1015
+ - id: linux-006
1016
+ topic: linux
1017
+ title: Use process substitution for diff-like comparisons
1018
+ body: >
1019
+ Process substitution <() lets you use command output as if it were a file.
1020
+ Perfect for comparing outputs of two commands.
1021
+ example: |
1022
+ # Compare two branches' file lists
1023
+ diff <(git ls-tree -r --name-only main) <(git ls-tree -r --name-only dev)
1024
+ # Compare sorted outputs
1025
+ diff <(sort file1.txt) <(sort file2.txt)
1026
+ level: advanced
1027
+ source: https://www.gnu.org/software/bash/manual/bash.html#Process-Substitution
1028
+
1029
+ - id: linux-007
1030
+ topic: linux
1031
+ title: Use trap to clean up on script exit
1032
+ body: >
1033
+ The trap command runs a function when your script exits, whether
1034
+ normally or due to an error. Essential for cleaning up temp files.
1035
+ example: |
1036
+ #!/bin/bash
1037
+ tmpfile=$(mktemp)
1038
+ trap "rm -f $tmpfile" EXIT
1039
+
1040
+ # Script runs... temp file is always cleaned up
1041
+ curl -o "$tmpfile" https://example.com/data
1042
+ process "$tmpfile"
1043
+ level: intermediate
1044
+ source: https://www.gnu.org/software/bash/manual/bash.html#Bourne-Shell-Builtins
1045
+
1046
+ - id: linux-008
1047
+ topic: linux
1048
+ title: Use ss instead of netstat for network info
1049
+ body: >
1050
+ ss (socket statistics) is faster and more informative than netstat.
1051
+ It's the modern replacement on Linux systems.
1052
+ example: |
1053
+ # List listening TCP ports
1054
+ ss -tlnp
1055
+ # Show established connections
1056
+ ss -tn state established
1057
+ # Find what's using port 8080
1058
+ ss -tlnp | grep 8080
1059
+ level: intermediate
1060
+ source: https://man7.org/linux/man-pages/man8/ss.8.html
1061
+
1062
+ - id: linux-009
1063
+ topic: linux
1064
+ title: Use set -euo pipefail in bash scripts
1065
+ body: >
1066
+ This combination makes bash scripts fail fast on errors instead of
1067
+ silently continuing. Essential for reliable scripts.
1068
+ example: |
1069
+ #!/bin/bash
1070
+ set -euo pipefail
1071
+ # -e: exit on error
1072
+ # -u: error on undefined variables
1073
+ # -o pipefail: catch errors in piped commands
1074
+ level: beginner
1075
+ source: https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin
1076
+
1077
+ - id: linux-010
1078
+ topic: linux
1079
+ title: Use jq to parse JSON on the command line
1080
+ body: >
1081
+ jq is a lightweight command-line JSON processor. It can filter, transform,
1082
+ and format JSON data from APIs and files.
1083
+ example: |
1084
+ # Pretty-print JSON
1085
+ curl -s api.example.com/users | jq '.'
1086
+ # Extract specific fields
1087
+ cat data.json | jq '.users[] | {name, email}'
1088
+ # Filter by condition
1089
+ jq '.items[] | select(.price > 100)' catalog.json
1090
+ level: intermediate
1091
+ source: https://jqlang.github.io/jq/manual/
1092
+
1093
+ - id: linux-011
1094
+ topic: linux
1095
+ title: Use rsync instead of cp for large copies
1096
+ body: >
1097
+ rsync only transfers changed files and can resume interrupted transfers.
1098
+ Far better than cp for large directories or remote copies.
1099
+ example: |
1100
+ # Copy directory (only changed files)
1101
+ rsync -avz src/ dest/
1102
+ # Copy to remote with progress
1103
+ rsync -avz --progress ./data user@server:/backup/
1104
+ # Dry run to preview changes
1105
+ rsync -avzn src/ dest/
1106
+ level: intermediate
1107
+ source: https://man7.org/linux/man-pages/man1/rsync.1.html
1108
+
1109
+ - id: linux-012
1110
+ topic: linux
1111
+ title: Use !! to repeat the last command
1112
+ body: >
1113
+ `!!` expands to your last command. Most commonly used with sudo when
1114
+ you forgot to run something as root.
1115
+ example: |
1116
+ apt install nginx
1117
+ # Permission denied
1118
+ sudo !!
1119
+ # Expands to: sudo apt install nginx
1120
+ level: beginner
1121
+ source: https://www.gnu.org/software/bash/manual/bash.html#Event-Designators
1122
+
1123
+ - id: linux-013
1124
+ topic: linux
1125
+ title: Use column to format command output as a table
1126
+ body: >
1127
+ The column command formats text into aligned columns.
1128
+ Pipe any delimited output through it for instant readability.
1129
+ example: |
1130
+ # Format CSV as table
1131
+ cat data.csv | column -t -s ','
1132
+ # Format mount output
1133
+ mount | column -t
1134
+ level: beginner
1135
+ source: https://man7.org/linux/man-pages/man1/column.1.html
1136
+
1137
+ - id: linux-014
1138
+ topic: linux
1139
+ title: Use nohup to keep commands running after logout
1140
+ body: >
1141
+ nohup prevents a command from being killed when you close the terminal.
1142
+ Output is saved to nohup.out by default.
1143
+ example: |
1144
+ # Run a long process that survives logout
1145
+ nohup python train_model.py &
1146
+ # Check output later
1147
+ tail -f nohup.out
1148
+ level: intermediate
1149
+ source: https://man7.org/linux/man-pages/man1/nohup.1.html
1150
+
1151
+ - id: linux-015
1152
+ topic: linux
1153
+ title: Use lsof to find what's using a file or port
1154
+ body: >
1155
+ lsof (list open files) shows which processes have a file or port open.
1156
+ Essential for debugging "address already in use" errors.
1157
+ example: |
1158
+ # Find what's using port 8080
1159
+ lsof -i :8080
1160
+ # Find who has a file open
1161
+ lsof /var/log/syslog
1162
+ # List all files opened by a process
1163
+ lsof -p 1234
1164
+ level: intermediate
1165
+ source: https://man7.org/linux/man-pages/man8/lsof.8.html
1166
+
1167
+ # =============================================================================
1168
+ # Kubernetes tips
1169
+ # =============================================================================
1170
+
1171
+ - id: k8s-001
1172
+ topic: kubernetes
1173
+ title: Use kubectl explain to explore resource specs
1174
+ body: >
1175
+ `kubectl explain` shows the schema for any Kubernetes resource field.
1176
+ No need to look up docs — it's built into the CLI.
1177
+ example: |
1178
+ kubectl explain pod.spec.containers
1179
+ kubectl explain deployment.spec.strategy
1180
+ # Recursive view
1181
+ kubectl explain pod.spec --recursive
1182
+ level: beginner
1183
+ source: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_explain/
1184
+
1185
+ - id: k8s-002
1186
+ topic: kubernetes
1187
+ title: Use labels and selectors for everything
1188
+ body: >
1189
+ Labels are key-value pairs attached to resources. Selectors let you query
1190
+ and operate on groups of resources matching specific labels.
1191
+ example: |
1192
+ # Add labels
1193
+ kubectl label pods my-pod env=staging
1194
+
1195
+ # Select by label
1196
+ kubectl get pods -l app=web,env=prod
1197
+ kubectl delete pods -l job=cleanup
1198
+ level: beginner
1199
+ source: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
1200
+
1201
+ - id: k8s-003
1202
+ topic: kubernetes
1203
+ title: Use kubectl port-forward for local debugging
1204
+ body: >
1205
+ port-forward tunnels a local port to a pod or service. Access internal
1206
+ services without exposing them externally.
1207
+ example: |
1208
+ # Forward local 8080 to pod's 80
1209
+ kubectl port-forward pod/my-pod 8080:80
1210
+ # Forward to a service
1211
+ kubectl port-forward svc/my-service 5432:5432
1212
+ # Now connect at localhost:8080 or localhost:5432
1213
+ level: beginner
1214
+ source: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_port-forward/
1215
+
1216
+ - id: k8s-004
1217
+ topic: kubernetes
1218
+ title: Use resource requests and limits
1219
+ body: >
1220
+ Requests guarantee minimum resources for your pod. Limits cap the maximum.
1221
+ Without them, a single pod can starve the entire node.
1222
+ example: |
1223
+ resources:
1224
+ requests:
1225
+ memory: "128Mi"
1226
+ cpu: "250m"
1227
+ limits:
1228
+ memory: "256Mi"
1229
+ cpu: "500m"
1230
+ level: intermediate
1231
+ source: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
1232
+
1233
+ - id: k8s-005
1234
+ topic: kubernetes
1235
+ title: Use kubectl get with custom columns
1236
+ body: >
1237
+ Custom columns let you extract exactly the fields you need from resources.
1238
+ Much more flexible than the default table output.
1239
+ example: |
1240
+ kubectl get pods -o custom-columns=\
1241
+ NAME:.metadata.name,\
1242
+ STATUS:.status.phase,\
1243
+ NODE:.spec.nodeName,\
1244
+ IP:.status.podIP
1245
+ level: intermediate
1246
+ source: https://kubernetes.io/docs/reference/kubectl/
1247
+
1248
+ - id: k8s-006
1249
+ topic: kubernetes
1250
+ title: Use ConfigMaps for non-secret configuration
1251
+ body: >
1252
+ ConfigMaps decouple configuration from container images. Mount them as
1253
+ files or inject as environment variables.
1254
+ example: |
1255
+ # Create from file
1256
+ kubectl create configmap app-config --from-file=config.yaml
1257
+
1258
+ # Use in pod
1259
+ envFrom:
1260
+ - configMapRef:
1261
+ name: app-config
1262
+ # Or mount as volume
1263
+ volumes:
1264
+ - name: config
1265
+ configMap:
1266
+ name: app-config
1267
+ level: intermediate
1268
+ source: https://kubernetes.io/docs/concepts/configuration/configmap/
1269
+
1270
+ - id: k8s-007
1271
+ topic: kubernetes
1272
+ title: Use kubectl rollout to manage deployments
1273
+ body: >
1274
+ rollout commands let you check status, pause, resume, or undo deployments.
1275
+ Use undo to instantly roll back a bad release.
1276
+ example: |
1277
+ # Check rollout status
1278
+ kubectl rollout status deployment/my-app
1279
+ # Roll back to previous version
1280
+ kubectl rollout undo deployment/my-app
1281
+ # Roll back to specific revision
1282
+ kubectl rollout undo deployment/my-app --to-revision=3
1283
+ level: beginner
1284
+ source: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_rollout/
1285
+
1286
+ - id: k8s-008
1287
+ topic: kubernetes
1288
+ title: Use liveness and readiness probes
1289
+ body: >
1290
+ Liveness probes restart unhealthy containers. Readiness probes stop sending
1291
+ traffic to containers that aren't ready. Both are essential for reliability.
1292
+ example: |
1293
+ livenessProbe:
1294
+ httpGet:
1295
+ path: /healthz
1296
+ port: 8080
1297
+ initialDelaySeconds: 5
1298
+ periodSeconds: 10
1299
+ readinessProbe:
1300
+ httpGet:
1301
+ path: /ready
1302
+ port: 8080
1303
+ initialDelaySeconds: 3
1304
+ periodSeconds: 5
1305
+ level: intermediate
1306
+ source: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
1307
+
1308
+ - id: k8s-009
1309
+ topic: kubernetes
1310
+ title: Use kubectl debug for troubleshooting
1311
+ body: >
1312
+ kubectl debug creates ephemeral containers in a running pod or a copy of
1313
+ it. Debug without modifying the original pod spec.
1314
+ example: |
1315
+ # Attach a debug container to a running pod
1316
+ kubectl debug -it my-pod --image=busybox --target=my-container
1317
+ # Create a debug copy of a pod
1318
+ kubectl debug my-pod -it --copy-to=my-debug --container=debug
1319
+ level: advanced
1320
+ source: https://kubernetes.io/docs/tasks/debug/debug-application/debug-running-pod/
1321
+
1322
+ - id: k8s-010
1323
+ topic: kubernetes
1324
+ title: Use kubectl dry-run for safe testing
1325
+ body: >
1326
+ --dry-run=client validates your YAML without applying it. Combine with
1327
+ -o yaml to generate resource manifests from imperative commands.
1328
+ example: |
1329
+ # Validate without applying
1330
+ kubectl apply -f deployment.yaml --dry-run=client
1331
+ # Generate YAML from imperative command
1332
+ kubectl create deployment nginx --image=nginx \
1333
+ --dry-run=client -o yaml > deployment.yaml
1334
+ level: beginner
1335
+ source: https://kubernetes.io/docs/reference/kubectl/
1336
+
1337
+ # =============================================================================
1338
+ # Vim tips
1339
+ # =============================================================================
1340
+
1341
+ - id: vim-001
1342
+ topic: vim
1343
+ title: Use ciw to change a word quickly
1344
+ body: >
1345
+ `ciw` (change inner word) deletes the word under the cursor and enters
1346
+ insert mode. Works anywhere in the word, not just the start.
1347
+ example: |
1348
+ # Cursor on "hello" in: print("hello")
1349
+ ciw → deletes "hello", enter insert mode
1350
+ # Type new word: print("world")
1351
+ # Also: diw (delete), yiw (yank/copy)
1352
+ level: beginner
1353
+ source: https://vimhelp.org/motion.txt.html#text-objects
1354
+
1355
+ - id: vim-002
1356
+ topic: vim
1357
+ title: Use . to repeat the last change
1358
+ body: >
1359
+ The dot command repeats your last edit. Plan your edits so they're
1360
+ repeatable, then use . to apply them everywhere.
1361
+ example: |
1362
+ # Change "foo" to "bar" on current line
1363
+ /foo<Enter> → find "foo"
1364
+ cw bar<Esc> → change word to "bar"
1365
+ n → jump to next "foo"
1366
+ . → repeat the change
1367
+ level: beginner
1368
+ source: https://vimhelp.org/repeat.txt.html#single-repeat
1369
+
1370
+ - id: vim-003
1371
+ topic: vim
1372
+ title: Use visual block mode for column editing
1373
+ body: >
1374
+ Ctrl-v enters visual block mode for rectangular selections.
1375
+ Select a column, then insert, delete, or replace text across all lines.
1376
+ example: |
1377
+ # Add "//" comment prefix to lines 5-15:
1378
+ 5G → go to line 5
1379
+ Ctrl-v → enter block mode
1380
+ 10j → select down 10 lines
1381
+ I// <Esc> → insert "// " at the start of each line
1382
+ level: intermediate
1383
+ source: https://vimhelp.org/visual.txt.html#blockwise-visual
1384
+
1385
+ - id: vim-004
1386
+ topic: vim
1387
+ title: Use marks to jump between locations
1388
+ body: >
1389
+ Marks save cursor positions you can jump back to. Lowercase marks are
1390
+ per-file, uppercase marks work across files.
1391
+ example: |
1392
+ ma → set mark 'a' at current position
1393
+ 'a → jump back to mark 'a' (line)
1394
+ `a → jump back to mark 'a' (exact position)
1395
+ '' → jump to position before last jump
1396
+ '. → jump to last edited line
1397
+ level: intermediate
1398
+ source: https://vimhelp.org/motion.txt.html#mark-motions
1399
+
1400
+ - id: vim-005
1401
+ topic: vim
1402
+ title: Use text objects for precise editing
1403
+ body: >
1404
+ Text objects select structured chunks of text. "i" means inner (without
1405
+ delimiters), "a" means around (with delimiters).
1406
+ example: |
1407
+ ci" → change inside quotes
1408
+ da( → delete around parentheses (including them)
1409
+ vi{ → visually select inside curly braces
1410
+ yat → yank (copy) around HTML tag
1411
+ cit → change inside HTML tag
1412
+ level: intermediate
1413
+ source: https://vimhelp.org/motion.txt.html#object-select
1414
+
1415
+ - id: vim-006
1416
+ topic: vim
1417
+ title: Use macros to automate repetitive edits
1418
+ body: >
1419
+ Record a sequence of commands as a macro, then replay it any number
1420
+ of times. Perfect for repetitive formatting or refactoring.
1421
+ example: |
1422
+ qa → start recording macro 'a'
1423
+ 0 → go to start of line
1424
+ i"<Esc> → insert quote
1425
+ A",<Esc> → append quote and comma
1426
+ j → move to next line
1427
+ q → stop recording
1428
+ 10@a → replay macro 10 times
1429
+ level: intermediate
1430
+ source: https://vimhelp.org/repeat.txt.html#complex-repeat
1431
+
1432
+ - id: vim-007
1433
+ topic: vim
1434
+ title: Use buffers instead of tabs
1435
+ body: >
1436
+ Buffers are Vim's way of holding open files. They're more efficient than
1437
+ tabs. Use :ls to list them and :b to switch.
1438
+ example: |
1439
+ :e file.py → open file in new buffer
1440
+ :ls → list all open buffers
1441
+ :b 3 → switch to buffer 3
1442
+ :b main → switch to buffer matching "main"
1443
+ :bd → close current buffer
1444
+ level: beginner
1445
+ source: https://vimhelp.org/windows.txt.html#buffers
1446
+
1447
+ - id: vim-008
1448
+ topic: vim
1449
+ title: Use :g for global commands on matching lines
1450
+ body: >
1451
+ The :g command executes an action on every line matching a pattern.
1452
+ It's like grep + sed combined inside Vim.
1453
+ example: |
1454
+ :g/TODO/d → delete all lines containing "TODO"
1455
+ :g/^$/d → delete all blank lines
1456
+ :g/debug/normal A // FIXME
1457
+ :g!/pattern/d → delete lines NOT matching pattern
1458
+ level: advanced
1459
+ source: https://vimhelp.org/repeat.txt.html#:global
1460
+
1461
+ - id: vim-009
1462
+ topic: vim
1463
+ title: Use Ctrl-o and Ctrl-i to navigate jumplist
1464
+ body: >
1465
+ Vim remembers every position you jump from. Ctrl-o goes back through
1466
+ your jump history, Ctrl-i goes forward.
1467
+ example: |
1468
+ # You're in file_a.py, jump to file_b.py
1469
+ Ctrl-o → jump back to file_a.py
1470
+ Ctrl-o → jump back further
1471
+ Ctrl-i → jump forward again
1472
+ :jumps → show full jump history
1473
+ level: beginner
1474
+ source: https://vimhelp.org/motion.txt.html#jumplist
1475
+
1476
+ - id: vim-010
1477
+ topic: vim
1478
+ title: Use :s for search and replace
1479
+ body: >
1480
+ Vim's substitute command is powerful and supports regex. Use flags to
1481
+ control scope and confirmation.
1482
+ example: |
1483
+ :s/old/new/ → replace first on current line
1484
+ :s/old/new/g → replace all on current line
1485
+ :%s/old/new/g → replace all in file
1486
+ :%s/old/new/gc → replace all with confirmation
1487
+ :5,20s/old/new/g → replace in lines 5-20
1488
+ level: beginner
1489
+ source: https://vimhelp.org/change.txt.html#:substitute
1490
+
1491
+ # =============================================================================
1492
+ # JavaScript tips
1493
+ # =============================================================================
1494
+
1495
+ - id: js-001
1496
+ topic: javascript
1497
+ title: Use optional chaining to access nested properties
1498
+ body: >
1499
+ The ?. operator short-circuits to undefined if any part of the chain
1500
+ is null or undefined. No more "Cannot read property of undefined" errors.
1501
+ example: |
1502
+ // Instead of: user && user.address && user.address.city
1503
+ const city = user?.address?.city;
1504
+ const first = arr?.[0];
1505
+ const result = obj?.method?.();
1506
+ level: beginner
1507
+ source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
1508
+
1509
+ - id: js-002
1510
+ topic: javascript
1511
+ title: Use destructuring for cleaner function parameters
1512
+ body: >
1513
+ Destructuring in function parameters makes it clear what a function
1514
+ expects and provides easy defaults.
1515
+ example: |
1516
+ function createUser({ name, role = "viewer", active = true }) {
1517
+ return { name, role, active };
1518
+ }
1519
+
1520
+ createUser({ name: "Alice" });
1521
+ // { name: "Alice", role: "viewer", active: true }
1522
+ level: beginner
1523
+ source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
1524
+
1525
+ - id: js-003
1526
+ topic: javascript
1527
+ title: Use Promise.all for parallel async operations
1528
+ body: >
1529
+ Promise.all runs multiple promises concurrently and waits for all to
1530
+ complete. Much faster than awaiting them sequentially.
1531
+ example: |
1532
+ // Slow: sequential
1533
+ const users = await fetchUsers();
1534
+ const posts = await fetchPosts();
1535
+
1536
+ // Fast: parallel
1537
+ const [users, posts] = await Promise.all([
1538
+ fetchUsers(),
1539
+ fetchPosts(),
1540
+ ]);
1541
+ level: intermediate
1542
+ source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
1543
+
1544
+ - id: js-004
1545
+ topic: javascript
1546
+ title: Use Array.from for array-like conversions
1547
+ body: >
1548
+ Array.from converts iterables and array-like objects to real arrays.
1549
+ Its second argument is a map function.
1550
+ example: |
1551
+ // NodeList to Array
1552
+ const divs = Array.from(document.querySelectorAll("div"));
1553
+
1554
+ // Generate a sequence
1555
+ const nums = Array.from({ length: 5 }, (_, i) => i + 1);
1556
+ // [1, 2, 3, 4, 5]
1557
+ level: beginner
1558
+ source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
1559
+
1560
+ - id: js-005
1561
+ topic: javascript
1562
+ title: Use structuredClone for deep copying
1563
+ body: >
1564
+ structuredClone() creates a true deep copy of objects, handling nested
1565
+ objects, arrays, Maps, Sets, and Dates correctly.
1566
+ example: |
1567
+ const original = { user: { name: "Alice" }, tags: [1, 2] };
1568
+
1569
+ // Shallow copy (nested objects still shared)
1570
+ const shallow = { ...original };
1571
+
1572
+ // Deep copy (fully independent)
1573
+ const deep = structuredClone(original);
1574
+ deep.user.name = "Bob"; // original unchanged
1575
+ level: intermediate
1576
+ source: https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone
1577
+
1578
+ - id: js-006
1579
+ topic: javascript
1580
+ title: Use AbortController to cancel fetch requests
1581
+ body: >
1582
+ AbortController lets you cancel in-flight fetch requests. Essential for
1583
+ search-as-you-type and component unmounting.
1584
+ example: |
1585
+ const controller = new AbortController();
1586
+
1587
+ fetch("/api/data", { signal: controller.signal })
1588
+ .then(res => res.json())
1589
+ .catch(err => {
1590
+ if (err.name === "AbortError") return; // expected
1591
+ throw err;
1592
+ });
1593
+
1594
+ // Cancel the request
1595
+ controller.abort();
1596
+ level: intermediate
1597
+ source: https://developer.mozilla.org/en-US/docs/Web/API/AbortController
1598
+
1599
+ - id: js-007
1600
+ topic: javascript
1601
+ title: Use Map instead of objects for dynamic keys
1602
+ body: >
1603
+ Map preserves insertion order, supports any key type (not just strings),
1604
+ and has better performance for frequent additions/deletions.
1605
+ example: |
1606
+ const cache = new Map();
1607
+ cache.set(userObj, "data"); // objects as keys!
1608
+ cache.set(42, "answer"); // numbers as keys
1609
+
1610
+ cache.has(userObj); // true
1611
+ cache.size; // 2
1612
+ cache.delete(42);
1613
+
1614
+ for (const [key, value] of cache) { ... }
1615
+ level: intermediate
1616
+ source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
1617
+
1618
+ - id: js-008
1619
+ topic: javascript
1620
+ title: Use at() for negative array indexing
1621
+ body: >
1622
+ The at() method supports negative indices to count from the end.
1623
+ Cleaner than arr[arr.length - 1] for getting the last element.
1624
+ example: |
1625
+ const arr = [1, 2, 3, 4, 5];
1626
+ arr.at(0); // 1
1627
+ arr.at(-1); // 5 (last)
1628
+ arr.at(-2); // 4 (second to last)
1629
+
1630
+ // Works on strings too
1631
+ "hello".at(-1); // "o"
1632
+ level: beginner
1633
+ source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at
1634
+
1635
+ - id: js-009
1636
+ topic: javascript
1637
+ title: Use Object.groupBy to group array items
1638
+ body: >
1639
+ Object.groupBy groups array elements by a key function. Replaces
1640
+ manual reduce-based grouping patterns.
1641
+ example: |
1642
+ const people = [
1643
+ { name: "Alice", dept: "eng" },
1644
+ { name: "Bob", dept: "sales" },
1645
+ { name: "Charlie", dept: "eng" },
1646
+ ];
1647
+
1648
+ const byDept = Object.groupBy(people, p => p.dept);
1649
+ // { eng: [{Alice}, {Charlie}], sales: [{Bob}] }
1650
+ level: intermediate
1651
+ source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy
1652
+
1653
+ - id: js-010
1654
+ topic: javascript
1655
+ title: Use WeakRef for memory-safe caching
1656
+ body: >
1657
+ WeakRef holds a reference that doesn't prevent garbage collection.
1658
+ Combine with FinalizationRegistry for automatic cache cleanup.
1659
+ example: |
1660
+ const cache = new Map();
1661
+
1662
+ function getCached(key, compute) {
1663
+ const ref = cache.get(key);
1664
+ const value = ref?.deref();
1665
+ if (value !== undefined) return value;
1666
+
1667
+ const result = compute();
1668
+ cache.set(key, new WeakRef(result));
1669
+ return result;
1670
+ }
1671
+ level: advanced
1672
+ source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef
1673
+
1674
+ # =============================================================================
1675
+ # Terraform tips
1676
+ # =============================================================================
1677
+
1678
+ - id: tf-001
1679
+ topic: terraform
1680
+ title: Use variables with validation rules
1681
+ body: >
1682
+ Variable blocks support validation conditions that catch bad input
1683
+ at plan time, before any resources are created.
1684
+ example: |
1685
+ variable "environment" {
1686
+ type = string
1687
+ validation {
1688
+ condition = contains(["dev", "staging", "prod"], var.environment)
1689
+ error_message = "Must be dev, staging, or prod."
1690
+ }
1691
+ }
1692
+ level: beginner
1693
+ source: https://developer.hashicorp.com/terraform/language/values/variables
1694
+
1695
+ - id: tf-002
1696
+ topic: terraform
1697
+ title: Use terraform fmt to format code
1698
+ body: >
1699
+ `terraform fmt` auto-formats your .tf files to a consistent style.
1700
+ Run it before every commit. Use -check in CI to enforce it.
1701
+ example: |
1702
+ # Format current directory
1703
+ terraform fmt
1704
+ # Format recursively
1705
+ terraform fmt -recursive
1706
+ # Check only (for CI) - exit 1 if changes needed
1707
+ terraform fmt -check -recursive
1708
+ level: beginner
1709
+ source: https://developer.hashicorp.com/terraform/cli/commands/fmt
1710
+
1711
+ - id: tf-003
1712
+ topic: terraform
1713
+ title: Use locals to reduce repetition
1714
+ body: >
1715
+ Locals let you define computed values used in multiple places.
1716
+ They simplify complex expressions and reduce copy-paste errors.
1717
+ example: |
1718
+ locals {
1719
+ common_tags = {
1720
+ Environment = var.environment
1721
+ Project = var.project_name
1722
+ ManagedBy = "terraform"
1723
+ }
1724
+ }
1725
+
1726
+ resource "aws_instance" "web" {
1727
+ tags = merge(local.common_tags, { Name = "web-server" })
1728
+ }
1729
+ level: beginner
1730
+ source: https://developer.hashicorp.com/terraform/language/values/locals
1731
+
1732
+ - id: tf-004
1733
+ topic: terraform
1734
+ title: Use terraform plan -out to save plans
1735
+ body: >
1736
+ Save the plan to a file, then apply exactly that plan. This prevents
1737
+ drift between planning and applying in CI/CD pipelines.
1738
+ example: |
1739
+ # Save the plan
1740
+ terraform plan -out=tfplan
1741
+ # Apply exactly what was planned
1742
+ terraform apply tfplan
1743
+ # In CI: plan in one step, review, then apply
1744
+ level: intermediate
1745
+ source: https://developer.hashicorp.com/terraform/cli/commands/plan
1746
+
1747
+ - id: tf-005
1748
+ topic: terraform
1749
+ title: Use data sources to reference existing resources
1750
+ body: >
1751
+ Data sources let you read information about infrastructure that already
1752
+ exists, without managing it. Reference it like any other resource.
1753
+ example: |
1754
+ data "aws_vpc" "main" {
1755
+ filter {
1756
+ name = "tag:Name"
1757
+ values = ["main-vpc"]
1758
+ }
1759
+ }
1760
+
1761
+ resource "aws_subnet" "app" {
1762
+ vpc_id = data.aws_vpc.main.id
1763
+ # ...
1764
+ }
1765
+ level: intermediate
1766
+ source: https://developer.hashicorp.com/terraform/language/data-sources
1767
+
1768
+ - id: tf-006
1769
+ topic: terraform
1770
+ title: Use for_each instead of count for resources
1771
+ body: >
1772
+ for_each creates resources keyed by map or set, so removing an item
1773
+ only destroys that resource. count-based resources shift indexes.
1774
+ example: |
1775
+ variable "buckets" {
1776
+ default = {
1777
+ logs = "my-logs-bucket"
1778
+ assets = "my-assets-bucket"
1779
+ }
1780
+ }
1781
+
1782
+ resource "aws_s3_bucket" "this" {
1783
+ for_each = var.buckets
1784
+ bucket = each.value
1785
+ tags = { Name = each.key }
1786
+ }
1787
+ level: intermediate
1788
+ source: https://developer.hashicorp.com/terraform/language/meta-arguments/for_each
1789
+
1790
+ - id: tf-007
1791
+ topic: terraform
1792
+ title: Use lifecycle to prevent accidental destruction
1793
+ body: >
1794
+ The prevent_destroy lifecycle rule stops Terraform from destroying
1795
+ critical resources like databases or storage buckets.
1796
+ example: |
1797
+ resource "aws_db_instance" "main" {
1798
+ # ...
1799
+ lifecycle {
1800
+ prevent_destroy = true
1801
+ }
1802
+ }
1803
+
1804
+ # Also useful: create_before_destroy for zero-downtime
1805
+ lifecycle {
1806
+ create_before_destroy = true
1807
+ }
1808
+ level: intermediate
1809
+ source: https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle
1810
+
1811
+ - id: tf-008
1812
+ topic: terraform
1813
+ title: Use moved blocks for safe refactoring
1814
+ body: >
1815
+ The moved block tells Terraform that a resource was renamed, not deleted
1816
+ and recreated. Prevents accidental destruction during refactors.
1817
+ example: |
1818
+ # Renamed aws_instance.web to aws_instance.app
1819
+ moved {
1820
+ from = aws_instance.web
1821
+ to = aws_instance.app
1822
+ }
1823
+
1824
+ resource "aws_instance" "app" {
1825
+ # ...
1826
+ }
1827
+ level: advanced
1828
+ source: https://developer.hashicorp.com/terraform/language/modules/develop/refactoring
1829
+
1830
+ - id: tf-009
1831
+ topic: terraform
1832
+ title: Use terraform import to adopt existing resources
1833
+ body: >
1834
+ `terraform import` brings an existing resource under Terraform management.
1835
+ In Terraform 1.5+, you can use import blocks declaratively.
1836
+ example: |
1837
+ # Declarative import (1.5+)
1838
+ import {
1839
+ to = aws_instance.web
1840
+ id = "i-abc123"
1841
+ }
1842
+
1843
+ # Then run: terraform plan
1844
+ # Terraform generates the config diff
1845
+ level: advanced
1846
+ source: https://developer.hashicorp.com/terraform/language/import
1847
+
1848
+ - id: tf-010
1849
+ topic: terraform
1850
+ title: Use terraform state list to audit resources
1851
+ body: >
1852
+ `terraform state list` shows all resources Terraform manages.
1853
+ Use it to audit what's tracked and find resources to remove or move.
1854
+ example: |
1855
+ # List all managed resources
1856
+ terraform state list
1857
+ # Filter by type
1858
+ terraform state list | grep aws_instance
1859
+ # Show details of one resource
1860
+ terraform state show aws_instance.web
1861
+ # Remove from state (without destroying)
1862
+ terraform state rm aws_instance.legacy
1863
+ level: beginner
1864
+ source: https://developer.hashicorp.com/terraform/cli/commands/state/list
1865
+
1866
+ # =============================================================================
1867
+ # Rust tips
1868
+ # =============================================================================
1869
+
1870
+ - id: rust-001
1871
+ topic: rust
1872
+ title: Use if let for single-pattern matching
1873
+ body: >
1874
+ `if let` is cleaner than match when you only care about one variant.
1875
+ Great for Option and Result handling.
1876
+ example: |
1877
+ // Instead of:
1878
+ match config.get("port") {
1879
+ Some(port) => println!("Port: {port}"),
1880
+ None => {}
1881
+ }
1882
+ // Use:
1883
+ if let Some(port) = config.get("port") {
1884
+ println!("Port: {port}");
1885
+ }
1886
+ level: beginner
1887
+ source: https://doc.rust-lang.org/book/ch06-03-if-let.html
1888
+
1889
+ - id: rust-002
1890
+ topic: rust
1891
+ title: Use the ? operator for error propagation
1892
+ body: >
1893
+ The ? operator returns early with the error if a Result is Err, or
1894
+ unwraps the Ok value. Replaces verbose match/unwrap chains.
1895
+ example: |
1896
+ fn read_config(path: &str) -> Result<Config, Box<dyn Error>> {
1897
+ let contents = fs::read_to_string(path)?;
1898
+ let config: Config = toml::from_str(&contents)?;
1899
+ Ok(config)
1900
+ }
1901
+ level: beginner
1902
+ source: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
1903
+
1904
+ - id: rust-003
1905
+ topic: rust
1906
+ title: Use iterators instead of manual loops
1907
+ body: >
1908
+ Rust iterators are zero-cost abstractions. Chaining map, filter, and
1909
+ collect is both idiomatic and as fast as hand-written loops.
1910
+ example: |
1911
+ let names: Vec<String> = users
1912
+ .iter()
1913
+ .filter(|u| u.active)
1914
+ .map(|u| u.name.clone())
1915
+ .collect();
1916
+
1917
+ let total: f64 = prices.iter().sum();
1918
+ level: intermediate
1919
+ source: https://doc.rust-lang.org/book/ch13-02-iterators.html
1920
+
1921
+ - id: rust-004
1922
+ topic: rust
1923
+ title: Use derive macros for common traits
1924
+ body: >
1925
+ #[derive] auto-implements traits like Debug, Clone, PartialEq, and
1926
+ Serialize. Saves pages of boilerplate.
1927
+ example: |
1928
+ #[derive(Debug, Clone, PartialEq, serde::Serialize)]
1929
+ struct User {
1930
+ name: String,
1931
+ age: u32,
1932
+ active: bool,
1933
+ }
1934
+
1935
+ // Now you can: println!("{:?}", user);
1936
+ // And: user1 == user2
1937
+ level: beginner
1938
+ source: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html
1939
+
1940
+ - id: rust-005
1941
+ topic: rust
1942
+ title: Use pattern matching with enums
1943
+ body: >
1944
+ Rust enums can hold data in each variant. Combined with match, they
1945
+ replace class hierarchies and visitor patterns.
1946
+ example: |
1947
+ enum Shape {
1948
+ Circle(f64),
1949
+ Rect(f64, f64),
1950
+ }
1951
+
1952
+ fn area(shape: &Shape) -> f64 {
1953
+ match shape {
1954
+ Shape::Circle(r) => std::f64::consts::PI * r * r,
1955
+ Shape::Rect(w, h) => w * h,
1956
+ }
1957
+ }
1958
+ level: intermediate
1959
+ source: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html
1960
+
1961
+ - id: rust-006
1962
+ topic: rust
1963
+ title: Use clippy for idiomatic Rust
1964
+ body: >
1965
+ Clippy catches common mistakes and suggests more idiomatic code.
1966
+ Run it regularly — it's like having a Rust expert review your code.
1967
+ example: |
1968
+ # Run clippy
1969
+ cargo clippy
1970
+ # Treat all warnings as errors (for CI)
1971
+ cargo clippy -- -D warnings
1972
+ # Fix automatically where possible
1973
+ cargo clippy --fix
1974
+ level: beginner
1975
+ source: https://doc.rust-lang.org/clippy/
1976
+
1977
+ - id: rust-007
1978
+ topic: rust
1979
+ title: Use impl blocks with associated functions
1980
+ body: >
1981
+ Associated functions (no &self) are Rust's constructors. By convention,
1982
+ new() creates an instance, but you can name them anything.
1983
+ example: |
1984
+ struct Config {
1985
+ port: u16,
1986
+ debug: bool,
1987
+ }
1988
+
1989
+ impl Config {
1990
+ fn new(port: u16) -> Self {
1991
+ Self { port, debug: false }
1992
+ }
1993
+
1994
+ fn with_debug(mut self) -> Self {
1995
+ self.debug = true;
1996
+ self
1997
+ }
1998
+ }
1999
+
2000
+ let cfg = Config::new(8080).with_debug();
2001
+ level: intermediate
2002
+ source: https://doc.rust-lang.org/book/ch05-03-method-syntax.html
2003
+
2004
+ - id: rust-008
2005
+ topic: rust
2006
+ title: Use Option combinators instead of match
2007
+ body: >
2008
+ Option has methods like map, and_then, unwrap_or, and filter that chain
2009
+ cleanly. Prefer these over verbose match expressions.
2010
+ example: |
2011
+ // Instead of matching:
2012
+ let name = user
2013
+ .get("name")
2014
+ .map(|n| n.to_uppercase())
2015
+ .unwrap_or_else(|| "ANONYMOUS".to_string());
2016
+
2017
+ // Chain with and_then for nested Options
2018
+ let city = user.address.as_ref().and_then(|a| a.city.as_ref());
2019
+ level: intermediate
2020
+ source: https://doc.rust-lang.org/std/option/enum.Option.html
2021
+
2022
+ - id: rust-009
2023
+ topic: rust
2024
+ title: Use cargo test with module tests
2025
+ body: >
2026
+ Rust tests live right next to the code in a #[cfg(test)] module.
2027
+ Private functions are testable without any special setup.
2028
+ example: |
2029
+ fn add(a: i32, b: i32) -> i32 { a + b }
2030
+
2031
+ #[cfg(test)]
2032
+ mod tests {
2033
+ use super::*;
2034
+
2035
+ #[test]
2036
+ fn test_add() {
2037
+ assert_eq!(add(2, 3), 5);
2038
+ }
2039
+
2040
+ #[test]
2041
+ #[should_panic]
2042
+ fn test_overflow() {
2043
+ add(i32::MAX, 1);
2044
+ }
2045
+ }
2046
+ level: beginner
2047
+ source: https://doc.rust-lang.org/book/ch11-01-writing-tests.html
2048
+
2049
+ - id: rust-010
2050
+ topic: rust
2051
+ title: Use traits for shared behavior
2052
+ body: >
2053
+ Traits define shared interfaces. Any type can implement a trait, enabling
2054
+ polymorphism without inheritance.
2055
+ example: |
2056
+ trait Summary {
2057
+ fn summarize(&self) -> String;
2058
+ // Default implementation
2059
+ fn preview(&self) -> String {
2060
+ format!("{}...", &self.summarize()[..50])
2061
+ }
2062
+ }
2063
+
2064
+ impl Summary for Article {
2065
+ fn summarize(&self) -> String {
2066
+ format!("{} by {}", self.title, self.author)
2067
+ }
2068
+ }
2069
+ level: intermediate
2070
+ source: https://doc.rust-lang.org/book/ch10-02-traits.html