پاییز دو سال پیش بود که ChatGPT آمد و به شکل خاصی بازار همه چیز رو عوض کرد یا بهتره بگم که به هم ریخت 😁 در این مدت نه فقط OpenAI که هزاران شرکت دیگر هم دست به کار شدند و شروع کردند به ارائه مدلهای زبانی بزرگ یا همون LLMها و خواستند که به شکلی با OpenAI رقابت کنند.
الان که دو سالی از اون روزها گذشته منتها موضوع کمی تفاوت داره و بیش از این که سمت ارائه مدل بریم، بهتره به سمت agent یا «عامل» بریم که خب خودش یک بحث مفصله.
دیشب، در بلاگ انگلیسیم کمی در مورد مدلهای بزرگ و ایجنتها صحبت کردم و امروز تصمیم گرفتم که بلاگ فارسیش رو هم بنویسم که هر دو طرف، محتوای مناسب رو داشته باشیم.
ایجنتها، عملگرایی به LLMها اضافه میکنند.
اگر دنبالکننده بلاگ و در کل محتوای من باشید، احتمالا میدونید که من هم در بازی LLM بودم و مثلا یکی از LLMهای اوپن سورسی که روش کار کردم مدل مارال هفت میلیارد پارامتری بود که روی Alpaca Persian تمرین داده شد.
اما آیا یک مدلی که سوال-جواب کنه کافیه یا به چیزی بیشتر نیاز داریم؟ در واقع برای این که LLMها بتونن موثر واقع بشن، باید بتونن با ابزارهای مختلف تعامل کنند. حالا شما فرض کنید که بخواهیم این تعامل رو در سطح فاینتیون کردن، به مدل اضافه کنیم.
یعنی فرض کنید که ما APIهایی از دیجیکالا، اسنپ، دیوار و مثلا ابر آروان بگیریم. سعی کنیم با کمک تعدادی API Call نمونه، مدل رو تیون کنیم. حالا فرض کنید یک نفر بخواد این مدل رو برای استفاده از تپسی یا باسلام به کار بگیره. چی میشه؟ هیچی! مجددا بار فاینتیون با APIهای جدید میفته روی دوش کاربر.
برای حل این مشکل، ما نیاز به agentها داریم. در واقع در مثالهای فوق هر API و ابزاری که لازم داریم رو برمیداریم، میبریم یک جایی براشون توابع درستی مینویسیم و سپس با کمک LLMها خروجی رو «انسانی» یا Humanize میکنیم. به این شکل بار فاینتیون کردن LLMهم به دوش نمیکشیم و همه چیز هم عالی پیش خواهد رفت.
ساخت ایجنت بدون استفاده از فریمورک
دقیقا از زمانی که OpenAI و سایر شرکتهایی که LLM ارائه دادند APIهای چت و یا Instruction Following خودشون رو هم ارائه کردند، فریمورکهای زیادی مثل Flowise یا Crew AI ساخته شدند که به شما کمک کنند تا ایجنت بسازید.
اما راستش رو بخواهید – همونطور که در بلاگ انگلیسی هم توضیح داده بودم – خیلی از این فریمورکها یه حجم عجیب و غریبی از پیچیدگی رو به فرایند ساخت ایجنت دارند اضافه میکنند.
نتیجه این شد که شخصا به دنبال روشی گشتم که بتونم بدون استفاده از فریمورک خاصی، به راحتی بتونیم یک ایجنت بسازیم. برای همین لازم بود که درک کنم ایجنت اصلا چی کار میکنه؟ چرا انقدر مهمه که ما بتونیم ایجنت رو درک کنیم؟ و صدالبته از هر ایجنتی که اسمش «اسمیت» باشه دوری بجوییم 😂
ایجنتها یک سری «وظیفه» و «ورودی مناسب هر وظیفه» رو درک میکنند. این وظایف یا تسکها در واقع توابعی هستند که در برنامهمون قرار ادادیم که بتونن یک کاری رو انجام بدن (مثلا بره رخداد n ام سری فیبوناچی رو حساب کنه) و ورودیهاشون هم دیتاییه که ایجنت باید با هوش خودش تشخیص بده و بسازه.
در نهایت نیاز به مکانیزمی داریم که بیاد این وظایف و ورودیها رو اجرا کنه، خروجیشون رو دوباره بده به LLM و ازش بخواد که Humanizeش کنه. گذشته از این بد نیست که ایجنت ما یک حافظه کوچکی هم داشته باشه.
نمونه یک ایجنت ساده با پایتون
سلب ادعا: از اونجایی که کد این ایجنت رو در گیتهاب گذاشتم، صرفا مراحل ساخت ایجنت ساده رو توضیح میدم و باقیش رو میتونید از گیتهابم ببینید و ایده بگیرید.
اولین گام ما برای ساخت ایجنت باید این باشه که یک LLM مناسب انتخاب کنیم. شما مختارید هر LLMای که یک OpenAI Compatible API ارائه میده انتخاب کنید اما من شخصا دارم از پروژه جبیر خودم استفاده میکنم 😁
بعد از اون، لازم داریم که بیاییم یک کلاینت ساده OpenAI درست کنیم که بتونه با API مورد نظر ما کار کنه:
from openai import OpenAI
client = OpenAI(api_key="FAKE", base_url="https://openai.jabirpoject.org/v1")
همونطور که قبلا در این پست توضیح داده بودم، کتابخونه OpenAI در پایتون نیازمند یک API Keyئه که اینجا ما از FAKE استفاده کردیم براش.
حالا یک کلاس ایجنت ساده درست میکنیم که حافظه هم داشته باشه:
class Agent:
def __init__(self, system=""):
self.system = system
self.messages = []
if self.system:
self.messages.append({"role" : "system", "content" : system})
def __call__(self, message):
self.messages.append({"role" : "user", "content" : message})
result = self.execute()
self.messages.append({"role" : "assistant", "content" : result})
return result
def execute(self):
completion = client.chat.completions.create(
model = "jabir-400b",
messages = self.messages,
temperature = 0.0
)
return completion.choices[0].message.content
همونطوری که میبینید، این ایجنت میتونه یک تاریخچه از چیزهایی که بهش گفتیم (و بهمون گفته) نگه داره و کم کم باید بریم سراغ این که بهش اکشنهای مورد نظر رو اضافه کنیم.
ولی خب بهتره قبل از اضافه کردن اکشن، تستش کنیم. برای تستش هم این کد رو میتونید اجرا کنید:
sample_agent = Agent("You are a helpful assistant")
print(sample_agent("What is 1+1?"))
کد نمونه با اکشن
اگر دوست دارید بدونید که این ایجنت ما با اکشن چطوری کار میکنه، میتونید به این مخزن گیتهاب مراجعه کنید و ببینید که چطور به راحتی میشه یک اکشن به همین ایجنت ساده اضافه کرد و بار فریمورکها رو هم به دوش نکشید.
جمعبندی
اگر طی دو سه سال گذشته محتوای این بلاگ رو خونده باشید میبینید که علاقه من به هوش مصنوعی از پروژههایی مثل ریاضی ۱ رو با هوش مصنوعی پاس کن یا پلاکخوان فارسی که با Yolo v5 پیاده کرده بودم جدی شد.
این علاقه، کم کم به سمت Generative AI رفت و خب طبیعتا همین علاقه باعث ساختهشدن پلتفرم مانی و همچنین آتلیه شد. اما خب در سال ۲۰۲۵ احتمالا بیش از این که به مدلهای جدید نیاز داشته باشیم، نیاز داریم که مدلها رو به سمت agentic شدن بیاریم و اپلیکیشنها رو به شکل AI agent داشته باشیم.
سلب ادعا: این مطلب صرفا آموزشی بوده و هرگونه استفاده غیرقانونی از دانش به اشتراک گذاشته شده در این مطلب، بر عهده خواننده خواهد بود.
احتمالا شما هم دوست داشتید که از APIهای OpenAI استفاده کنید ولی هزینههای بالایی داشته و اونطوری که باید و شاید، نتونسته شما رو راضی کنه. در این پست، میخوام یک راهکار بهتون نشون بدم که به صورت «کاملا رایگان» بتونید از این APIها استفاده کنید. فقط یادتون باشه که این روش رو فقط برای مصارف شخصی استفاده کنید، چون اگر ببریدش روی محصول، ممکنه دردسرساز بشه براتون.
این رو هم بگم که این مطلب، مطلبیه شدیدا برنامهنویسانه و خب برخلاف مطالب قبلی که یکم مخاطب عامتری داشت، نیاز به کمی دانش پایه برنامهنویسی داره.
پیشنیازها
برای این که از این آموزش استفاده کنیم، نیاز داریم این موارد رو بلد باشیم:
آشنایی پایه با APIها و این که چطور کار میکنند (میتونید یکی از مطالب قدیمی من رو بخونید)
آشنایی اجمالی با پایتون
همین؟ بله همین!
شروع به کار
نصب کتابخانههای مربوطه
مثل هر پروژه دیگری، ابتدا نیاز داریم تا کتابخانهها و چارچوبهای مربوط به اون رو، روی سیستم خودمون نصب کنیم. چون این پروژه پایتونیه، از ابزار pip استفاده خواهیم کرد.
اما قبل از اون، بهتره یک محیط مجازی پایتون ایجاد کنیم:
virtualenv -ppython3 .venv
بعد از اون، وقتشه که فعالش کنیم:
source .venv/bin/activate
دقت کنید این پروسه فعالسازی، در ویندوز کمی متفاوت از مک و لینوکسه که با یک سرچ ساده، میتونید بهش برسید. البته توصیه شخصیم اینه که روی ویندوز هم از WSL استفاده کنید که بدون مشکل تمامی کدهایی که در این پست قرار دادم، براتون اجرا بشه (چون هم روی لینوکس، هم مک و هم WSL تستشون کردم).
بعد از فعالسازی، ترمینال شما به این شکل درمیاد:
(venv) ~:$
این به این معناست که محیط مجازی پایتون، اجرا شده و میشه بدون مشکل ازش استفاده کرد.
حالا وقتشه که کتابخونههای openai و g4f رو نصب کنیم:
pip install "g4f[all]" openai
این دو کتابخونه، دقیقا تنها چیزهایی هستند که ما نیاز داریم!
حالا g4f چیه؟
عبارت g4f مخفف gpt4free و بازی با عبارت gpt for free یعنی «جیپیتی رایگان»ئه! حالا این کتابخونه چه کاری میکنه که gpt رایگان به ما میرسونه؟ 😁
کاری که این کتابخونه میکنه، اینه که میاد و از providerهای مختلفی که داره (بعضیا مثل Airforce/OpenRouter با خواست خودشون البته در اختیارش قرار دادند) استفاده میکنه و به شما امکان استفاده از مدلهای متنوع هوش مصنوعی مثل GPT, Claude, Mistral و … رو میده. در واقع یک «تلاش برای دمکراتیزه کردن هوش مصنوعی» در نوع خودش میتونه محسوب بشه.
و خب نه فقط چتبات، که APIهای تولید تصویر (بخصوص با مدل Dall-E) رو هم پشتیبانی درستی داره میکنه! اما حقیقتش رو بخواهید، مدلهای تصویرش به شدت محدودن و بهتره که به همین متنیها قناعت بورزیم 😁
چرا به OpenAI نیاز داریم؟
این هم سوال خوبیه. مگه نگفتیم قرار نیست از خود OpenAI یا سایر فراهمکنندگان APIهاش سرویس بگیریم؟ درسته. ولی نیاز داریم به کتابخونه پایتونیش برای این که بتونیم از API لوکالمون استفاده کنیم!
راهاندازی API لوکال
خب الان وقتشه یک پنجره ترمینال جدید باز کنید، طبق چیزی که گفته شد، محیط مجازی رو فعال کنید و سپس تایپ کنید:
g4f api
بعدش enter بزنید و صبر کنید تا API بیاد بالا. وقتی API بیاد بالا چنین صحنهای میبینید:
و تبریک، API ما قابل استفادهست.
نوشتن کد پروژه
این همه توضیح دادیم تا برسیم به بخش جذاب ماجرا، که نوشتن کدهای پروژهمونه!
اول لازم داریم تا کتابخونههای لازم رو به پروژه اضافه کنیم:
from openai import OpenAI
این قطعه کد، میاد و کلاس OpenAI رو از کتابخونه openai برای ما در پروژه لود میکنه.
خب یک توضیحی بدم، کتابخونه OpenAI بدون API Key کار نمیکنه. به همین خاطر یک مقدار بیخود (در اینجا عبارت FAKE) رو وارد کردیم. در قسمت Base URL هم آمدیم و به این کتابخونه فهموندیم که به جای این که به APIهای خود OpenAI متصل بشه، به لوکال هاست ما متصل بشه.
در واقع کل کار رو اینجا انجام دادیم و حالا مونده یک مرحله! اون هم اینه که یک چت با مدل مورد نظر بسازیم:
و همونطوری که میبینید فرمت پیامهای ما، فرمت چت و اسم مدلمون هم gpt-4o گذاشتیم. البته امکان استفاده از مدلهای دیگر هم هست ولی اینجا با gpt-4o کار داشتیم 😁
احتمالا شما هم الان نگران این هستید که این نوع استفاده، میتونه برای شما دردسر قانونی درست کنه. حقیقتش رو بخواهید خیر. این کتابخونه (و سایر کتابخونههای مشابه) میتونن کاملا قانونی باشن اگر شما از مدلهای اوپن سورس موجود استفاده کنید.
مثلا من پیشنهاد میکنم برای خیلی از پروژههایی که با g4f قراره بسازید از mixtral-8x22b استفاده کنید. هم خوبه، هم اوپن سورسه و هم فارسی میفهمه. یا مثلا llama-3.1-70b و llama-3.1-405b و …
در کل میخوام بگم که میتونیم این موضوع رو کاملا درست و قانونی هم در دستان خودمون داشته باشیم و لذت هم ببریم 😎
جمعبندی
در دنیای امروز که ابزارها دارند حرف اول رو میزنن، خیلی مهمه که بدونیم چطور میتونیم به ابزار خوب برسیم. این پست، یکی از اهدافش این بود که به شما نشان بده ابزارهای خوب رایگان هم وجود دارند که شما بتونید بدون مشکل، باهاشون کار کنید.
احتمالا در آینده، باز هم ابزار یا API خوب در حوزه هوش مصنوعی و بخصوص هوش مصنوعی زایا (Generative AI) معرفی کنم. امیدوارم که موفق و موید باشید و این آموزش به دردتون خورده باشه.
ضمنا، لطفا از مدلهای تجاری به صورت غیرقانونی استفاده نکنید 😁
گنوم، چندسال اخیر رو در حال بهبود تجربه کاربریش روی دستگاههایی مثل گوشیهای همراه و همچنین تبلتهاست. در کل، داره برای یک انقلاب در صفحات لمسی آماده میشه. حالا، یک رابط کاربری جالب به اسم Phosh (مخففی برای Phone Shell) ارائه کرده که روی دبیان (بله، حتی دسکتاپ!) قابل نصب و اجراست.
نماگرفت زیر، نماگرفتی از صفحه قفل این رابط کاربریه:
و خب همونطوری که میبینید، کار تمیز و نسبتا زیباییه. حالا سوال اینه چطور نصبش کنیم؟ در ادامه مطلب مفصلا توضیح میدم 🙂
نصب قدم به قدم Phosh روی دبیان
گام اول: نصب دبیان
توجه داشته باشید که دبیان مد نظر من اینجا، دبیانیه که شما روی پردازندههای x86 نصب میکنید. اگر قراره این دبیان روی رزبری پای باشه، یا سیستم شخصی شما صفحه لمسی داره، میتونید این قسمت رو نادیده بگیرید. اما من نصب رو روی یک ماشین مجازی با کمک Virtual Box انجام دادم. آموزش نصب دبیان، در اینترنت زیاد پیدا میشه؛ فلذا اینجا حرفی از آموزش نصب به میان نمیارم. فقط حواستون باشه نسخه Net Install دبیان رو دانلود و نصب کنید که چیز اضافهای نداشته باشیم. برای دانلود دبیان هم میتونید به وبسایت دبیان مراجعه کنید و آخرین ISO مورد نظر رو بگیرید.
گام دوم: قبل از نصب Phosh چه کنیم؟
خب اولین کاری که قبل از نصب Phosh کنید اینه که با خودتون یک فنجان قهوه یا نوشیدنی خنک داشته باشید چون پروسه نصب ممکنه شما رو خسته و تشنه کنه. بعد از اون، بد نیست که سیستم رو بروزرسانی کنید. بعد از بروزرسانی سیستمعامل، نوبتی هم باشه نوبت اینه که مستقیم بریم سر نصب Phosh. اینجا هم جا داره نکته مهم رو متذکر بشم که من phosh رو از مخازن نصب میکنم تا صرفا کنجکاوی رفع شده باشه وگرنه روش درستتر نصب phosh نصب از کد منبعه (حداقل اگر روی سیستم x86 و به قصد توسعه نصب میکنید).
گام سوم: نصب و راهاندازی Phosh
خب برای نصب کافیه که دستورات زیر رو اجرا کنیم:
sudo apt install phosh-core
و اگر میخواهید Phosh شما مناسب تبلت باشه:
sudo apt install phosh-tablet
و اگر میخواهید نسخه کامل Phosh رو نصب کنید، کافیه که دستور رو به این شکل تغییر بدید:
sudo apt install phosh-full
و بعد از نصب حدود یک گیگابایت بستههای نرمافزاری، کل میزکار گنوم مخصوص صفحات لمسی یا همون Phosh برای شما نصب خواهد شد. پس از نصب، کافیه که اول سرویسش رو فعال و سپس راهاندازی کنیم:
سپس، صفحه قفل (که بالاتر عکسش رو قرار دادم) و بعد از اون، صفحه ورود رمز به شما نمایش داده میشه.
پس از ورود رمز، وارد صفحه منوی اصلی میشیم که از اونجا میتونیم به نرمافزارها و ابزارهای نصب شده روی سیستم دسترسی داشته باشیم:
خب، حالا با خیال راحت میتونیم از Phosh استفاده کنیم و لذت ببریم 😁
نکات مهم
از اونجایی که Phosh نرمافزار نوپا و نسبتا جدیدیه، لازمه چند نکته مهم رو در موردش متذکر بشم:
نسخه خاصی ازش در مخازن دبیان پایدار موجوده که خب برای یک تست دم دستی و ویرچوالباکسی، بهترین گزینه بود (حداقل برای من) و خب قاعدتا روی مخازن تستینگ و ناپایدار هم قرارش دادند. موقع نصب، مراقب باشید تا به ضررتون نشه 😁 ترجیحا نصب رو روی یک ماشین مجازی انجام بدید.
این میزکار خاص، برای صفحات لمسی خیلی بهینه شده و استفاده ازش با ماوس و کیبرد تا حد زیادی سخته. اگر صفحه لمسی دارید که میتونید به سیستمتون وصلش کنید، احتمالا تجربه کاربری بهتری داشته باشید.
بعضی نرمافزارها اندازهشون برای من مشکل داشت (که احتمالا برمیگرده به ویرچوال باکس). اگر در جای دیگری امتحان بشه شاید اندازه صفحه و برنامهها، مناسب باشه.
کدوم توزیعها از Phosh پشتیبانی میکنند؟
این هم سوال مهمیه، تا جایی که دیدم PostmarketOS (که برمبنای آلپاین ساخته شده) و همچنین Mobian (که برپایه دبیانه) از این میزکار (یا بهتر بگم پوسته) پشتیبانی میکنند. در مورد سایر توزیعها/سیستمعاملهایی که ممکنه گنوم رو اجرا کنند، ایدهای ندارم.
جمعبندی
این بلاگ اصلا قرار نبود نوشته شه، ولی امروز از سر خستگی (دقیقا خستگی 😂) جستجو کردم ببینم Phosh چطور میتونه روی دبیان دسکتاپ نصب بشه. امتحانش کردم و به نظرم پروژه تمیز، باحال و آیندهداری اومد. حالا هم تستش کردم و هم یک سری ایده اومد به ذهنم. در آینده، احتمالا بیشتر با Phosh کار کنم و در موردش بنویسم. در آخر هم بابت وقتی که صرف کردید و این مطلب رو خوندید، ازتون تشکر میکنم.
پس از مدت طولانی، با یک پست دیگر برگشتم و این بار قراره با هم احراز هویت JWT رو در ریلز بررسی کنیم. اول از همه، لازمه بدونیم JWT چیه؟ چرا نیازش داریم؟ اصلا چرا احراز هویت و هزاران چرای دیگر که احتمالا الان در سر شما هستند. بعدش یک پروژه خیلی کوچولو ایجاد میکنیم و با هم براش احراز هویت رو پیادهسازی میکنیم 🙂
احراز هویت JWT چیه و چرا بهش نیاز داریم؟
اول از همه این سوال بنیادیتر رو پاسخ بدیم که «چرا احراز هویت نیاز داریم؟» و بعد بریم سراغ احراز هویت JWT که قراره در این مطلب در موردش مفصل حرف بزنیم.
ما به احراز هویت نیاز داریم چون همیشه بخشی از دادههای ما، خصوصی هستند. گذشته از اون، احراز هویت میتونه اجازه CRUD رو به شما بده، نه؟ فکر کنید اپی دارید که هرکسی میتونه روش بخونه و بنویسه. ممکنه خوندن چیزی باشه که برای «همه» مناسب باشه اما «نوشتن» اینطور نیست. بخصوص که نوشتن خودش به قسمتهایی مثل حذف و بروزرسانی هم شکسته شده.
پس ما به احراز هویت نیاز داریم که هر ننهقمری (😂) نتونه از API ما استفاده کنه. بلکه کاربرانی که ثبتنام کردند و دسترسی درستی به سرویس دارند، بتونن استفاده کنن. این قضیه در API های تجاری (یا Business facing) خودشون رو بیشتر و بهتر نشون میدن.
حالا سوال مهمتر …
احراز هویت JWT چیه؟
در اپهای قدیمی (مثل همین وردپرس)، احراز هویت توسط cookie ها انجام میشه. به چه صورتی؟ به این صورت که وقتی نام کاربری و گذرواژه وارد میکنیم، نرمافزار فضایی رو در مرورگر به خودش اختصاص میده و یک سری اطلاعات رو با خودش جابجا میکنه. اما در ReST API ها این قضیه رو نداریم. در واقع نمیتونیم به کوکیها اعتماد کنیم. پس چه میکنیم؟ اینجا لازمه جز یوزرنیم(که معمولا میتونه عمومی باشه) و پسورد (که میتونه راحت لو بره) میاییم و یک «توکن» هم تعریف میکنیم. این توکن، میتونه ثابت یا متغیر باشه. یعنی چی؟ یعنی میتونه به ازای هربار ورود تغییر کنه، میتونه سر زمان مشخصی هم منقضی بشه.
حالا توکن چیه؟ توکن به صورت کلی، در کازینوها معادل پولیه که شما در بازیها قرار میدید، در واقع مجوز حضور شما در اون کازینو، کلاب و … است. حتی به رمزارزهایی که بر مبنای دیگر رمزارزها ساخته میشن هم سکه نمیگن بلکه میگن توکن. شما فرض کنید که مثلا ۱۰۰ دلار میدید و پنج تا سکه با آرم اون کازینوی خاص دریافت میکنید. اگر در بازی برنده بشید یا ببازید، باید توکنهاتون رو تحویل بدید یا بگیرید.
حالا در احراز هویت JWT هم، ما به ازای کاربرمون یک توکن در نظر میگیریم. این توکن، معمولا یک رشته طولانیه که انسان نمیتونه بخوندش. نتیجتا خیلی از اطلاعات ما به صورت ایمنتر میتونن رد و بدل بشن (طبیعیه که مواردی مثل SSL داشتن و الگوریتمهایی که در ساخت توکن داشتیم هم مهمن). ضمن این که نامکاربری، ایمیل، رمزعبور و .. هم به همین سادگیا نمیتونن خونده بشن.
پس ما میآییم و یک دیتابیسی از توکنها در کنار دیتابیسی از یوزرها میسازیم (البته درستترش، جدوله!) و به ازای هر یوزر معمولا دوتا توکن در اون دیتابیس قرار میدیم. یکیش رو بهش میگیم «توکن دسترسی» یا Access Token و یکی رو میگیم «توکن بازنشانی» یا Refresh Token. توکن دسترسی، معمولا یک تاریخ انقضایی داره و بعد از اون با استفاده از توکن بازنشانی، میتونیم یکی جدید بگیریم. اما در آموزش امروز، صرفا میخوایم توکن دسترسی رو به دست بیاریم.
خب، الان که تقریبا همهچی رو میدونیم، بریم برای پیادهسازی.
پیادهسازی یک اپلیکیشن ریلز با JWT
خب در قدم اول، باید یک اپ ایجاد کنیم. این اپ رو به این شکل ایجاد میکنیم:
rails new devise-jwt --api
خب توضیح واضحات:
قسمت rails که واضحا فراخوانی نرمافزار rails در ترمینال ماست.
قسمت new در خواست برای ایجاد یک اپ جدیده.
قسمت devise-jwt اسم پروژه ماست. حالا چرا؟ چون قراره از یک لایبرری با همین اسم استفاده کنیم. بنابراین، پروژه رو اینطوری اسم گذاشتیم.
در قسمت آخر هم، به ریلز گفتیم که ما تو رو بخاطر API هات دوست داریم. ویو نیاز نیست.
بعد از چند ثانیه (و بسته به سرعت اینترنت دقیقه) اپ ما ساخته میشه. بعد لازمه که مرحله مرحله کارهایی رو انجام بدیم.
نصب لایبرریهای مورد نیاز
خب، اول از همه با ویرایشگر متنی مورد علاقمون فایل Gemfile رو باز میکنیم و این خطوط رو بهش اضافه میکنیم :
gem 'devise'
gem 'devise-jwt'
gem 'rack-cors'
بعد از این که این خطوط رو اضافه کردیم، دستور زیر رو اجرا میکنیم:
bundle
این دستور چه کار میکنه؟ میاد و تمام لایبرریهای مورد نظر شما رو به صورت ایزوله در یک دایرکتوری، نصب میکنه. به این شکل شما میتونید به سادگی بدون رسیدن آسیب به باقی لایبرریهای روبی نصب شده روی سرور یا حتی کامپیوتر خودتون، ایدههاتون رو تست کنید.
لازم به ذکره که بعد از اجرای این دستور فایل Gemfile.lock بهروز میشه، این فایل حالا چه کار میکنه؟ این فایل حواسش به همهچی هست. در واقع، ورژن روبی، ورژن ریلز، لایبرریهای مورد نیاز و ورژنینگشون و … رو همه رو این فایل داره کنترل میکنه.
بعد از انجام مراحل فوق، کافیه این دستور هم اجرا کنیم:
rails g devise:install
این دستور چه میکنه؟ این دستور هم برای ما فایلهای devise رو در جای درستش قرار میده.
آشنایی با devise
برای احراز هویت در هر سیستمی ما دو راه داریم:
نوشتن سیستم احراز هویت از بیخ
استفاده از کتابخانههای موجود
در مورد روش «از بیخ»، ما معمولا این کار رو انجام نمیدیم. چرا؟ چون معمولا اونقدر خوب نیستیم که بتونیم امنیت سیستم رو به خوبی تامین کنیم. در مورد دوم، در هر فرمورک و زبانی، کتابخانههایی ساخته شدند که کمک میکنن ما بتونیم با اضافه کردنشون به پروژه خودمون، بخش احراز هویت رو هندل کنیم. برای ریلز devise ساخته شده. این لایبرری، یک لایبرری مبتنی بر cookie برای احراز هویت وباپهاست.
بعد از همهگیر شدن ReST API ها، لایبرری devise-jwt هم نوشته شد. این لایبرری، ابزاریه که به من و شما کمک میکنه بتونیم احراز هویت JWT رو به پروژهمون اضافه کنیم. در واقع هر سه لایبرری که به پروژه اضافه کردیم، کارشون همینه که JWT رو برای ما راحت کنند.
هندل کردن CORS
در این مطلب قصد ندارم در مورد CORS حرف بزنم، چون قبلتر ازش حرف زدم (و میتونید اینجا بخونید). اینجا ما صرفا قصدمون اینه که بیاییم و این مشکل رو حل کنیم. چطوری؟ خب این فایل:
config/initializers/cors.rb
رو با ویرایشگر متنی مورد علاقهمون باز میکنیم، و محتواش رو به این شکل تغییر میدیم:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
توجه کنید که این قسمت معمولا به صورت کامنتشده در کد هست، فقط کافیه آنکامنتش کنید و نیاز نیست که کلا این مورد رو کپی پیست کنید.
ساخت مدل و کنترلرهای مورد نیاز برای کاربر
یکی از خوبیهای devise اینه که به شکل scaffold گونهای، میتونه به ما کمک کنه که کاربر و سیستم کنترلش رو بسازیم. برای ساخت مدل کاربر فقط کافیه که این دستور رو اجرا کنیم:
rails g devise User
به این شکل میفهمه که باید یک مدل، مطابق مدل User ولی با مشخصات devise برامون بسازه. بعدش هم کافیه این دستور رو اجرا کنیم:
rails db:migrate
که جدولای مرتبط برامون در دیتابیس ساخته بشن.
حالا که خیالمون از بابت این قضایا راحت شد چی؟ هیچی. دو تا کنترلر هم میسازیم به این شکل:
rails g controller users/sessions
rails g controller users/registrations
بعد از این میشه گفت که کار ما اینجا تمام شده و باید بریم یه چیزایی رو ادیت کنیم 🙂
ویرایش مدل یوزر
بعد از این که کارهای بالا رو انجام دادیم، کافیه که بریم سراغ مدل یوزرمون و به این شکل ادیتش کنیم:
class User < ApplicationRecord
devise :database_authenticatable,
:jwt_authenticatable,
:registerable,
jwt_revocation_strategy: JwtDenylist
end
حالا این کار برای چیه؟ برای اینه که ما یک جدول دیگر به اسم JWT Deny List در نظر میگیریم و توکنهای منقضیشده رو درونش قرار میدیم. به اون شکل وقتی توکنی منقضی بشه، میتونیم به کاربر خطا نشون بدیم یا از توسعهدهندههای فرانت تیم بخوایم که وقتی اون خطا رو دیدن، کاربر رو لاگ اوت کنن. خلاصه که راه برای رسیدن به نتیجه مطلوب زیاده. بگذریم، بعد از این، در پوشه مدلها لازمه که یک فایل به اسم jwt_denylist.rb ایجاد کنیم و این محتوا رو درونش قرار بدیم:
class JwtDenylist < ApplicationRecord
include Devise::JWT::RevocationStrategies::Denylist
self.table_name = 'jwt_denylist'
end
بعد نیاز داریم که برای این قضیه یک مایگرشن اضافه کنیم:
rails g migration CreateJwtDenylist
سپس، فایل مایگرشن که معمولا در آدرس:
db/migrate
قرار داره رو باز میکنیم و محتواش رو به این شکل تغییر میدیم:
class CreateJwtDenylist < ActiveRecord::Migration[6.1]
def change
create_table :jwt_denylist do |t|
t.string :jti, null: false
t.datetime :exp, null: false
end
add_index :jwt_denylist, :jti
end
end
و بعد یک دور مایگرشنها رو اجرا میکنیم:
rails db:migrate
تا اینجا مطلب طولانی شد؟ ایرادی نداره. بریم یک قهوه بزنیم به بدن و برگردیم 🙂
کنترلر Session
امیدوارم که کافئین به قدر کافی مودتون رو بالا آورده باشه 🙂 حالا وقتشه که بریم و کنترلر session رو درست کنیم. نیازی نیست واقعا کار خاصی کنیم. تنها کاری که نیازه بکنیم اینه که کنترلری که ساختیم رو باز کنیم و این موارد رو درش کپی کنیم:
class Users::SessionsController < Devise::SessionsController
respond_to :json
private
def respond_with(resource, _opts = {})
render json: { message: 'You are logged in.' }, status: :ok
end
def respond_to_on_destroy
log_out_success && return if current_user
log_out_failure
end
def log_out_success
render json: { message: "You are logged out." }, status: :ok
end
def log_out_failure
render json: { message: "Hmm nothing happened."}, status: :unauthorized
end
end
نکته مهم، اگر هنگام ساخت کنترلر، جای users از چیز دیگری استفاده کردید باید Users رو در کد بالا به اون تغییر بدید. اگر هم کلا چیزی نذاشتید، کل قسمت Users:: رو ازش حذف کنید.
کنترلر Registration
خب عین همون بخش قبلی، شما کافیه کنترلر registrations رو باز کنید و این کد رو درونش کپی کنید:
class Users::RegistrationsController < Devise::RegistrationsController
respond_to :json
private
def respond_with(resource, _opts = {})
register_success && return if resource.persisted?
register_failed
end
def register_success
render json: { message: 'Signed up sucessfully.' }
end
def register_failed
render json: { message: "Something went wrong." }
end
end
تنظیمات نهایی devise
خب اول در ترمینال (یا cmd) این دستور رو اجرا کنید:
rake secret
و یک کد طولانی و مسخره بهتون میده 😁 اون رو در فایل:
config/initializers/devise.rb
در آخر فایل به این شکل کپی کنید:
config.jwt do |jwt|
jwt.secret = rake_secret_output
end
نکته بسیار مهم اینجا چیه؟ این که حواستون باشه این صرفا یک پروژه تسته و برای محیط پروداکشن اصلا جالب نیست که سیکرتها و توکنها، هاردکد باشن. برای اون زمان میتونید از ENV استفاده کنید.
مسیرها
خب، الان که تقریبا همهچی آرومه و ما چقدر خوشحالیم، کافیه که بیاییم و فایل routes.rb رو هم به این شکل ویرایش کنیم:
Rails.application.routes.draw do
devise_for :users,
controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'
}
end
خب پس چی میمونه که انجام ندادیم؟ یک سری آزمایش ساده 🙂
ساخت کاربر
خب الان کافیه بعد اجرای سرور ریلز (مطابق آموزشهای قبلی)، این دستور رو اجرا کنیم:
که اینها سرایند (Header) های ما هستند. در این قسمت، هرچی جلوی Authorization قرار داره توکن ماست. و میتونیم ازش استفاده کنیم.
بخش بعدی هم اینه :
{"message":"You are logged in."}
که صرفا به ما میگه ورودمون موفقیتآمیز بوده.
فکر کنم این مطلب، آخرین مطلبی بود که در مورد بیسیکهای روبیآنریلز مینوشتم. احتمالا در آینده نهچندان دور، همه اینها رو با هم به یک سری آموزش ویدئویی تبدیل کنم و از طریق آپارات یا یوتوب منتشرشون کنم.
طبیعتا یک قسمتهایی از آموزش در این مطلب پوشش داده نشده، سعی میکنم در آینده یک یا دو پست تکمیلی هم ارائه کنم که همه این قضایا به خوبی پوشش داده بشه (یا این که کلا در بخش ویدئویی در خدمتتون باشم).
به صورت کلی، دوست دارم بدونم نظر شما در مورد این تیپ آموزشها چیه؟ آیا ادامهشون بدم یا خیر؟ و این که آیا پایهش هستید که بحث فرانتند رو هم شروع کنیم یا روی همین بکند باقی بمونیم و اول یه پروژه کامل رو بکندش رو بزنیم و بعد بریم سراغ فرانت؟ 🙂
در آخر هم بابت وقتی که گذاشتید و مطلب رو خوندید ازتون متشکرم.
در پست قبلی، بررسی کردیم که اصلا MVC چیه و به چه کار میاد و یکم هم مثال ازش در روبی آن ریلز دیدیم. در این پست، قصد دارم مزایا و معایبش رو بگم و بگم که روبی آن ریلز، چه راهحلی برای مشکلاتش پیشنهاد میکنه.
باز هم لازمه که سلب ادعا کنم که این مطلب مطلقا آموزش روبی آن ریلز نیست و شما اگر میخواید روبی آن ریلز یاد بگیرید، میتونید تا پست بعدی منتظر باشید 😁
مروری بر کلیت MVC
از پست قبلی، این دید رو داریم که MVC در واقع یک روش تبدیل کردن موجودیتهای محصول به یک سری مدل، کنترل ارتباطاتشون با هم و با دنیای بیرون با یک سری کنترلر و نمایششون به صورت ویوئه (متفاوتتر از قبلی شد، نه؟ چون صرفا بیانم رو در تعریفش عوض کردم). اما حرفی از مزایای و معایبش نزدم.
عمدهترین دلیلم برای ادامه ندادن، این بود که مطلب قبلی زمان زیادی از من گرفت و حتی مجبور به ریبوت کردن لپتاپم میانه راه شدم. خود مطلب هم شدیدا طولانی بود و مطمئن بودم از یک حدی طولانیتر میشد، دیگه کسی اون رو نمیخوند.
حالا که تعاریف رو با هم بررسی کردیم، بریم سراغ اصل مطلب 🙂
مزایا و معایب معماری MVC
مزایا
تسریع فرایند پیادهسازی : همونطوری که در پست قبلی دیدید، اکثریت قریب به اتفاق چارچوبهای توسعه که با این معماری کار میکنند، ابزارهایی برای تولید و تست موجودیتها در اختیار شما میذارن. این به خودی خود موجب تسریع فرایند پیادهسازی میشه. در مورد توسعه هم این قضیه میتونه تا حدی صادق باشه، البته توسعه رو در بخش معایب بررسی میکنیم.
تسهیل فرایند کار گروهی : در یک بیزنس، معمولا بیش از یک نیرو روی محصول نهایی – چه در پیادهسازی چه در توسعه – کار میکنه. این معماری به توسعهدهندهها کمک میکنه بهتر بتونن محصول رو درک کنن. بخصوص اگر قرار باشه هر شخص روی یه بخشی کار کنه و پیادهش کنه.
تسهیل فرایند بهروزرسانی : طبیعیه که بهروزرسانی یک محصول، کار سادهای نیست. اما یک فرض ساده رو در نظر بگیرید. مثلا من، یک فروشگاه اینترنتی دارم، قراره در نسخه جدید وبسایتم، بخشی هم افتتاح کنم که افراد بتونن لوازم کارکرده هم خرید و فروش کنن. اضافه کردن یک موجودیت جدید به نرمافزاری که MVC نوشته شده به شدت سادهتر میشه و من فقط لازمه مدل بخش «کارکرده» رو اضافه کنم و روابطش با باقی اجزا رو پیادهسازی کنم.
تسهیل فرایند کشف و رفع باگ : خب از اونجایی که هر موجودیتی، در این معماری به شکلی جدا از موجودیت دیگره، خیلی راحت میشه فهمید مشکل از کجاست. البته لازمه این رو بگم که در معایب هم قراره به این بخش اشاره کنیم و در گوشتون هم میگم که Rest API در این زمینه میتونه بهتر عمل کنه 🙂
خب ما ایرانیا یک ضربالمثل معروف داریم که میگه «گل بیعیب، خداست». پس این معماری و طبیعتا فرمورکهایی که با این معماری کار میکنند هم خالی از ایراد نیستند. در این بخش از معایب MVC میگم و البته بخشیش هم از معایبی که برای ریلز و لاراول گفته شده نقل میکنم.
در مورد بخشی که از ریلز و لاراوله، اسمی از فرمورک نمیارم چون در نظرم این معایب، معایب معماری هستند و نه فرمورک. در واقع اینطوری فرض کنیم که یک سلولی که مشکلی داشته تقسیم شده و همه سلولهای جدید، همون مشکل رو دارند 😁
معایب
سختی درک معماری : این موضوع، میتونه برای برنامهنویسهای تازهکارتر، کمی مشکلساز باشه. توصیه میکنم قبل از این که لقمه بزرگ بردارید و سراغ ریلز، جنگو یا لاراول برید حتما اول با سیناترا، فلاسک یا لومن کار کنید. به این شکل فرمورکها میتونن براتون به شدت قابل درکتر بشن.
خارج شدن شکل نرمافزار از کنترل توسعهدهنده(ها) : این مورد کمی پیچیدهست. فقط بذارید به این شکل بهتون بگم که شما مثلا یه سری واژه رو نمیدونید چطور مدیریت کنید. مثلا ممکنه اسم مدل مربوط به حساب بانکی رو Hesab, Bank یا Bank Account بذارید و نفر بعدی که روی کد شما کار میکنه، با این قضیه به مشکل بخوره. بهترین راه اینه که این موارد، قبل از پیادهسازی کشف و مستند بشن.
انعطاف پایین : طبیعیه که وقتی یک جعبهابزار کامل دم دستتون باشه، دیگه سراغ ساخت ابزار نمیرید. اکثر فرمورکهای MVC هم این مشکل رو دارند و اگر شما بخواهید بخشی هم خودتون پیاده کنید، به شدت به مشکل میخورید.
پرفرمنستایم پایین : خب از اونجایی که اکثر این فرمورکها، دارن همه چیز رو خودشون هندل میکنن، ممکنه هزینه بالایی برای اجرا داشته باشند. البته این هزینه ممکنه با توجه به سختافزارهای امروزی زیاد هم بالا حساب نشه، اما چرا وقتی میشه با کمترین هزینه کاری کرد، هزینه رو بیخود و بیجهت ببریم بالا؟
رفع اشکال پرهزینه : درسته که فرایند کشف و رفع باگ رو گفتیم که آسونه، اما هزینه بالایی داره. حواسمون باید به این موضوع باشه که داریم با چیزی کار میکنیم که همه چیش به همه چیش ربط داره و قطع این ارتباط میتونه هزینه زیادی وارد کنه بهمون.
بزرگ شدن غیرقابل کنترل پروژه : خب وقتی که MVC کار میکنیم، عموما خیلی کم پیش میاد که بخواهیم موجودیتها رو به صورت سرویسهای مجزا توسعه بدیم. در واقع اینجا خبری از میکروسرویس و اینا نیست! همین باعث میشه بیزنس از یک حدی که بزرگتر بشه، کنترلش به شدت سخت شه. از همین رو، معمولا در کنار MVC یک معماری دیگری مثل rest هم استفاده میشه که این داستانها رو نداشته باشیم.
حالا بیاید ببینیم چه راهحلایی برای این قضیه داریم؟ یک راه خیلی خوب اینه که وقتی مدلی ساخته میشه، کنترلر و ویوهای مربوطه هم اتوماتیک تولید بشن. بعدها میتونیم اون چیزی که نیاز نداریم رو از این چرخه حذف کنیم. خب چطوری؟ در این بخش، دو راه حل میارم. یکی از ریلز و دیگری لاراول (فکر کنم کسی انتظار لاراول رو در این قسمت نداشت).
راه حل Ruby on Rails
در ریلز یک مفهومی داریم به اسم scaffold. این مفهوم چی کار میکنه؟ میاد مدل، ویو و کنترلر یه موجودیت رو برای ما میسازه. برای زمانهایی که Rest API نداریم و میخواهیم صفر تا صد اپ رو خودمون بزنیم، یکی از بهترین انتخابها در ساخت و طراحی موجودیتها همینه.
مثال پست بلاگ رو در نظر بگیرید. چطوری میتونیم به سادگی همهچیش رو هندل کنیم؟! سادهست، کافیه این دستور رو تایپ کنیم:
rails generate scaffold Post title:string slug:string body:text
و این دستور به خودی خودش میاد و همه چیزهایی که نیاز داشتیم رو میسازه. خوبیهای این روش چیه؟
استاندارد بودن متدها در کنترلر (یعنی نیاز نیست دیگه زحمت مضاعف برای Routing بکشیم)
وجود viewهایی که پارامترهای درست ارسال و یا دریافت میکنن (کاهش هزینه کشف و رفع باگ در مراحل اولیه توسعه)
اما خب یک بدی بزرگ هم داره و اون اینه که خلاقیت شما رو میتونه کلا نابود کنه. برای اون هم راهکارهایی هست. مثل این که شما یه کنترلر مجزا بسازید و متدها و endpointهای مورد نظر خودتون رو اونجا تعریف کنید.
باقی موارد، همه مثل مطلب قبلیه و خب در مطالبی که در آینده نزدیک خواهم نوشت، حتما اشاره خواهم کرد به این موضوع که چه فعل و انفعالاتی در ریلز رخ میده برای ساخت این ماجراها 🙂
راهحل در لاراول
یک سلب ادعای کوچک ابتدای این بخش بکنم؟ عمده تجربه من با لاراول روی Rest API بوده و فرصتی نشده که MVC باهاش کار کنم. شاید هم هیچوقت MVC کار نکنم. اما این راهحل قطع به یقین برای MVC هم پاسخگوئه.
اول از همه یک مدل میسازیم:
php artisan make:model Post
و خب وارد جزییات نمیشم، میتونیم جزییات مدل رو در فایلهای مربوطه بررسی کنیم.
بعد برای این مدل به این شکل میتونیم کنترلر بسازیم:
البته لازم به ذکره که باید دقت داشته باشید همیشه کنترلرها از جنس resource و CRUD نیستن و این دو راهکار، در واقع برای وقتی خوبن که شما نیازمند CRUD باشید و نخواهید هزینه ساخت کنترلر «از بیخ» رو متحمل بشید.
جمعبندی مطالب
در دو مطلب، هم تعاریف مرتبط با MVC رو یاد گرفتیم، هم یه نیمچه اپ MVC نوشتیم و هم مزایا و معایبش و راهحلهای احتمالی برای معایب قضیه رو بررسی کردیم.
این مطالب، بیش از این که رنگ و بوی برنامهنویسی داشته باشند، مرتبط با مهندسی نرمافزار بودند و خوشحالم که در این زمینه هم محتوایی تولید کردم. فکر کنم این پست دیگه جمعبندی خاصی نیاز نداشته باشه. فقط خواستم بابت وقتی که برای خوندن این مطلب گذاشتید، ازتون تشکر کنم 🙂
احتمالا اگر با فرمورکهایی مثل جنگو، ریلز یا ASP کار کرده باشید، عبارت MVC رو به کرات مشاهده کردید. در این پست، قصد دارم تا در مورد این معماری توضیحاتی ارائه کنم. در هر بخش هم، یک مثالی از فرمورک روبی آن ریلز آوردم.
قبل از شروع بعنوان سلب ادعا عرض کنم که شما نیاز دارید که خودتون، روبی آن ریلز رو جداگانه یاد بگیرید و این مطلب، مطلقا آموزش روبی آن ریلز نیست.
معماری MVC یعنی چی؟
خب MVC یک مخففه برای Model, View و Controller. در این معماری، یک نرمافزار (یا بهتره بگیم ایده/بیزنس) رو به سه موجودیت مدل، ویو و کنترلر تقسیم میکنیم و هر قسمت ایده یا بیزنس رو به یکی از اینها تبدیل میکنیم. در واقع، فرمورکها اینجان که ما فرایند ساخت این قضایا رو سریعتر پیش ببریم.
پس، بهتره جای این که صرفا دنبال زیربغل مار بگردیم، هر موجودیت رو جدا تعریف کنیم و ببینیم تهش به چی میرسیم!
مدل – Model
مدل، همونطور که از اسمش پیداست؛ یک مفهوم انتزاعی از یک موجودیته. بذارید یک مثال ببینیم. بیاید یک پست وبلاگ رو بررسی کنیم.
پست وبلاگ چیا داره؟ پست وبلاگ در نظر من اینها رو حتما داره:
عنوان که به عنوان یک رشته متنی در نظر گرفته میشه.
عنوان کوتاه یا slug که این هم یک رشته متنی در نظر گرفته میشه.
متن بدنه یا body که «متن» در نظر گرفته میشه.
توجه کنید که text از نظر اکثر فرمورکها با string متفاوته. این تفاوت رو احتمالا در مستندات فرمورکی که باهاش کار میکنید میتونید پیدا کنید.
حالا این مدل رو چطوری میسازیم؟ در ریلز به این صورت میتونیم یک مدل بسازیم:
rails generate model Post title:string slug:string body:text
بعد از اون هم به این شکل مایگرشنها رو اجرا میکنیم:
rails db:migrate
خب الان چی داریم؟!
الان چیزی نداریم جز یک مدل، که صرفا میگه «تعریف من از پست چیه». این تعریف کجا استفاده میشه؟ در دیتابیس. خب پس یعنی چی؟ بیاید یک تعریف کلی از مدل ارائه کنیم:
مدل عبارت است از تعاریف انتزاعی و ویژگیهاشون که در یک پایگاه داده ذخیره میشه.
خب، الان که میدونیم مدل چیه، چطور میتونیم یک نمونه ازش اجرا کنیم؟ برای نمونه در ریلز، ما اول کنسول ریلز رو باز میکنیم:
rails c
و سپس این دستور رو در کنسول وارد میکنیم:
Post.create(:title => "Hello, World", :slug => "hello-world", :body
=> "This is a first post made the wrongest way possible")
و به این شکل، ما یک پست ساختیم. اما آیا روش بهتری هم هست؟ بله هست!
کنترلرها – Controllers
طبیعتا وقتی به شما یک API داده میشه، از شما نمیخوان که با دستورات روبی پست بسازید، بهروز کنید یا حذف کنید! چیزی که به شما میدن چنین چیزیه:
GET /api/v1/posts
و این باید لیست همه پستها رو برگردونه. پس چطور این اتفاق میافته؟ با موجودیتی به اسم «کنترلر». کنترلر کارش چیه؟ کنترلر همونطور که از اسمش پیداست، میتونه کنترل کنه (یا بعبارتی چطور چشمبسته غیب بگیم؟). کنترلر وظیفهش انجام عملیات CRUD روی مدله.
حالا CRUD چیه؟ این هم یه مفهومی در بطن MVC و Rest API عه که باید بدونید چی به چیه و چی کار میکنه. عبارت CRUD مخفف Create, Restore, Update و Destroy عه. بیاید با هم دقیق بررسی کنیم:
حرف C یا Create : یعنی کنترلر باید بتونه برای من، یک نمونه از مدلم رو بسازه.
حرف R یا Restore (که در بعضی منابع Retrieve هم گفتن) : یعنی کنترلر باید بتونه محتوای یک مدل یا همه مدلها رو به من نشان بده.
حرف U یا Update : یعنی کنترلر باید بتونه در وضعیت یک نمونه از مدل، تغییری ایجاد کنه.
حرف D یا Destroy : یعنی کنترلر باید بتونه یک نمونه از مدل رو حذف کنه.
شما همون پست بلاگ رو در نظر بگیرید. این پست ممکنه نیاز داشته باشه که ویرایش بشه، نیازمند اینه که گاهی حتی حذف کامل بشه و … . این کار رو با کنترلر انجام میدیم. حالا چطوری یک کنترلر میسازیم؟ به این شکل:
rails generate controller api/v1/posts
سپس درون فایل کنترلر، این دو تابع رو برای حرف R اضافه میکنیم:
def index
@posts = Post.all
render json: @posts
end
def show
@post = Post.find(params[:id])
render json: @post
end
در یک تابع، قراره که کل پستها رو ببینیم و در یکی، فقط اونی که با ID مورد نظر ما درخواست شده نمایش داده میشه. خب، الان کافیه با ابزاری مثل curl تست کنیم API مون رو.
~/playground/mvc-tutorial/ [master] curl http://localhost:3000/api/v1/posts/1
{"id":1,"title":"Hello, World","slug":"hello-world","body":"This is a first post made the wrongest way possible","created_at":"2021-03-23T16:19:41.950Z","updated_at":"2021-03-23T16:19:41.950Z"}
حالا جهت این که C هم ببینیم، اون هم به کنترلر مربوطه اضافه میکنیم، اما بقیهش رو از مستندات ریلز میتونید یاد بگیرید 😁
پس این تابع رو به فایل کنترلرمون اضافه میکنیم:
def create
@post = Post.new(post_params)
if @post.save
render json: {:post => @post, :status => success}
else
render error: {:error => "Failed"}
end
end
این تابع چی کار میکنه؟ اول میاد از طریق یک تابع خصوصی به اسم post_params تعدادی از پارامترها مثل عنوان، عنوان کوتاه و متن بدنه رو دریافت میکنه، یک نمونه از مدل پست میسازه. اگر ذخیرهسازی پست با موفقیت انجام شه، محتوای پست رو به ما نمایش میده.
با ابزار curl به این شکل میتونیم از این بخش کنترلر استفاده کنیم:
curl -X POST -H 'Content-Type: application/json' -i http://localhost:3000/api/v1/posts --data '{
"title":"A post from a request",
"slug":"a-post-from-a-request",
"body":"This post has been create using an API call, to show you how awesome MVC can get!"
}'
البته حواستون باشه در این مورد، حتما باید هدر Content-Type رو ارسال کنیم.
این هم نمونه جوابی که این تابع باید به ما بده:
{
"post": {
"id": 2,
"title": "A post from a request",
"slug": "a-post-from-a-request",
"body": "This post has been create using an API call, to show you how awesome MVC can get!",
"created_at": "2021-03-23T17:37:55.502Z",
"updated_at": "2021-03-23T17:37:55.502Z"
},
"status": "success"
}
اما خب، چطوری این داده رو میتونیم همینجا ببینیم؟! بدون این که از curl و … استفاده کنیم؟
ویوها – View
در بخش پیش، کنترلرها رو با دیدی که برای API و … داریم ساختیم. برای استفاده از ویو، یک بار دیگه یه کنترلر میسازیم:
rails generate controller posts
در این کنترلر این دو تابع رو قرار میدیم:
def index
@posts = Post.all
end
def show
@post = Post.find(params[:id])
end
خب قرار نبود این قسمت اینجاش با کد زدن شروع شه اما خب نیاز بود درک کنیم که ویو دقیقا چیه. خب، بیایم با دو تعریف آشنا شیم.
قابل خواندن برای ماشین (Machine Readable) : این مفهوم، به معنای دادههاییه که صرفا برای کامپیوتر قابل درک و خواندن هستن و برای کاربر، خواندنشون مشکله. مثل خروجی JSON یا چیزایی که تو دیتابیس ذخیره میکنیم. وقتی از روی API دادهای میفرستیم، در واقع دادهها رو به صورت قابل خواندن برای ماشین میفرستیم و دریافت میکنیم.
قابل خواندن برای انسان (Human Readable) : این مفهوم، به معنای دادههاییه که برای انسان قابل خوندن هستند. مثل همین پستی که شما دارید میخونید. در واقع این پست در یک دیتابیس MySQL به شکل عجیب و غریب (برای انسان) ذخیره شده و وقتی شما روی لینکش کلیک میکنید، به شکل قابل خواندن برای انسان درمیاد.
اگر صرفا API داشته باشیم، کار ما MVC نیست، اما میتونیم ویو رو با استفاده از Front End داشته باشیم (که در آینده در مورد اون هم یک مطلب خواهم نوشت). اما میتونیم بیایم و برای حداقل همون حرف R یک ویو بسازیم (در حقیقت دو تا). چرا؟ چون بعضی وقتا ممکنه برنامهنویس فرانت نداشته باشیم، بعضی وقتا ممکنه حتی نیازی به فرانت نباشه و … .
برای ساخت ویو در ریلز، نیازی به اجرای دستوری نیست. در این فرمورک، وقتی کنترلر بسازید در پوشه:
app/views
یک پوشه به اسم کنترلر مربوطه ساخته میشه. پس در پوشه:
app/views/posts
دو فایل به اسمهای index.html.erb و show.html.erb ایجاد میکنیم.
در فایل index.html.erb این موارد رو باید داشته باشیم:
<h1> Posts </h1>
<% for post in @posts %>
<ul>
<li>
<a href="/posts/<%= post.id %>"> <%= post.title %></a>
</li>
</ul>
<% end %>
همونطور که میبینید، این کد دو تفاوت اساسی با HTML معمولی داره :
پسوندش یه ERB اضافه داره
کد روبی وسطش زده شده.
خب، این زبون، HTML نیست (بله، HTML هم زبانه، فقط «زبان برنامهنویسی» نیست!) بلکه زبان تمپلیتینگ خود روبیه. مثل blade در php یا Jinja در پایتون.
حالا اگر با مرورگر به localhost:3000/posts بریم این صحنه زشت رو میبینیم 😁
و اگر روی لینکها کلیک کنیم، وارد پستها میشیم:
البته یادتون باشه slug معمولا برای url کاربرد داره ولی چون اینجا قصد آموزش ریلز نبود، از این ماجرا صرف نظر کردیم.
خب، حالا بعد یک مطلب طولانی، میدونیم که چی به چیه؛ بیاید با هم جمعبندی کنیم.
جمعبندی مطلب
اول از همه در این مطلب به یک تعریفی برای MVC رسیدیم. در واقع، کار ما بعنوان یک مهندس نرمافزار، تبدیل مفاهیم و موجودیتهای یک بیزنس و روابطشون با هم به یک سری مدل، کنترلر و نحوه نمایششون به کاربر در فرم ویو خواهد بود. حالا که یک تعریفی از MVC داریم، به نظرم بد نیست که بیایم هر مورد هم یک بار دیگر، بررسی کنیم.
مدل : مدلها، تعاریف انتزاعی از موجودیتها، ویژگیها و روابط بینشون هستند. به عبارتی، شکلی که ما قراره داده خام رو پردازش کنیم، در مدل تعیین میشه. کمی راحتترش کنم؟ مدل در واقع ساختار دیتابیس ماست.
کنترلر : کنترلر وظیفه ساخت یک نمونه از مدل، استخراج داده از دیتابیس، بروزرسانی داده در دیتابیس و حذف یک رکورد از دیتابیس رو عهده داره. این هم اگر بخوام راحت توصیف کنم، میگم ابزاری که باهاش دیتابیس رو به شکل سادهتری کنترل میکنیم.
ویو : ویو، نتیجه یک کوئری رو به صورت قابل خواندن توسط انسان، به ما نمایش میده. نتیجه کوئری معمولا به صورت یک جدول در دیتابیس (در واقع یک یا چند سطرش) یا به صورت JSON برمیگرده که توسط انسان قابل خوندن نیست. ما در ویو (و البته اغلب فرانت) این اتفاق رو رقم میزنیم.
البته موارد دیگری هم هستند که دیگه واقعا از حوصله این مطلب خارج شدند. دلیل عمدهش؟ طولانی شدن بیش از حد این مطلب. وگرنه دوست داشتم از معایب و مزایای MVC هم حرف بزنم. یک اتفاق بامزه هم این وسط افتاد که من حتی مجبور شدم لپتاپ رو ریبوت کنم و شانس آوردم که دو سه ساعت فکر و نوشتن، نپریده بود 😂
در پایان، از همه شمایی که این مطلب رو خوندید تشکر میکنم که وقت گذاشتید بابت خوندن مطلب. ضمنا، این اتفاقات در فرمورکی که شما استفاده میکنید چطوری رقم میخوره؟ در نظرات منتظرتونم 🙂
در دنیای امروزی، بخش بسیار بزرگی از بیزنس و همچنین توسعه نرمافزار مرتبط به توسعه عملیات (Dev Ops)، مدیریت سیستم (System Administration) و همچنین استقرار و یکپارچگی ادامهدار (CI/CD) میشه. شاید حتی مهمتر از اصل نرمافزار، رسیدگی به این موضوعات باشه. در این پست، قراره که با هم بررسی کنیم چطور میتونیم در پایان روز، به خودمون بگیم DevOps Engineer؟ و چه چیزایی باید بلد باشیم؟ 🙂
مدیریت سیستم یاد بگیرید
یادگیری مدیریت سیستم، بخش «عملیات» قضیه رو معمولا شامل میشه. پس لازمه که اینجا چیزایی رو بلد باشیم که معمولا در شرکتها و سازمانهای بزرگ بهشون نیاز میشه. اما قبل از اون، لازمه که یه چیزایی رو به صورت عمومی بلد باشیم. پس بیاید با هم بررسی کنیم که عمومیات دواپس شدن چیا هستن؟
یادگیری لینوکس. عموم شرکتها در دنیا در حال حاضر، سرورهای لینوکسی دارند. بلد بودن لینوکس، یک «باید» در یادگیری دواپس محسوب میشه. یادگیری لینوکس اصلا سخت نیست. کافیه یک توزیع خاص (مثل اوبونتو) رو نصب کنید و باهاش بازی کنید. کم کم دستتون میاد که چی به چیه. بعد از این ماجرا، میتونید یک سرور اجاره کنید و چیزایی که یاد گرفتید رو روش تست کنید.
آشنایی با وبسرورها. وبسرورها، نرمافزارهایی هستند که به شما امکان نمایش نرمافزار و محتوای تولیدی از طریق پروتکل HTTP رو میدن. در دنیای امروز اکثریت قریب به اتفاق کسب و کارهای کوچک و حتی بزرگ، از NGINX استفاده میکنن. پس بد نیست بعد از این که لینوکس یاد گرفتید، روی سرور یا ماشین مجازی لینوکسیتون یک وبسرور نصب کنید و سعی کنید یک صفحه استاتیک باهاش نمایش بدید.
آشنایی با شبکه. گرچه معمولا این مورد رو باید اول از همه بیاریم، اما من شخصا معتقدم که یادگیری لینوکس در بحث مدیریت سیستم به هرچیزی ارجحه. اما از این موضوع که بگذریم، چرا شبکه؟ شبکه پایه و اساس دواپسه. شما بدون بلد بودن شبکه، تقریبا هیچ کاری نمیتونید بکنید. اما چه حد شبکه بلد بودن خوبه؟ دقت کنید که اینجا قرار نیست ما نیروی آیتی یک سازمان باشیم، پس فقط کافیه که پایههای شبکه، آیپی و بعضی پروتکلهای مرسوم (SSH, FTP, HTTP, SMTP و …) رو بدونیم و بدونیم که هرکدوم چطور و کجا کار میکنند.
آشنایی با فایروال و تامین امنیت شبکه. فکر کنم عنوان خودش گویاست. در لینوکس، ما معمولا از iptables یا اینترفیسهایی که براش ساخته میشن (مثلا اوبونتو UFW و دبیان apparmor رو دارند) استفاده میکنیم. این خیلی مهمه که شما بعنوان مدیر سیستم، در جریان باشید که چه چیزایی از بیرون در دسترسه و این حجم از دسترسی، چقدر میتونه آسیبزا باشه.
موارد بالا، مواردی هستند که حتما باید بلد باشید. فرقی هم نمیکنه که جایی استخدام شدید یا اگر قراره بشید، ازتون خواستند بلد باشید یا نه. در واقع «باید»های مدیریت سیستم موارد بالان.
اما در بسیاری از شرکتها یک سری سناریو خاص وجود داره که اینها رو میتونیم با هم بررسی کنیم، گرچه قرار نیست همه موارد رو با هم یاد بگیریم، اما چیزایی که به نظرم ممکنه وجود داشته باشند رو در اینجا بررسی میکنم.
استفاده از یک ابر خصوصی به جای چندین سرور عمومی. این مورد، مورد خوب و امنیه. گذشته از این که باعث میشه خیلی از موارد (مثل دیتابیس و …) از بیرون در دسترس عموم قرار نگیرند، هزینهها رو هم پایین میاره. فقط حواستون باشه که در این مورد، معمولا چند چیز اتفاق میافته که باید بلد باشید:
استفاده از لود بالانسر : لود بالانسرهای مرسوم مثل haproxy میتونن نقطه شروع خوبی باشن. البته این هم در نظر داشته باشید که معمولا ارائهدهندگان سرویسهای ابری؛ خودشون هم لود بالانسینگ رو انجام میدن.
استفاده از سیستمهای مانیتورینگ : طبیعتا شما برای این که ببینید هرکجا چه اتفاقاتی میافته، نیاز به یک سیستم مانیتورینگ خوب دارید. در حال حاضر سرویسهایی مثل prometheus و zabbix وجود دارند. همچنین میتونید اینها رو به grafana و امثالهم متصل کنید و به شکل زیبایی، اونها رو ویژوالایز کنید.
استفاده از نرمافزارهای بیلد شده به صورت سفارشی. گرچه این مورد رو شخصا درک نمیکنم (چون نسبت به نرمافزاری که از کانال رسمی – مثل مخزنهای توزیع لینوکستون – نصب میکنید ممکنه امنیت و پایداری کمتری نشون بدن) اما برخی سازمانها ممکنه وبسرور، کامپایلر یا مفسر یا حتی کرنل رو خودشون از نو بیلد کرده باشن. پس یادتون باشه این مورد هم تا حدی یاد بگیرید که اگر نیاز به بیلد مجدد شد گیر نکنید 😁
در مورد مدیریت سیستم به قدر کافی یاد گرفتیم، دیگه چی میمونه؟ نظر من رو بخواید الان وقتشه که یک سری ابزار رو با هم بررسی کنیم. توجه کنید که ابزارهایی که در این بخش ازشون حرف میزنم، ابزارهایی هستند که خودم باهاشون تجربه کار دارم. فلذا اگر ابزاری از قلم افتاده، در بخش نظرات در مورد ابزارهای مورد نظر خودتون صحبت کنید. من خوشحال میشم 🙂
ابزارهایی که باید یاد بگیرید
وبسرور
گرچه این رو در بخش قبلی اشاره کردم، در اینجا میخوام صرفا کمی در مورد NGINX حرف بزنم. یادتون باشه که NGINX امروزه یک انتخاب خوبه چون:
در بسیاری از توزیعها، وجود داره. در حدی که خیلی از توزیعهای سروری رو وقتی نصب کنید؛ ممکنه همراهش نصب شده باشه.
پیکربندی به شدت سادهای داره (و خب کاش حداقل نیاز نبود ته هر خط پیکربندی شما یک سمیکالن بذاری)
ابزارهای جانبی بسیار خوبی مثل python3-certbot-nginx براش ساخته شده که امکان SSL و … گرفتن برای دامنه خاص و زیردامنهها و … رو به شدت ساده میکنه.
تقریبا برای هرکاری یه آموزشی ازش هست!
ابزارهای CI/CD
خب ابزارهای CI/CD چی هستند؟ به صورت کلی، این ابزارها اینجان که کار استقرار (Deploy) و یکپارچگی (Integration) هرآپدیت با نسخه قبلی رو اتوماتیک انجام میدن. ابزارهای زیادی برای این کار وجود دارند من جمله Travis CI, Jenkins و البته معروفترینشون Gitlab CI/CD (حداقل در ایران).
این ابزارها به این شکل عمل میکنن که یه سری فایل پیکربندی (در مورد گیتلب از نوع YML ) دریافت میکنند و اون رو بررسی میکنند. سپس مطابق اون، عملیات رو انجام میدند و نرمافزار شما رو مستقر میکنن. خوبی گیتلب در این زمینه اینه که به ازای هر بهروزرسانیای که شما انجام بدید، یک بار Pipeline اجرا میکنه و بروزرسانیها رو روی سرور مورد نظر اعمال میکنه. البته باقی ابزارها هم امکان اتصال به گیت رو دارند پس نگران نباشید.
ابزارهای مانیتورینگ
طبیعتا بالا بودن یا نبودن سرویسها، دیتابیس، سرویسهایی که از بیرون دریافت میکنیم و یکپارچگی داریم باهاشون، مهمن. همینطور ظرفیتی که در دیسک و حافظه و … اشغال شده هم مهمه که دونسته بشه. فلذا اینجا لازمه که ابزاری باشه که اینجا بیاد و این رو برای ما چک کنه.
این ابزار معمولا چیه؟ خب ابزارهای زیادی براش هست و من تجربهم استفاده از prometheus بوده. پرومتئوس یک سری ابزار خاص داره که بهش میگن exporter. شما روی هر قسمتی که نیاز دارید (مثلا nginx یا خود سرور که بهش میگن node یا هرچیزی از این قبیل) یک اکسپورتر نصب کنید و نتایج آنالیزها رو اینجا ببینید.
همچنین نتایج معمولا روی پرمتئوس زیبا نیستن، به همین خاطر شما میتونید یک ابزار بهتر مثل Grafana نصب کنید و نتیجه رو به شکل قشنگی visualize کنید. همچنین میتونید روی هرکدوم یک سیستم alerting ست کنید که از روشهای مختلفی مثل پیامک، ایمیل یا حتی پیام در اسلک بهتون هشدار بده که کجا چی درست نیست.
ابزارهای ذخیرهسازی
خب، این هم یه چیزی که شاید کمتر ازش با خبر بوده باشید :). در دنیای امروز تقریبا کسی نیست که رو همون سروری که نرمافزارش هست، فایل ذخیره کنه. پس چی کار میکنن؟ هیچی، اونجاهایی که جزء دنیا حساب میشن؛ معمولا از Amazon AWS استفاده میکنن و پارتیشن S3 دریافت میکنن. S3 یعنی Simple Storage Solution (سه تا S) و خب این حقیقت وجود داره که راهکار بهتریه. چرا؟ چون شما برای ذخیرهسازی صرفا هارد نیاز داری و نه پردازنده یا رم زیاد.
اما نگران نباشید، اگر به هر دلیلی دسترسی به AWS ندارید، میتونید در همین ایران از ابزارهایی مثل ابرآروان و پشتیبان هم استفاده کنید. فقط کافیه که یاد بگیرید که چطور نرمافزار رو با S3 یکپارچه کنید (اینجا اهمیت این ماجرا که مهندس دواپس نیازمند اینه که دانش برنامهنویسی داشته باشه مشخص میشه) و دستورالعملهای لازم رو به توسعهدهندهها بدید؛ یا این که اصلا خودتون کدبیس رو درک کنید و این یکپارچهسازی رو انجام بدید.
یک راه دیگه هم داشتن سرور با حجم بالای هارددیسک (در ابعاد ترابایت) میتونه باشه. بعد از اون شما نیاز دارید تا یک نمونه S3 روی اون مستقر کنید. برای این کار میتونید از ابزاری مثل minio بهره بگیرید.
ابزارهای ارکستراسیون
ابزارهای ارکستراسیون چی هستند؟ ارکستر در موسیقی، به معنای «گروهی از نوازندگان»ــه. یعنی یک گروهی که مثلا دو نفر ویولن میزنن، یک نفر ویولا و یک نفر چلو. در دواپس ارکستر به مجموعهای از سرورها یا شبکهها گفته میشه که یک کار انجام میدن. تا حالا دقت کردید چطوریه که شما سرعت کارتون با توییتر در آلمان با سرعت کارتون با توییتر در آمریکا یکیه؟ یا مثلا چطوریه که شما از ایران یک عکس رو پست میکنید و مثلا خاله شما در آمریکای شمالی اون رو لایک میکنه؟!
علتش اینه که این نرمافزارها به عبارتی Orchestrate میشن (فارغ از بحث CDN و …) یعنی از یک نرمافزار و همچنین دیتابیسشون (البته دیتابیس Cache و نه دیتابیسهای اصلی) بیش از یک نمونه در حال اجراست. برای شما سوال نشده که اینا چطور هندل میشن؟ خب جواب اینه که ابزارهای ارکستراسیون استفاده میشه.
از بین این ابزارها میشه به Docker Swarm و Kubernetes و Ansible اشاره کرد. طبق تجربه با Ansible به شما بگم که شما تنظیماتی که نیاز دارید رو مشابه CI/CD در یک سری فایل پیکربندی (انسیبل بهشون میگه استوری) مینویسید و مجموعهای از استوریها رو در یک namespace قرار میدید. مثلا فرض کنید همین وبلاگ کجاها قراره باشه، من یه namespace به اسم haghiri75 میسازم و اطلاعات استقرار رو بهش میدم.
با ابزارهای ارکستراسیون، آمادهسازی و پیادهسازی سناریوهای سرور و یا ابر خصوصی به شدت سادهتر و سریعتر خواهد شد.
بسیار عالی، این بخش هم تمام شد. یک بخش کوچک هم مونده که اون هم میخونیم و بعدش این دفتر هم به پایان میرسونم. تا اینجا اگر خوندید، یکم به خودتون استراحت بدید. بعد بخش بعدی رو بخونید و یادتون نره که این مطلب رو با دوستانتون به اشتراک بذارید.
برنامهنویسی یاد بگیرید
بسیار خوب، در این بخش که در واقع بخش پایانی این مطلب در مورد اینه که چطور DevOps بشیم، لازمه اشاره کنم به این که نیاز دارید برنامهنویسی بلد باشید. حالا به چه زبونی و در چه حد؟ اینها مهمن. خب در این قسمت یکم در مورد زبانهایی که «باید» بلد باشید صحبت میکنم و بعد از اون هم راهنمایی میدم در مورد زبانهایی که احتمالا در جریان کار مجبورید باهاشون کار کنید.
پایتون، از چیزایی که باید بلد باشید!
چرا پایتون؟ خب پایتون این روزها طوریه که شما حتی مهندس کامپیوتر یا توسعهدهنده هم نباشی احتمالا دوست داری یادش بگیری و خیلیها کم و بیش پایتون رو بلدند. اما چرا بعنوان یک مهندس دواپس باید پایتون بلد باشیم؟
بر خلاف گذشته که خیلی از پیکربندیهای سرور با پرل انجام میشد، سالهاست که توزیعهای مطرح لینوکس مثل اوبونتو، ردهت، دبیان، سنتاواس و … دارند میرن سمت پایتون. پس به نوعی شما زبانی رو یاد گرفتید که برای پیکربندی سرور داره استفاده میشه و عملا ضرری نکردید.
ابزارهای مانیتورینگ و همچنین پنلهایی که براشون ساخته شده هم معمولا پایتونی هستند. حداقل گرافانا که با پایتون نوشته شده و دونستن پایتون میتونه در بهبود کارکرد این قضیه به شما کمک بده.
احتمال خوبی هم وجود داره که نرمافزاری که میدن به شما تا مستقر کنید هم پایتونی باشه، فلذا پیادهسازی بخش دواپسی قضیه هم میتونه براتون سادهتر باشه.
و در نهایت؛ شما ممکنه ابزاری نیاز داشته باشید که موجود نباشه. پس خودتون باید پیادهش کنید. با پایتون این قضیه به شدت سریع اتفاق میافته.
یک زبان سیستمی
زبانهای سیستمی، زبانهای برنامهنویسی هستند که برای توسعه ابزارهای سیستمعامل استفاده میشن، برای تعامل با سختافزار پرفرمنس بهتری دارند و در نهایت برای ایجاد ابزارهای زیرساختی مناسبترند. اینجا نمیخوام شما رو به یادگیری اسمبلی تشویق کنم، بلکه ازتون خواهش میکنم همیشه نیمنگاهی به زبانهایی مثل Rust یا Go داشته باشید (و در نظر بگیرید که Go حتی در بکند هم استفاده میشه فلذا یادگیریش خالی از لطف نیست!).
زبانی که سازمان ازش استفاده میکنه
این هم نیاز به گفتن نداره. شما نیاز دارید تا کدبیس رو یاد بگیرید و درکش کنید. حداقل وقتی که قراره دواپسیجات رو روی کد اعمال کنید این مهم خودش رو نشون میده. نگران هم نباشید، معمولا DevOps درگیری به شدت کمتری با کدبیس مستقیم درگیر میشه. پس اگر حس و حال کار تو تیم توسعهدهندهها رو ندارید نگران این مورد هم نباشید :))
خب این دفتر هم به پایان رسوندم. جا داره در انتها، یک نکته خیلی مهم رو عارض بشم خدمت شما. سعی من کلا بر این بود که مطلبم خیلی مرتبط به یک دوران خاص از تاریخ نباشه و مثلا ۳ سال بعد هم قابل استفاده باشه. همچنین، این رو یادتون باشه که این مطالبی که در اینترنت موجودند، معمولا تجربیات شخصی هستند.
شخصا معتقدم تجربیات ارزشمندن، اما یه نکته مهم اینه که تجربهها یکسان نیستند. مثل همین مطلب، مطلبیه که من طی تجربه خودم بهش رسیدم و ممکنه شما مسیر متفاوتی رو در سفرتون به دنیای دواپس طی کرده باشید. به همین خاطر هم کل مطلب رو در یک جمله خلاصه میکنم که «فرمول کلی برای دواپس شدن وجود نداره».
امیدوارم مطلب مفیدی بوده باشه، در نهایت هم سال نوتون پیشاپیش مبارک 🙂
شاید سالها پیش چنین مطلبی رو نوشتم. اما دوست داشتم دوباره هم بنویسم. حقیقتا، این بحث، بحثیه که هیچوقت قدیمی نمیشه و راستش رو بخواید، حتی میتونه بروز بشه. به همین خاطر تصمیم گرفتم اینجا، این تجربه رو منتقل کنم. شاید دو سال دیگه یه مطلب دیگه با همین مضمون اینجا بنویسم.
حالا چرا اینجا؟ در حال حاضر، ابزارهایی مثل ویرگول و مدیوم و dev.to و … اومدند که انتقال تجربه رو هم آسون کردند. اما راستش انتقال تجربه در وبلاگی که سالهای سال اصلیترین محل انتقال تجربه و دانش من بوده، نوشتن مطالبی مثل این، که از جوانب مختلفی اهمیت بالایی دارند اون هم در جای دیگر؛ نوعی خیانت به اینجاست!
خب، هندیبازی بسه 😀 بریم سر اصل مطلب.
حقیقتا نوشتن برنامه در دنیای امروز، مثل قدیم برای «حل مسائل ریاضی» نیست. گرچه ما در هر حال، داریم یه مسالهای رو به شکل مدلهای متعدد ریاضی درمیاریم که فهمشون رو آسون کنیم؛ اما صرفا ریاضیکاری نمیکنیم. پس نیازه که اول از همه یه سری مهارت خاص رو در خودمون تقویت کنیم.
تقویت مهارتهای نرم
شاید مهارتهای نرم یا Soft Skills ، به صورت مستقیم در نوشتن برنامه مهم نباشند. اما از اونجایی که آداب معاشرت، این که چطور صحبت فنی درستی داشته باشیم، بررسی شرایط روانی خودمون و مشتری و …؛ برای کسایی که میخوان از طریق برنامهنویسی و توسعه نرمافزار ارتزاق کنند مهم باشه.
بعضی مهارتهای نرم که در کار برنامهنویسی (بعنوان یک شغل) مهمن :
آداب معاشرت: راستش این رو من نباید توضیح بدم دیگه :D. و خب آداب معاشرت حتی در فرهنگهای مختلف میتونه شکلای مختلفی داشته باشه. پس به نظر میاد لازمه که علاوه بر بلد بودن آداب معاشرت در فرهنگ حاکم بر منطقه خودمون، آداب معاشرت حاکم بر سایر مناطق هم یاد بگیریم. یکی از دلایلش هم شاید این که ممکنه روزی کار ریموت بهمون بخوره.
اخلاق کاری: اخلاق کاری، یه سری چارچوب ویژه خودش رو میتونه داشته باشه. اما خب هرشخصی میتونه چیزی بهش اضافه کنه یا تعریف مشخصتری ازش ارائه کنه. به نظرم لازمه که بعنوان برنامهنویس، اخلاق کاری خودمون رو هم شفاف مشخص کنیم.
روحیه کار تیمی: گفتن نداره، برنامههای بزرگ رو معمولا یک نفر نمینویسه. اگر یک نفر هم بنویسه یحتمل بعدها به تیم محول کنه ادامه توسعهش رو. پس لازمه که روحیه کار تیمی رو هم در خودمون تقویت کنیم.
اینا چیزایی بودن که در زمینه Soft Skill یا همون «مهارت نرم» به نظرم رسیدن. البته فقط اینا هم نیستند. اما بهتره اینها رو تا حد خوبی، تقویت کنیم.
یادگیری زبان انگلیسی
زبان انگلیسی، مدتهای زیادی (شاید از زمانی که امریکاییها در دنیا اسم و رسم دار شدند؛ به طور دقیق از بعد جنگ دوم جهانی) میشه که شده زبان بین المللی. ارتباطات مختلف، تولید محتوا و حتی تولید علم به این زبان انجام میشه.
گرچه شخصا خوشحال میشم اگر جایی مستندات فارسی ببینم، اما ناچاریم برای بهتر شدنمون در دنیای برنامهنویسی، زبان انگلیسی رو هم به خوبی یاد بگیریم. در بخش قبلی، به کار ریموت اشاره کردم. لازم به ذکره که شما لازم دارید برای انجام مصاحبه و ارتباط گرفتن با خارجیها، زبان انگلیسی بلد باشید (با این فرض که تو شرایطشون نگن زبان خودشون هم باید بدونید. مثلا شرکت ترکیهای، ممکنه از شما بخواد تُرکی هم بلد باشید.) که در اون صورت، اگر حال و حوصله کافی دارید، میتونید یک زبان جدید هم شروع کنید.
این دو موردی که در بالا اشاره کردم، خیلی با عنوان مطلب خوانایی نداشتند. راستش بهتره که بریم سراغ این که «چطور یک برنامه بنویسیم؟». حقیقتا این سوال، سوال خوبی نیست. به قول دوستی «سوالیه که مثل زلزلهست». البته اینطورام نیست، اما حقیقتش سوال خوب، سوالیه که هدف سوالکننده درش مشخص باشه.
پس بیایم اینطوری نگاه کنیم. شما شخصی هستید که شنیده برنامهنویسها خوب پول درمیارن. یا شنیده که اگر مهارت برنامهنویسی هم داشته باشه، احتمالا بتونه آینده شغلی خودش رو بیش از حال؛ تضمین کنه. خب، این سوال که «چطور برنامه نویس بشم؟» یا «چطور برنامه بنویسم؟» و … مطمئنا تو ذهن شما میپیچه.
من بعنوان یک برنامهنویس، این سوال رو اصلاح میکنم به این شکل :
چطور یک برنامه تجاری بنویسم و آینده شغلی خودم رو تضمین کنم؟
الان این سوال از نظر من یک سوال خوبه. من میدونم شما چند هدف دارید :
برنامه نویسی
برنامه نویسی با هدف یک برنامه تجاری
تضمین آینده شغلی
(احتمالا) درآمد بالا
خب، حالا میایم سراغ این که شما دقیقا نیاز دارید چه مراحلی رو طی کنید. اینها تجربه شخصی من هستند و ممکنه کامل نباشند. پس لطفا بعد از خوندن این مقاله، خودتون هم دنبال منبع باشید 🙂
شناخت نیاز بازار
«نیاز بازار» چیزیه که احتمالا تو کار زیاد بشنویم. اما بیاید عمیقتر بهش فکر کنید. نیاز بازار دقیقا چیه؟ بازار از دو بخش عرضهکننده و تقاضاکننده تشکیل شده. تقاضاکننده یا مشتری؛ یک انسانه. یک شهروند مثل من و شما. پس شاید اولین و بهترین «نیاز بازار» نیازی باشه که من در حال حاضر دارم. منطقیتر بگم که اون چیزی که نیاز منه، مطمئنا نیاز تعداد زیادی آدم دیگه هم هست. این یعنی اگر این نیاز منحصر به شما بود، ممکن بود اصلا راه حلهای احتمالی به سرتون نزنه.
بعنوان یک تجربه، میتونم بگم وقتایی که با دوستانم صحبتی کردم تازه فهمیدم چه نیازهایی بوده که داشتم، میدونستم دارم ولی راه حل درستی نداشتم. اما صحبتها باعث شده به راه حل برسم و نیازهای دیگران هم رفع کنم حتی. پس این موضوع رو جدی بگیرید.
طراحی راهحل
اول مقاله اشاره کردم که برنامهنویسی علیرغم این که در دنیای امروز حل یه سری مساله ریاضی نیست، اما ما همچنان به مدلسازیهای ریاضیاتی برای طراحی یک برنامه خوب نیاز داریم. در واقع بعد از این که نیازهای بازار رو بسنجیم، نیاز داریم که تا حد امکان اونها رو ساده کنیم و از راهحلهای ذهنیمون، مدل ریاضی بسازیم.
ساخت این مدلهای ریاضی؛ نتیجهش میشه الگوریتمهای ما. نتیجهش میشه دیتابیسهای ما. پس یعنی بعد شناخت بازار، نیاز داریم تا حد زیادی ریاضیکاری کنیم و ببینیم که چی به چیه. تا برسیم به یه ساختاری که بتونه به برنامه تبدیل بشه.
چیدن پلن
این مرحله، خودش حتی شامل واحدهای درسی میشه. نمیدونم عبارت «مهندسی نرمافزار» به گوش شما خورده یا نه؛ اما مهندسی نرمافزار، حرفش دقیقا همینه. یعنی شما وقتی یه چیزی داری و میخوای پیادهش کنی، نیاز به پلن چیدن داری.
خب، فکر کنم اگر بخوام همینطوری توضیح بدم خیلی خیلی پیچیده و مصنوع میشه. بیایم موردی بررسی کنیم که یه پلن خوب چطوریه. در واقع چیزی که در ذیل این مطلب میاد؛ پلنیه که خودم برای یه پروژه چیدم (البته با کمی دخل و تصرف 🙂 )
معرفی اجمالی پروژه
بررسی پروژه های مشابه
طرح مساله
طرح راه حل
طرح ساختارهای دادهای
طرح ساختارهای الگوریتمی
طرح روش پیادهسازی
زبان، فرمورک و …
مدت زمان احتمالی پیاده سازی
امکاناتی که در فازهای مختلف نیاز داریم
پکیجها و ابزارهای کمکی
توسعهپذیر کردن طرح پیاده شده
آمادهسازی برای ارائه
با چیدن چنین پلنی، شما میتونید به خوبی روند توسعه رو پیش ببرید. ابزارهایی مثل ترلو و تسکولو و … هم هستند که بهتون کمک کنن در انجام دادن این مراحل.
پیادهسازی
فکر کنم اینجا دیگه میرسیم به خود خود خود برنامهنویسی. راستش این همه توضیح دادم که به اینجا برسیم. برای پیاده سازی، چی نیاز داریم؟
یه خط اینترنت
یه هدفون
یه پلیلیست از موزیک مورد نیاز برای برنامهنویسی (دیگه این بستگی به سلیقهتون داره 😉 )
مقدار خوبی ماده قندی و قهوه
اما آیا اینا کافین؟ خیر. اینها خوبن. در واقع با اینترنت شما به دنیای بیکران مستندات و اطلاعات متصل هستید. با استفاده از هدفونتون به پلیلیست گوش میدید و خب احتمالا وقتی خسته میشید یه فنجون قهوه داغ خیلی میچسبه. یا مثلا وقتی قندتون میفته، یه شیرینی میخورید.
اما برای پیاده سازی، ما ذهنیت نیاز داریم. راستش ذهنیت ما باید اینطوری باشه :
شناخت ابزار مناسب: ابزارهای زیادی همیشه دم دست ما هستند. اما این به خودمون برمیگرده که از کدوم استفاده کنیم برای انجام کارمون. نمیدونم شما دیدید یا نه. اما با چاقو میوه خوری هم میشه پیچهای ریز رو باز کرد. حالا سوال اینه، آیا کار منطقیه؟ نه! آچارهای ریز هستند که به طرفةالعینی، پیچ رو برای ما باز میکنن. پس مهمه که ابزارها رو بررسی کنید و بهترین رو انتخاب کنید.
استفاده از ابزارهای کنترل سورس: خب، کنترل سورس، به شکل خوب و عجیبی؛ به تسریع روند توسعه کمک میکنه. اما مهمترین بخشش که کمتر کسی بهش توجه میکنه اینه که این ابزارها، روند توسعه ما رو قابل ردگیری میکنند. یعنی چی؟ یعنی میشه فهمید سه روز پیش دقیقا چه حرکتی زدیم و آیا حرکتی که امروز میزنیم، درسته؟ و از این چیزا 🙂
تجدید نظر، هرجا که لازم بود : خب این آخرین مورد این لیسته. راستش دوست دارم با یه مثال جمعش کنم! کرنل لینوکس یه برنامه خیلی بزرگه که قریب به سیساله داره توسعه داده میشه. توسعه اولیه این برنامه تا سال ۲۰۱۲ ادامه داشت. تقریبا بیست سال روی یک مدل پافشاری شده بود. اما میدونید اتفاق بد چی بود؟ این که در سال ۲۰۱۵ توسعهدهندهها فهمیدن که یکم دیگه بگذره عملا هیچ غلطی نمیتونن بکنن (اگر با چنین لحنی میگم به این خاطره که دقیقا به همین وضعیت دچار شده بودند) و خب تصمیم گرفتن تو کل کرنل، تجدید نظر کلی کنن. این یعنی چی؟ یعنی نترسید و هرجا که دیدید دارید گند میزنید، حتی شده برگردید و از اول کار رو انجام بدید، این کار رو بکنید.
این هم موارد مورد نیاز برای پیاده سازی. خب یه نصیحت ریزی میکنم و بعدش هم کلا مطلب رو میبندم 🙂
بلندپروازی نکنید 🙂
رویاپرداز و بلندپرواز بودن خوبه. جف بزوس و بیل گیتس و ایلان ماسک و …، یه بخش بزرگی از موفقیتشون رو مدیون همین بلندپروازیشون هستند. اما بگذریم، بیش از اندازه بلندپرواز بودن هم گاهی کار دست آدم میده.
پس بهتره که «خیلی» بلندپرواز نباشید و حد معقولی هدفگذاری کنید برای پروژهها. اینطوری پروژهها هم به موقع انجام میشن و صدالبته، کیفیت لازم رو خواهند داشت.
حرف آخر
حرف آخری ندارم، راستش مطلب اونقدر طولانیه که اگر تا اینجا اومدید، دمتون گرم! من سعی کردم هرچی که این اواخر برای خودم پیش اومد و با رعایتش کیفیت کارم بالاتر رفت رو بنویسم. فقط الان بعنوان حرف آخر، میتونم بگم که لطفا اگر تجربه مشابهی دارید، در بخش کامنتهای همین پست بنویسید.
مصادف با عید قربان امسال، پروژه API ترجمه فارسی قرآن کریم رو منتشر کردم. این پروژه، پروژه سختی برای من نبود اما چیزای جالبی ازش یاد گرفتم که خب بد نیست در موردش مطلبی بنویسم. اما قبل از اون، لازمه یک چیزی رو توضیح بدم …
چه شد که این پروژه رو شروع کردم؟
حقیقتش شروع این پروژه به این دلیل بود که شدیدا دنبال ابزار مشابهی میگشتم. با این که بعد از این که این پروژه رو دپلوی کردم، یک دوستی در توییتر به من پیشنهاد استفاده از این ابزار رو داد؛ اما بهرحال من ابزار رو توسعه داده بودم و دپلوی هم کرده بودم.
خلاصه که، شروع این پروژه برای من جالب بود. چرا که پروژه به خودی خود سخت نبود اما وسطاش، دقیقا جایی که داشتم فرانتند براش میساختم، چالشی شد. به همین خاطر تصمیم گرفتم که این مطلب رو بنویسم و توضیح بدم که چرا این چالش برای من پیش اومد 🙂
مفهوم تازه : CORS
خب، وقتی که ما بکند و فرانتند پروژه رو از هم جدا میکنیم، در واقع داریم دوتا origin مختلف رو به هم وصل میکنیم. طبق استانداردهای وب؛ اصولا چنین کاری در مرورگرها؛ بخاطر مسائل امنیتی مجاز دونسته نشده. به همین خاطر، ما مفهوم تازهای به اسم «چند ریشهای» یا Cross-Origin رو خواهیم داشت.
حقیقتا وقتی فرانتند رو با جاوااسکریپت مینوشتم؛ دیدم که یک سری ارور بهم میده و توی اون ارورها بهم میگه که بکند من، برای «اشتراک گذاری منابع چندریشهای» یا Cross-Origin Resource Sharing تهیه نشده. دوست داشتم از خود کد جاوااسکریپتم درستش کنم اما چون قرار بود روی هاست همین وبلاگ قرار بگیره و نه سرور مجزایی؛ ترجیح دادم که به جای node.js از وانیلا جی اس استفاده کنم (توضیح : وانیلا اصطلاحا به نرم افزار یا ابزار دست نخورده گفته میشه) و خب راهکاری براش پیدا نکردم (شاید هم چون درست دنبالش نگشتم) ولی از اونجایی که بکند رو با روبی و سیناترا نوشته بودم، براش راهکار پیدا کردم و این راهکار رو در یک ویرگول به اشتراک گذاشتم (لینک).
همین یک کار کوچک، باعث شد که من مفهوم کورز و صد البته نحوه کانفیگ درستش در بکند رو یاد بگیرم، از این جهت هم واقعا خوشحالم چرا که اکثر توسعه دهنده های فرانت، مدام از این قضیه که در بکند این مشکل حل نمیشه، نالانند ((:
چیزی که سالها عقبش انداخته بودم : زرین پال!
تقریبا از وقتی که فهمیدم اینترنت چیه، دنبال راهی برای کسب درآمد ازش بودم. فکر کنم دوم سوم دبیرستان بودم که سایت زرین پال به وجود اومد و اون موقع (چون به سن قانونی نرسیده بودم) نمیتونستم ازش استفاده کنم؛ یا این که باید از کسی میخواستم که قبول کنه به اسمش اکانت باز کنم (مثلا پدر یا مادرم).
از وقتی به سن قانونی رسیدم هم هرروز میخواستم برم و اکانت زرین پال درست کنم تا ازش برای حمایت و فروش و … روی اینترنت استفاده کنم. خلاصه که بالاخره همزمان با ریلیز این پروژه، این اتفاق هم افتاد ((: تازه دقیقتر بخواهیم حساب کنیم، برای این مساله هم مجبور شدم کارت بانکیم رو تمدید کنم و هم برای کارت هوشمند ملی اقدام کنم!
به طور خلاصه، این پروژه پروژه جالبی برام بود. هم چالشاش هم ساختارش و هم اتفاقات پیرامونش. ضمن این که به خود پروژه هم ابتدای مطلب لینک دادم و امیدوارم بخونید و خوشتون بیاد. اگر هم از پروژه قراره استفادهای کنید، حمایت هم بکنید ممنون میشم (:
شاید حدود ۱۰ سال پیش، وقتی به تازگی وارد ۱۲ سالگی شده بودم، شروع به ساخت وبلاگ در یکی از قدیمی ترین سرویس های وبلاگدهی فارسی، یعنی بلاگفا کردم. بلاگفایی که تا همین یکی دو سال پیش، به معنای واقعی از پرترافیک ترین وبسایت های فارسی به شمار میرفت.
دقیقا همان روزها، بلاگفا در صفحه اصلیش، دست کم دو تبلیغ نشان میداد، اخبارش و وبلاگ های بروز شده را لیست میکرد و گهگاه در شکل خبرهای فوری، امکانات حذف یا اضافه شده به سیستمش رو اطلاع رسانی میکرد. به این شکل مثلا فهمیدیم که مدتی blogfa.ir هم در دسترسه، و هر وبلاگی که شما بسازید هم در زیردامنه blogfa.com و هم blogfa.ir قرار میگیره.
البته، آن روزها پرشین بلاگ (قدیمی ترین سیستم بلاگدهی فارسی) و بلاگ اسکای و … هم رونق زیادی داشتند. در واقع، هرکس که میتونست هزینه های یک سرویس بلاگدهی (بخاطر سرور و منابع بالایی که نیاز داره و … ) رو تامین کنه و دانشی از برنامه نویسی وب داشت، یک سیستم بلاگدهی بالا میاورد. اما اونهایی که خیلی مطرح بودند، همین بلاگفا و بلاگ اسکای و پرشین بلاگ بودند.
دوستانی هم بودند که ترجیح میدادند – علیرغم فیلترینگ – از سرویس هایی مثل وردپرس یا بلاگر استفاده کنند، و ما هم با سختی و زحمت هایی که اون زمان برای عبور از سد داشتیم، وبلاگ ها رو میخوندیم و گهگداری هم اینتراکشنی داشتیم.
اما الان چه بلایی سر بلاگ ها اومده؟ امروز بعد از چند سال صفحه اصلی بلاگفا رو باز کردم! دیدم دیگه خبری از اخبار و لیست بلاگهای بروز شده نیست، همهش شده لینک در صفحه اصلی، و صفحه اصلی صرفا شده یه محل برای لاگین کردن وبلاگ نویس ها!
لیست وبلاگ های بروز شده رو باز کردم و یکی دو تا وبلاگ رو خوندم، یکیشون دقیقا همین دهم آبان ویرایش شده بود و یکی هم حدود سه روز پیش. قبلا، این بروزرسانی ها، ساعتی بود. مثلا الان لیست رو میخوندیم، میدیدیم که در ۴ ساعت گذشته دست کم ۱۰ وبلاگ بروزرسانی شدند، اما الان این اختلافها به روز رسیدند!
گرچه، دلیل «مرگ وبلاگ نویسی» مشخصه، دیگه کسی نمیره از بلاگفا سرویس بگیره و بلاگ بنویسه، معمولا یه کانال تلگرامی میزنن و حرفاشون رو اونجا میزنن، دریغ از این که نمیدونن موندگار نیست، حداقل اونقدری که وبلاگ های روی بلاگفا هستند!
وبلاگ شخصی محمدرضا حقیری، برنامهنویس، گیک و یک شخص خوشحال