پرش به محتویات

ماژول

Elm شامل سیستمی ماژولار است که به شما کمک می‌کند کد خود را به روشی منظم گسترش دهید. در ساده‌ترین حالت، ماژول به شما اجازه می‌دهد کد را به چندین فایل تقسیم کنید.

تعریف ماژول

ماژول در Elm زمانی بهترین عملکرد را دارد که آن را حول یک نوع داده مرکزی تعریف کنید. برای نمونه، ماژول List که فقط نوع داده List را شامل می‌شود. فرض کنید می‌خواهیم ماژولی حول نوع داده Post برای یک پلتفرم وبلاگ‌نویسی بسازیم. می‌توان چیزی شبیه به این ایجاد کرد:

module Post exposing (Post, decoder, encoder, estimatedReadTime)

import Json.Decode as D
import Json.Encode as E



-- POST


type alias Post =
    { title : String
    , author : String
    , content : String
    }



-- READ TIME


estimatedReadTime : Post -> Float
estimatedReadTime post =
    toFloat (wordCount post) / 220


wordCount : Post -> Int
wordCount post =
    List.length (String.words post.content)



-- JSON


decoder : D.Decoder Post
decoder =
    D.map3 Post
        (D.field "title" D.string)
        (D.field "author" D.string)
        (D.field "content" D.string)


encoder : Post -> E.Value
encoder post =
    E.object
        [ ( "title", E.string post.title )
        , ( "author", E.string post.author )
        , ( "content", E.string post.content )
        ]

خط جدید module Post exposing (Post, decoder, encoder, estimatedReadTime) در بالای صفحه، به این معنی است که ماژول به عنوان Post شناخته می‌شود و تنها مقادیر خاصی خارج از ماژول در دسترس است. همانطور که می‌بینید، تابع wordCount تنها در داخل ماژول Post در دسترس است. پنهان کردن توابع به این شکل یکی از مهم‌ترین تکنیک‌های برنامه‌نویسی در Elm است!

یادداشت

اگر فراموش کنید که خط اعلام ماژول را اضافه کنید، Elm به صورت پیشفرض از این خط استفاده خواهد کرد:

module Main exposing (..)

این کار برای مبتدیان که در یک فایل کار می‌کنند، برنامه را آسان‌تر می‌کند. آن‌ها نباید در روز اول کاری خود با سیستم ماژول مواجه شوند!

گسترش ماژول

با پیچیده‌تر شدن برنامه، در نهایت چیزهایی به ماژول‌های خود اضافه خواهید کرد. همان‌طور که در ارایه 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 اگر نام ماژول طولانی باشد!