ماژول¶
Elm شامل سیستمی ماژولار است که به شما کمک میکند کد خود را به روشی منظم گسترش دهید. در سادهترین حالت، ماژول به شما اجازه میدهد کد را به چندین فایل تقسیم کنید.
تعریف ماژول¶
ماژول در Elm زمانی بهترین عملکرد را دارد که آن را حول یک نوع داده مرکزی تعریف کنید. برای نمونه، ماژول List
که فقط نوع داده List
را شامل میشود. فرض کنید میخواهیم ماژولی حول نوع داده Post
برای یک پلتفرم وبلاگنویسی بسازیم. میتوان چیزی شبیه به این ایجاد کرد:
خط جدید module Post exposing (Post, decoder, encoder, estimatedReadTime)
در بالای صفحه، به این معنی است که ماژول به عنوان Post
شناخته میشود و تنها مقادیر خاصی خارج از ماژول در دسترس است. همانطور که میبینید، تابع wordCount
تنها در داخل ماژول Post
در دسترس است. پنهان کردن توابع به این شکل یکی از مهمترین تکنیکهای برنامهنویسی در Elm است!
یادداشت
اگر فراموش کنید که خط اعلام ماژول را اضافه کنید، Elm به صورت پیشفرض از این خط استفاده خواهد کرد:
این کار برای مبتدیان که در یک فایل کار میکنند، برنامه را آسانتر میکند. آنها نباید در روز اول کاری خود با سیستم ماژول مواجه شوند!
گسترش ماژول¶
با پیچیدهتر شدن برنامه، در نهایت چیزهایی به ماژولهای خود اضافه خواهید کرد. همانطور که در ارایه The Life of a File توضیح میدهم، طبیعی است که ماژولهای Elm در محدوده ۴۰۰ تا ۱۰۰۰ خط کد باشند. اما وقتی چندین ماژول دارید، چگونه تصمیم میگیرید کجا کد جدیدی اضافه کنید؟
برای حالتهای مختلف کد، سعی میکنم از رویکردهای اکتشافی استفاده کنم:
-
حالت منحصر بفرد — اگر منطق تنها در یک مکان ظاهر شود، توابع کمکی سطح بالا را تا حد ممکن نزدیک به استفاده جدا میکنم. شاید از یک کامنت مانند
POST PREVIEW --
استفاده کنم تا نشان دهم که توابع پیش رو مربوط به پیشنمایش پست هستند. -
حالت مشابه — فرض کنید میخواهیم پیشنمایش
Post
را در صفحه اصلی و در صفحه نویسنده نشان دهیم. در صفحه اصلی، میخواهیم محتوای جالب را برجسته کنیم، بنابراین میخواهیم تکههای طولانیتری داشته باشیم. در صفحه نویسنده، میخواهیم وسعت محتوا را برجسته کنیم، بنابراین میخواهیم بر روی عناوین تمرکز کنیم. این موارد مشابه هستند، نه یکسان، بنابراین به رویکرد منحصر بفرد برمیگردیم. فقط منطق را بطور جداگانه بنویسید. -
حالت یکسان — در یک نقطه، یک دسته کد منحصر بفرد خواهیم داشت. ایرادی ندارد! اما شاید متوجه شویم که برخی تعاریف شامل منطقی هستند که دقیقا یکسان است. برای آن منطق یک تابع کمکی جدا کنید! اگر تمام کاربرد آن در یک ماژول است، نیازی به انجام کار دیگری نیست. شاید اگر واقعا بخواهید، یک کامنت مانند
READ TIME --
قرار دهید.
رویکردهای بالا درباره ایجاد توابع کمکی در یک فایل هستند. تنها زمانی میخواهید یک ماژول جدید ایجاد کنید که تعدادی از این توابع کمکی حول یک نوع داده سفارشی متمرکز شده باشند. برای نمونه، با ایجاد ماژول Page.Author
شروع میکنید و تا زمانی که توابع کمکی شروع به جمع شدن نکنند، ماژول Post
را ایجاد نمیکنید. در آن نقطه، ایجاد یک ماژول جدید، باید منجر به احساس راحتی بیشتر در پیمایش و درک کد شود. اگر اینطور نیست، به نسخهای که واضحتر بود برگردید. ماژول بیشتر به معنای بهتر بودن نیست! مسیری را انتخاب کنید که کد را ساده و واضح نگه دارد.
فرض کنید کد مشابه بطور پیشفرض منحصر بفرد است. (معمولا در رابطهای کاربری اینطور است!) اگر منطقی را ببینید که در تعاریف مختلف یکسان است، توابع کمکی با کامِنت مناسب بسازید. وقتی تعدادی تابع کمکی حول یک نوع داده خاص دارید، در نظر بگیرید که یک ماژول جدید بسازید. اگر یک ماژول جدید کد شما را واضحتر کند، عالی است! اگر نه، به عقب برگردید. فایلهای بیشتر، به معنای سادگی یا وضوح بیشتر نیستند.
یادداشت
یکی از رایجترین راهها برای به مشکل خوردن با ماژولها زمانی است که چیزی که قبلا یکسان بود، بعدا مشابه شود. در رابطهای کاربری، این اتفاق بسیار رایج است! معمولا توسعهدهندگان سعی میکنند یک تابع «هیولا» ایجاد کنند که تمام موارد مختلف را مدیریت میکند. افزودن آرگومانهای بیشتر، افزودن آرگومانهای پیچیدهتر. مسیر بهتر این است که بپذیرید اکنون دو وضعیت منحصر بفرد دارید و کد را به هر دو مکان منتقل کنید. آن را دقیقا به همان شکلی که نیاز دارید سفارشی کنید. سپس ببینید آیا هیچ یک از منطقهای حاصل یکسان است. اگر چنین است، آن را به توابع کمکی منتقل کنید. توابع طولانی باید به چندین تابع کوچکتر تقسیم شوند، نه اینکه طولانیتر و پیچیدهتر شوند!
کاربرد ماژول¶
در Elm، کد برنامه معمولا در دایرکتوری src/
قرار دارد. این پیشفرض برای فایل elm.json
نیز صادق است. بنابراین ماژول Post
باید در فایلی به نام src/Post.elm
قرار گیرد. در ادامه، میتوانیم این ماژول را import
کرده و از مقادیر در دسترس آن استفاده کنیم. این کار، به چهار روش مختلف قابل انجام است:
import Post
-- Post.Post, Post.estimatedReadTime, Post.encoder, Post.decoder
import Post as P
-- P.Post, P.estimatedReadTime, P.encoder, P.decoder
import Post exposing (Post, estimatedReadTime)
-- Post, estimatedReadTime
-- Post.Post, Post.estimatedReadTime, Post.encoder, Post.decoder
import Post as P exposing (Post, estimatedReadTime)
-- Post, estimatedReadTime
-- P.Post, P.estimatedReadTime, P.encoder, P.decoder
توصیه میکنم از شیوه exposing
به ندرت استفاده کنید. ایدهآل این است که بیش از یک مرتبه از آن استفاده نشود. در غیر این صورت، هنگام خواندن کد برنامه، ممکن است سخت بفهمید که مقدارها و توابع از کجا آمدهاند. "صبر کنید، filterPostBy
از کجا آمده است؟ چه آرگومانهایی میگیرد؟" با افزودن exposing
بیشتر، خواندن کد سخت و سختتر میشود. من معمولا از آن برای (..) import Html exposing
استفاده میکنم اما برای چیزهای دیگر نه. برای سایر موارد، توصیه میکنم از import
استاندارد استفاده کنید و شاید از as
اگر نام ماژول طولانی باشد!