diff --git a/lectures/writing_good_code.md b/lectures/writing_good_code.md
new file mode 100644
index 0000000..e23a482
--- /dev/null
+++ b/lectures/writing_good_code.md
@@ -0,0 +1,501 @@
+---
+jupytext:
+ text_representation:
+ extension: .md
+ format_name: myst
+kernelspec:
+ display_name: Python 3
+ language: python
+ name: python3
+heading-map:
+ overview: مرور کلی
+ an-example-of-poor-code: نمونهای از کد ضعیف
+ good-coding-practice: شیوههای کدنویسی خوب
+ dont-use-magic-numbers: از اعداد جادویی استفاده نکنید
+ dont-repeat-yourself: خودتان را تکرار نکنید
+ minimize-global-variables: متغیرهای سراسری را به حداقل برسانید
+ jit-compilation: کامپایل JIT
+ use-functions-or-classes: از توابع یا کلاسها استفاده کنید
+ which-one-functions-or-classes: کدام یک، توابع یا کلاسها؟
+ revisiting-the-example: بازبینی مثال
+ exercises: تمرینها
+---
+
+(writing_good_code)=
+```{raw} jupyter
+
+```
+
+# نوشتن کد خوب
+
+```{index} single: Models; Code style
+```
+
+```{epigraph}
+"هر احمقی میتواند کدی بنویسد که کامپیوتر بتواند درک کند. برنامهنویسان خوب کدی مینویسند که انسانها بتوانند درک کنند." -- مارتین فاولر
+```
+
+
+## مرور کلی
+
+وقتی برنامههای کامپیوتری کوچک هستند، کد بد نوشته شده خیلی پرهزینه نیست.
+
+اما دادههای بیشتر، مدلهای پیچیدهتر و قدرت محاسباتی بیشتر ما را قادر میسازد تا مسائل چالشبرانگیزتری را که شامل نوشتن برنامههای طولانیتر هستند، در پیش بگیریم.
+
+برای چنین برنامههایی، سرمایهگذاری در شیوههای کدنویسی خوب بازدهی بالایی خواهد داشت.
+
+بازدههای اصلی، بهرهوری بالاتر و کد سریعتر هستند.
+
+در این سخنرانی، برخی از عناصر شیوههای کدنویسی خوب را بررسی میکنیم.
+
+همچنین به تحولات مدرن در محاسبات علمی --- مانند کامپایل به موقع --- و چگونگی تأثیر آنها بر طراحی خوب برنامه اشاره میکنیم.
+
+## نمونهای از کد ضعیف
+
+بیایید نگاهی به کد بدی که نوشته شده است بیندازیم.
+
+کار این کد تولید و رسم سریهای زمانی مدل سادهشده سولو است
+
+```{math}
+:label: gc_solmod
+
+k_{t+1} = s k_t^{\alpha} + (1 - \delta) k_t,
+\quad t = 0, 1, 2, \ldots
+```
+
+در اینجا
+
+* $k_t$ سرمایه در زمان $t$ است و
+* $s, \alpha, \delta$ پارامترها هستند (پسانداز، یک پارامتر بهرهوری و استهلاک)
+
+برای هر پارامتربندی، کد
+
+1. $k_0 = 1$ را تنظیم میکند
+1. با استفاده از {eq}`gc_solmod` برای تولید دنباله $k_0, k_1, k_2 \ldots , k_T$ تکرار میکند
+1. دنباله را رسم میکند
+
+نمودارها در سه زیرشکل گروهبندی خواهند شد.
+
+در هر زیرشکل، دو پارامتر ثابت نگه داشته میشوند در حالی که پارامتر دیگر تغییر میکند
+
+```{code-cell} ipython
+import numpy as np
+import matplotlib.pyplot as plt
+
+# Allocate memory for time series
+k = np.empty(50)
+
+fig, axes = plt.subplots(3, 1, figsize=(8, 16))
+
+# Trajectories with different α
+δ = 0.1
+s = 0.4
+α = (0.25, 0.33, 0.45)
+
+for j in range(3):
+ k[0] = 1
+ for t in range(49):
+ k[t+1] = s * k[t]**α[j] + (1 - δ) * k[t]
+ axes[0].plot(k, 'o-', label=rf"$\alpha = {α[j]},\; s = {s},\; \delta={δ}$")
+
+axes[0].grid(lw=0.2)
+axes[0].set_ylim(0, 18)
+axes[0].set_xlabel('time')
+axes[0].set_ylabel('capital')
+axes[0].legend(loc='upper left', frameon=True)
+
+# Trajectories with different s
+δ = 0.1
+α = 0.33
+s = (0.3, 0.4, 0.5)
+
+for j in range(3):
+ k[0] = 1
+ for t in range(49):
+ k[t+1] = s[j] * k[t]**α + (1 - δ) * k[t]
+ axes[1].plot(k, 'o-', label=rf"$\alpha = {α},\; s = {s[j]},\; \delta={δ}$")
+
+axes[1].grid(lw=0.2)
+axes[1].set_xlabel('time')
+axes[1].set_ylabel('capital')
+axes[1].set_ylim(0, 18)
+axes[1].legend(loc='upper left', frameon=True)
+
+# Trajectories with different δ
+δ = (0.05, 0.1, 0.15)
+α = 0.33
+s = 0.4
+
+for j in range(3):
+ k[0] = 1
+ for t in range(49):
+ k[t+1] = s * k[t]**α + (1 - δ[j]) * k[t]
+ axes[2].plot(k, 'o-', label=rf"$\alpha = {α},\; s = {s},\; \delta={δ[j]}$")
+
+axes[2].set_ylim(0, 18)
+axes[2].set_xlabel('time')
+axes[2].set_ylabel('capital')
+axes[2].grid(lw=0.2)
+axes[2].legend(loc='upper left', frameon=True)
+
+plt.show()
+```
+
+درست است، این کد کم و بیش از [PEP8](https://peps.python.org/pep-0008/) پیروی میکند.
+
+در عین حال، ساختار آن بسیار ضعیف است.
+
+بیایید در مورد اینکه چرا چنین است صحبت کنیم، و در مورد آنچه میتوانیم انجام دهیم.
+
+## شیوههای کدنویسی خوب
+
+معمولاً راههای مختلفی برای نوشتن برنامهای که یک وظیفه معین را انجام میدهد وجود دارد.
+
+برای برنامههای کوچک، مانند برنامه بالا، نحوه نوشتن کد چندان مهم نیست.
+
+اما اگر شما جاهطلب هستید و میخواهید چیزهای مفیدی تولید کنید، برنامههای متوسط تا بزرگ نیز خواهید نوشت.
+
+در آن تنظیمات، سبک کدنویسی **بسیار** مهم است.
+
+خوشبختانه، افراد باهوش زیادی در مورد بهترین راه برای نوشتن کد فکر کردهاند.
+
+در اینجا برخی از اصول اولیه آورده شده است.
+
+### از اعداد جادویی استفاده نکنید
+
+اگر به کد بالا نگاه کنید، اعدادی مانند `50` و `49` و `3` را در سرتاسر کد پراکنده خواهید دید.
+
+این نوع مقادیر عددی در بدنه کد شما گاهی اوقات "اعداد جادویی" نامیده میشوند.
+
+این یک تعریف نیست.
+
+در حالی که تمام مقادیر عددی بد نیستند، اعدادی که در برنامه بالا نشان داده شدهاند
+مطمئناً باید با ثابتهای نامگذاری شده جایگزین شوند.
+
+به عنوان مثال، کد بالا میتواند متغیر `time_series_length = 50` را اعلام کند.
+
+سپس در حلقهها، `49` باید با `time_series_length - 1` جایگزین شود.
+
+مزایا اینها هستند:
+
+* معنی در سرتاسر کد بسیار واضحتر است
+* برای تغییر طول سری زمانی، شما فقط نیاز به تغییر یک مقدار دارید
+
+### خودتان را تکرار نکنید
+
+گناه کبیره دیگر در قطعه کد بالا تکرار است.
+
+بلوکهای منطقی (مانند حلقه برای تولید سری زمانی) با تغییرات جزئی تکرار میشوند.
+
+این یک اصل بنیادی برنامهنویسی را نقض میکند: خودتان را تکرار نکنید (DRY).
+
+* همچنین DIE (تکرار شر است) نامیده میشود.
+
+بله، ما میدانیم که شما میتوانید فقط کپی و پیست کنید و چند نماد را تغییر دهید.
+
+اما به عنوان یک برنامهنویس، هدف شما باید **خودکارسازی** تکرار باشد، **نه** انجام آن توسط خودتان.
+
+مهمتر از آن، تکرار منطق یکسان در مکانهای مختلف به این معنی است که در نهایت یکی از آنها احتمالاً اشتباه خواهد بود.
+
+اگر میخواهید بیشتر بدانید، خلاصه عالی موجود در [این صفحه](https://code.tutsplus.com/3-key-software-principles-you-must-understand--net-25161t) را بخوانید.
+
+ما در مورد چگونگی اجتناب از تکرار در زیر صحبت خواهیم کرد.
+
+### متغیرهای سراسری را به حداقل برسانید
+
+مطمئناً، متغیرهای سراسری (یعنی نامهایی که به مقادیر خارج از هر تابع یا کلاس اختصاص داده شدهاند) راحت هستند.
+
+برنامهنویسان مبتدی معمولاً از متغیرهای سراسری بیپروا استفاده میکنند --- همانطور که ما یک زمانی چنین میکردیم.
+
+اما متغیرهای سراسری خطرناک هستند، به خصوص در برنامههای متوسط تا بزرگ، زیرا
+
+* آنها میتوانند بر آنچه در هر بخشی از برنامه شما اتفاق میافتد تأثیر بگذارند
+* آنها میتوانند توسط هر تابع تغییر کنند
+
+این کار اطمینان از آنچه بخش کوچکی از یک قطعه کد خاص واقعاً دستور میدهد را بسیار سختتر میکند.
+
+در اینجا یک [بحث مفید در مورد این موضوع](https://wiki.c2.com/?GlobalVariablesAreBad) وجود دارد.
+
+در حالی که متغیر سراسری فردی در اسکریپتهای کوچک مشکل بزرگی نیست، ما توصیه میکنیم که به خود یاد دهید از آنها اجتناب کنید.
+
+(ما در مورد چگونگی این کار در زیر بحث خواهیم کرد).
+
+#### کامپایل JIT
+
+برای محاسبات علمی، دلیل خوب دیگری برای اجتناب از متغیرهای سراسری وجود دارد.
+
+همانطور که {doc}`در سخنرانیهای قبلی دیدیم `، کامپایل JIT میتواند عملکرد عالی برای زبانهای اسکریپتی مانند Python ایجاد کند.
+
+اما کار کامپایلری که برای کامپایل JIT استفاده میشود زمانی که متغیرهای سراسری وجود دارند سختتر میشود.
+
+به عبارت دیگر، استنتاج نوع مورد نیاز برای کامپایل JIT زمانی امنتر و
+مؤثرتر است که متغیرها در داخل یک تابع ایزوله شوند.
+
+### از توابع یا کلاسها استفاده کنید
+
+خوشبختانه، ما به راحتی میتوانیم از شرارتهای متغیرهای سراسری و کد WET اجتناب کنیم.
+
+* WET مخفف "we enjoy typing" است و مخالف DRY است.
+
+ما میتوانیم این کار را با استفاده مکرر از توابع یا کلاسها انجام دهیم.
+
+در واقع، توابع و کلاسها به طور خاص برای کمک به ما برای جلوگیری از شرمساری خود با تکرار کد یا استفاده بیش از حد از متغیرهای سراسری طراحی شدهاند.
+
+#### کدام یک، توابع یا کلاسها؟
+
+هر دو میتوانند مفید باشند، و در واقع آنها به خوبی با یکدیگر کار میکنند.
+
+ما با گذشت زمان بیشتر در مورد این موضوعات خواهیم آموخت.
+
+(ترجیح شخصی نیز بخشی از موضوع است)
+
+آنچه واقعاً مهم است این است که شما از یکی یا دیگری یا هر دو استفاده کنید.
+
+## بازبینی مثال
+
+در اینجا کدی است که نمودار بالا را با سبک کدنویسی بهتر بازتولید میکند.
+
+```{code-cell} python3
+from itertools import product
+
+def plot_path(ax, αs, s_vals, δs, time_series_length=50):
+ """
+ Add a time series plot to the axes ax for all given parameters.
+ """
+ k = np.empty(time_series_length)
+
+ for (α, s, δ) in product(αs, s_vals, δs):
+ k[0] = 1
+ for t in range(time_series_length-1):
+ k[t+1] = s * k[t]**α + (1 - δ) * k[t]
+ ax.plot(k, 'o-', label=rf"$\alpha = {α},\; s = {s},\; \delta = {δ}$")
+
+ ax.set_xlabel('time')
+ ax.set_ylabel('capital')
+ ax.set_ylim(0, 18)
+ ax.legend(loc='upper left', frameon=True)
+
+fig, axes = plt.subplots(3, 1, figsize=(8, 16))
+
+# Parameters (αs, s_vals, δs)
+set_one = ([0.25, 0.33, 0.45], [0.4], [0.1])
+set_two = ([0.33], [0.3, 0.4, 0.5], [0.1])
+set_three = ([0.33], [0.4], [0.05, 0.1, 0.15])
+
+for (ax, params) in zip(axes, (set_one, set_two, set_three)):
+ αs, s_vals, δs = params
+ plot_path(ax, αs, s_vals, δs)
+
+plt.show()
+```
+
+اگر این کد را بررسی کنید، خواهید دید که
+
+* از یک تابع برای جلوگیری از تکرار استفاده میکند.
+* متغیرهای سراسری با جمعآوری آنها در انتها، نه ابتدای برنامه قرنطینه شدهاند.
+* از اعداد جادویی اجتناب شده است.
+* حلقه در انتها که کار واقعی در آن انجام میشود کوتاه و نسبتاً ساده است.
+
+## تمرینها
+
+```{exercise-start}
+:label: wgc-exercise-1
+```
+
+در اینجا کدی وجود دارد که نیاز به بهبود دارد.
+
+این شامل یک مسئله اساسی عرضه و تقاضا است.
+
+عرضه توسط
+
+$$
+q_s(p) = \exp(\alpha p) - \beta.
+$$
+
+منحنی تقاضا
+
+$$
+q_d(p) = \gamma p^{-\delta}.
+$$
+
+مقادیر $\alpha$، $\beta$، $\gamma$ و
+$\delta$ **پارامترها** هستند
+
+تعادل $p^*$ قیمتی است که
+$q_d(p) = q_s(p)$.
+
+ما میتوانیم این تعادل را با استفاده از یک الگوریتم یافتن ریشه حل کنیم.
+به طور خاص، ما $p$ را پیدا خواهیم کرد به طوری که $h(p) = 0$،
+جایی که
+
+$$
+h(p) := q_d(p) - q_s(p)
+$$
+
+این قیمت تعادل $p^*$ را به دست میدهد. از این ما مقدار
+تعادل را با $q^* = q_s(p^*)$ به دست میآوریم
+
+مقادیر پارامتر خواهند بود
+
+- $\alpha = 0.1$
+- $\beta = 1$
+- $\gamma = 1$
+- $\delta = 1$
+
+```{code-cell} ipython3
+from scipy.optimize import brentq
+
+# Compute equilibrium
+def h(p):
+ return p**(-1) - (np.exp(0.1 * p) - 1) # demand - supply
+
+p_star = brentq(h, 2, 4)
+q_star = np.exp(0.1 * p_star) - 1
+
+print(f'Equilibrium price is {p_star: .2f}')
+print(f'Equilibrium quantity is {q_star: .2f}')
+```
+
+بیایید نتایج خود را نیز رسم کنیم.
+
+```{code-cell} ipython3
+# Now plot
+grid = np.linspace(2, 4, 100)
+fig, ax = plt.subplots()
+
+qs = np.exp(0.1 * grid) - 1
+qd = grid**(-1)
+
+
+ax.plot(grid, qd, 'b-', lw=2, label='demand')
+ax.plot(grid, qs, 'g-', lw=2, label='supply')
+
+ax.set_xlabel('price')
+ax.set_ylabel('quantity')
+ax.legend(loc='upper center')
+
+plt.show()
+```
+
+ما همچنین میخواهیم تغییرات عرضه و تقاضا را در نظر بگیریم.
+
+به عنوان مثال، بیایید ببینیم چه اتفاقی میافتد وقتی تقاضا افزایش مییابد، با افزایش $\gamma$ به $1.25$:
+
+```{code-cell} ipython3
+# Compute equilibrium
+def h(p):
+ return 1.25 * p**(-1) - (np.exp(0.1 * p) - 1)
+
+p_star = brentq(h, 2, 4)
+q_star = np.exp(0.1 * p_star) - 1
+
+print(f'Equilibrium price is {p_star: .2f}')
+print(f'Equilibrium quantity is {q_star: .2f}')
+```
+
+```{code-cell} ipython3
+# Now plot
+p_grid = np.linspace(2, 4, 100)
+fig, ax = plt.subplots()
+
+qs = np.exp(0.1 * p_grid) - 1
+qd = 1.25 * p_grid**(-1)
+
+
+ax.plot(grid, qd, 'b-', lw=2, label='demand')
+ax.plot(grid, qs, 'g-', lw=2, label='supply')
+
+ax.set_xlabel('price')
+ax.set_ylabel('quantity')
+ax.legend(loc='upper center')
+
+plt.show()
+```
+
+اکنون ممکن است تغییرات عرضه را در نظر بگیریم، اما شما قبلاً ایده را دریافت کردهاید که
+کد تکراری زیادی در اینجا وجود دارد.
+
+با استفاده از اصول مورد بحث در این سخنرانی، کد بالا را بازسازی و وضوح آن را بهبود ببخشید.
+
+```{exercise-end}
+```
+
+```{solution-start} wgc-exercise-1
+:class: dropdown
+```
+
+در اینجا یک راهحل است که از یک کلاس استفاده میکند:
+
+```{code-cell} ipython3
+class Equilibrium:
+
+ def __init__(self, α=0.1, β=1, γ=1, δ=1):
+ self.α, self.β, self.γ, self.δ = α, β, γ, δ
+
+ def qs(self, p):
+ return np.exp(self.α * p) - self.β
+
+ def qd(self, p):
+ return self.γ * p**(-self.δ)
+
+ def compute_equilibrium(self):
+ def h(p):
+ return self.qd(p) - self.qs(p)
+ p_star = brentq(h, 2, 4)
+ q_star = np.exp(self.α * p_star) - self.β
+
+ print(f'Equilibrium price is {p_star: .2f}')
+ print(f'Equilibrium quantity is {q_star: .2f}')
+
+ def plot_equilibrium(self):
+ # Now plot
+ grid = np.linspace(2, 4, 100)
+ fig, ax = plt.subplots()
+
+ ax.plot(grid, self.qd(grid), 'b-', lw=2, label='demand')
+ ax.plot(grid, self.qs(grid), 'g-', lw=2, label='supply')
+
+ ax.set_xlabel('price')
+ ax.set_ylabel('quantity')
+ ax.legend(loc='upper center')
+
+ plt.show()
+```
+
+بیایید یک نمونه با مقادیر پیشفرض پارامتر ایجاد کنیم.
+
+```{code-cell} ipython3
+eq = Equilibrium()
+```
+
+اکنون ما تعادل را محاسبه کرده و آن را رسم خواهیم کرد.
+
+```{code-cell} ipython3
+eq.compute_equilibrium()
+```
+
+```{code-cell} ipython3
+eq.plot_equilibrium()
+```
+
+یکی از چیزهای خوب در مورد کد بازسازی شده ما این است که، وقتی ما
+پارامترها را تغییر میدهیم، نیازی به تکرار خودمان نداریم:
+
+```{code-cell} ipython3
+eq.γ = 1.25
+```
+
+```{code-cell} ipython3
+eq.compute_equilibrium()
+```
+
+```{code-cell} ipython3
+eq.plot_equilibrium()
+```
+
+```{solution-end}
+```
\ No newline at end of file