میزبانی کردن صفحات ایستا در گیت‌لب

وبسایت گیت‌لب (لینک) همچون سایر سرویس‌های مشابه، امکان میزبانی کردن پرونده‌ها و صفحات ایستا را به شما می‌دهد. در این پست، قصد داریم بررسی کنیم که چگونه می‌توان یک صفحه ایستا را در گیت‌لب میزبانی کرد.

ساخت مخزن

پس از ساخت حساب کاربری در گیت‌لب، یک مخزن ایجاد کنید. برای مثال، اگر نام کاربری شما username است، پیشنهاد می‌شود که نام مخزن را username.gitlab.io بگذارید. این مخزن، می‌تواند عمومی یا خصوصی باشد (معمول است که مخازن وبسایت یا وبلاگ شخصی خصوصی ساخته شوند. اما اگر نیاز است که روش ساخت، شیوه‌نامه یا جاوااسکریپت خود را با دیگران شریک شوید، بهتر است مخزن را عمومی کنید).

ساخت پرونده‌های مورد نیاز

پس از این که مخزن ساخته شد، پوشه‌ای روی رایانه خود ایجاد کرده و برای مثال نامش را username.gitlab.io بگذارید. سپس داخل پوشه، پرونده‌ها را به این شکل ایجاد کنید :

username.gitlab.io/
├── .gitlab-ci.yml
└── index.html

توجه کنید که ممکن است پرونده‌های شما بیشتر نیز بشوند، برای مثال پوشه‌ای برای شیوه‌نامه‌ها، پوشه‌ای برای جاوااسکریپت و … ممکن است نیاز داشته باشید. فلذا هرچه کنار index.html نیاز است را درون این پوشه قرار دهید.

ویرایش پرونده gitlab-ci

این پرونده، به شما کمک می‌کند که پرونده‌های ایستای خود را، روی گیت‌لب قرار دهید. به عبارتی، کاری که این پرونده انجام می‌دهد «یکپارچه‌سازی مستمر» یا Continuous Integration است. درون این پرونده، باید مراحل «استقرار» یا Deploy پروژه، تعریف شود. برای این منظور، از YAML استفاده می‌شود.

برای استقرار یک صفحه ایستا، تنها کافیست به این شکل، این پرونده را ویرایش کنید :

pages:
 stage: deploy
 scirpt:
  - mkdir .public
  - cp -r * .public
  - mv .public public
 artifacts:
  paths:
   - public
 only:
  - master

در قسمت اول، می‌گوییم که قرار است روی Gitlab pages چیزی ساخته شود. در قسمت stage مشخص می‌کنیم که قرار است پرونده‌های تولید شده، کجا قرار بگیرند.

در قسمت script ابتدا یک پوشه مخفی می‌سازیم و سپس تمام محتوا را به آن منتقل می‌کنیم. علت مخفی بودن این پوشه، این است که دستور cp تلاشی برای کپی کردن خود پوشه نکند.

پس از آن، این پوشه را از حالت مخفی خارج کرده و سپس، در قسمت artifacts مشخص می‌کنیم که مسیر مورد نظر؛ پوشه public است. پس از انجام تمام مراحل کافی است که در بخش only مشخص نماییم فقط از شاخه master پرونده‌ها را خوانده و به پوشه public منتقل کند.

استفاده از تولید‌کنندگان صفحات ایستا

بسیاری از افراد، از «تولیدکنندگان صفحات ایستا» یا Static Generator ها استفاده می‌نمایند. استفاده از این ابزارها، بسیار سریع و به صرفه بوده و معمول است که جای درگیر شدن با طراحی ایستا، از این‌ها استفاده شود. شما می‌توانید از تولیدکنندگان صفحات ایستا مانند jekyll یا hugo روی گیت‌لب استفاده نمایید. در آموزش بعدی، بررسی می‌کنیم که چگونه می‌توان یک بلاگ با جکیل روی گیت‌لب ایجاد و مدیریت کرد.

Share

نگاهی کلی به کد منبع ماستودون

مدتی پیش، خواستم یک نمونه شخصی از ماستودون بسازم. موقع نصب، ارورهای عجیب و غریب دریافت کردم و خب شروع کردم به جست و جو پیرامون این که چرا اینطوریه و خیلی‌ها واضحا بیان کردند که «مشکل از تصویر داکر PostgresSQL بوده و باید روی اون تصویر کمی تغییر داده شه».

حقیقتا من از PGSQL استفاده نکردم و خیلی هم دلم نمیخواست وارد قضیه بشم و روی داکرفایل و داکر کامپوز و …، تغییر ایجاد کنم. به نظرم همون چیزی که خود توسعه‌دهنده پیشنهاد می‌کنه، معمولا بهترین حالتیه که داره با نرم‌افزار کار می‌کنه. اما یه ایده‌ای به سرم زد و اون هم این بود که چی میشه اگر پشتیبانی از MySQL رو به این بزرگوار اضافه کنم؟ نتیجه این شد که تصمیم گرفتم این مطلب رو بنویسم 😀

ماستودون چیه؟

ماستودون یک شبکه اجتماعی از نوع «فدریتد» (انگلیسی : Federated) محسوب میشه. به این شکل که وقتی شما روی سرور خودتون هم اون رو اجرا کنید، می‌تونید باقی سرورها رو ببینید و تعامل کنید.

مدتی میشه که خیلی از دوستانم، ماستودون رو بعنوان شبکه اجتماعی اصلی استفاده می‌کنند و خیلی کم‌تر به توییتر میان. شاید هم کلا توییتر نیان. یکی از دلایلش همینه که شما، صاحب داده‌های خودت هستی. این یک ایده خیلی خوبه که اگر واقعا حریم خصوصی و گردش اطلاعات براتون مهمه، به سمت ماستودون مهاجرت کنید.

نگاه به کد و چندکلمه‌ای صحبت پیرامون اون

خب از اینجا اصل ماجرا شروع میشه. کد ماستودون با فرمورک روبی آن ریلز (لینک) نوشته شده. این برای من خیلی خوشحال‌کننده بود چون خوندن و تغییر دادن اون کد رو آسون می‌کرد. اما این هم باید در نظر گرفت که کد، به شدت بزرگه و حتی برای حرفه‌ای‌های روبی آن ریلز هم خوندنش کمی دشواره. بهرحال می‌شه یکم حوصله به خرج داد و کد بزرگ رو درک کرد. این مشکل کد نیست. بلکه مشکل اون ساختار MVC محسوب میشه که بعد یه مدتی کد رو به شدت بزرگ می‌کنه و پیمایش و رفع اشکالش رو سخت.

در نگاه اول، کد واقعا ایراد خاصی (جز ایرادات مرسوم پروژه‌های مشابه) رو نداره. اما اولین ایراد جایی خودش رو نشون میده که شما چندین کتابخونه سیستمی اضافی نیاز دارید. برای من libicu و libidn و اینا بود. یکم جا خوردم که چرا باید این‌ها نصب باشه؟ اما با کمی تحقیق در موردش، فهمیدم که یک سری از کتابخونه‌های روبی هستند که وابسته به این بزرگوارهان. در واقع، هردوی این‌ها به شکلی برای پردازش متن استفاده شدند و خب این که پردازش متن، از طرف سیستم انجام بشه خیلی منطقیه. این موضوع فقط کمی باعث بزرگتر شدن پروژه شده. اما خوبی‌هاش، به شدت بیشتر از بدی‌هاشه.

مورد بعدی اروری بود که سر PGSQL گرفتم. خب حقیقتا انتظار این یکی رو داشتم. چون PGSQL و کتابخونه‌های سیستمیش، روی سیستم من نصب نیستند (البته شاید بعدها مجبور شم برای اشکال زدایی و کمک به همین ماستودون، نصبش کنم) و خب اروری که گرفتم دقیقا همین رو می‌گفت. وقتی مطمئن شدم که هیچ کتابخونه دیگری مشکلی نداره، دست به کار شدم که PGSQL رو با MySQL عوض کنم.

پروسه تغییر سیستم مدیریت پایگاه داده

خب معمولش اینه که اول، به پروژه می‌گیم کتابخونه‌های لازم رو نصب کنه. نیاز بود روی سیستم libmysqlclient-dev هم نصب کنم و کردم. بعدش در Gemfile، جم‌های مربوط به مدیریت MySQL رو اضافه کردم و جم‌های مربوط به PGSQL رو به دیدگاه تبدیل کردم و رفتم سراغ مراحل ساخت پروژه.

متاسفانه، اینجا کلی ارور گرفتم سر یک سری جم خاص! جم‌هایی که مرتبط با PGSQL هستند و شدیدا Hard Code شدن رو در کد منبع، شاهد بودیم.

قسمتیش رو دستی حذف کردم به امید این که کار کنه. اما موقع اجرای Migration ها، ارورهای جدیدی گرفتم. قسمت بزرگی از Migration ها رو چک کردم و دیدم که یه جاهایی حتی به صورت دستی دستورات PGSQL نوشته شده. حس می‌کردم که دیگه از اینجا جلوتر رفتن، یه جورایی مسخره کردن خودم باشه. حقیقتا بود، چون اصلا آشنا نبودم به این که اینجا چه اتفاقی داره می‌افته و خب بیخیال اضافه کردن پشتیبانی MySQL به این پروژه شدم.

جمع‌بندی

همونطوری که عرض کردم خدمت شما، بزرگترین اشکال این کد اینه که شدیدا وابسته به PGSQL عه. اگر اینقدر هاردکد نمی‌شد، شاید وضعیت طور دیگری بود و می‌شد پشتیبانی پایگاه‌های دیگر رو بهش اضافه کرد. متاسفانه در issue هایی که در پروژه بود هم دیدم که خیلی صریح پیشنهادات مرتبط با MySQL رو رد کردند و امیدم رو به طور کلی به این پروژه برای اضافه کردن این دیتابیس، از دست دادم.

یک توصیه نهایی بخوام به دوستان توسعه‌دهنده کنم اینه که : سعی کنید حداقل در زمینه دیتابیس، وابستگی رو به حداقل خودش برسونید. اول از همه با این فرض که ممکنه هرلحظه شما به هردلیلی بخواید سیستم رو عوض کنید. پس هرقدر وابستگی کمرنگ‌تر باشه، بیشتر به نفع خودتونه.

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

Share

چطور یک برنامه بنویسیم؟!

شاید سالها پیش چنین مطلبی رو نوشتم. اما دوست داشتم دوباره هم بنویسم. حقیقتا، این بحث، بحثیه که هیچوقت قدیمی نمی‌شه و راستش رو بخواید، حتی میتونه بروز بشه. به همین خاطر تصمیم گرفتم اینجا، این تجربه رو منتقل کنم. شاید دو سال دیگه یه مطلب دیگه با همین مضمون اینجا بنویسم.

حالا چرا اینجا؟ در حال حاضر، ابزارهایی مثل ویرگول و مدیوم و dev.to و … اومدند که انتقال تجربه رو هم آسون کردند. اما راستش انتقال تجربه در وبلاگی که سالهای سال اصلی‌ترین محل انتقال تجربه و دانش من بوده، نوشتن مطالبی مثل این، که از جوانب مختلفی اهمیت بالایی دارند اون هم در جای دیگر؛ نوعی خیانت به اینجاست!

خب، هندی‌بازی بسه 😀 بریم سر اصل مطلب.

حقیقتا نوشتن برنامه در دنیای امروز، مثل قدیم برای «حل مسائل ریاضی» نیست. گرچه ما در هر حال، داریم یه مساله‌ای رو به شکل مدلهای متعدد ریاضی درمیاریم که فهمشون رو آسون کنیم؛ اما صرفا ریاضی‌کاری نمی‌کنیم. پس نیازه که اول از همه یه سری مهارت خاص رو در خودمون تقویت کنیم.

تقویت مهارت‌های نرم

شاید مهارت‌های نرم یا Soft Skills ، به صورت مستقیم در نوشتن برنامه مهم نباشند. اما از اونجایی که آداب معاشرت، این که چطور صحبت فنی درستی داشته باشیم، بررسی شرایط روانی خودمون و مشتری و …؛ برای کسایی که میخوان از طریق برنامه‌نویسی و توسعه نرم‌افزار ارتزاق کنند مهم باشه.

بعضی مهارت‌های نرم که در کار برنامه‌نویسی (بعنوان یک شغل) مهمن :

  • آداب معاشرت: راستش این رو من نباید توضیح بدم دیگه :D. و خب آداب معاشرت حتی در فرهنگ‌های مختلف میتونه شکلای مختلفی داشته باشه. پس به نظر میاد لازمه که علاوه بر بلد بودن آداب معاشرت در فرهنگ حاکم بر منطقه خودمون، آداب معاشرت حاکم بر سایر مناطق هم یاد بگیریم. یکی از دلایلش هم شاید این که ممکنه روزی کار ریموت بهمون بخوره.
  • اخلاق کاری: اخلاق کاری، یه سری چارچوب ویژه خودش رو می‌تونه داشته باشه. اما خب هرشخصی میتونه چیزی بهش اضافه کنه یا تعریف مشخص‌تری ازش ارائه کنه. به نظرم لازمه که بعنوان برنامه‌نویس، اخلاق کاری خودمون رو هم شفاف مشخص کنیم.
  • روحیه کار تیمی: گفتن نداره، برنامه‌های بزرگ رو معمولا یک نفر نمی‌نویسه. اگر یک نفر هم بنویسه یحتمل بعدها به تیم محول کنه ادامه توسعه‌ش رو. پس لازمه که روحیه کار تیمی رو هم در خودمون تقویت کنیم.

اینا چیزایی بودن که در زمینه Soft Skill یا همون «مهارت نرم» به نظرم رسیدن. البته فقط اینا هم نیستند. اما بهتره اینها رو تا حد خوبی، تقویت کنیم.

یادگیری زبان انگلیسی

زبان انگلیسی، مدتهای زیادی (شاید از زمانی که امریکایی‌ها در دنیا اسم و رسم دار شدند؛ به طور دقیق از بعد جنگ دوم جهانی) میشه که شده زبان بین المللی. ارتباطات مختلف، تولید محتوا و حتی تولید علم به این زبان انجام میشه.

گرچه شخصا خوشحال میشم اگر جایی مستندات فارسی ببینم، اما ناچاریم برای بهتر شدنمون در دنیای برنامه‌نویسی، زبان انگلیسی رو هم به خوبی یاد بگیریم. در بخش قبلی، به کار ریموت اشاره کردم. لازم به ذکره که شما لازم دارید برای انجام مصاحبه و ارتباط گرفتن با خارجی‌ها، زبان انگلیسی بلد باشید (با این فرض که تو شرایطشون نگن زبان خودشون هم باید بدونید. مثلا شرکت ترکیه‌ای، ممکنه از شما بخواد تُرکی هم بلد باشید.) که در اون صورت، اگر حال و حوصله کافی دارید، میتونید یک زبان جدید هم شروع کنید.

این دو موردی که در بالا اشاره کردم، خیلی با عنوان مطلب خوانایی نداشتند. راستش بهتره که بریم سراغ این که «چطور یک برنامه بنویسیم؟». حقیقتا این سوال، سوال خوبی نیست. به قول دوستی «سوالیه که مثل زلزله‌ست». البته اینطورام نیست، اما حقیقتش سوال خوب، سوالیه که هدف سوال‌کننده درش مشخص باشه.

پس بیایم اینطوری نگاه کنیم. شما شخصی هستید که شنیده برنامه‌نویس‌ها خوب پول درمیارن. یا شنیده که اگر مهارت برنامه‌نویسی هم داشته باشه، احتمالا بتونه آینده شغلی خودش رو بیش از حال؛ تضمین کنه. خب، این سوال که «چطور برنامه نویس بشم؟» یا «چطور برنامه بنویسم؟» و … مطمئنا تو ذهن شما می‌پیچه.

من بعنوان یک برنامه‌نویس، این سوال رو اصلاح می‌کنم به این شکل :

چطور یک برنامه تجاری بنویسم و آینده شغلی خودم رو تضمین کنم؟

الان این سوال از نظر من یک سوال خوبه. من میدونم شما چند هدف دارید :

  • برنامه نویسی
  • برنامه نویسی با هدف یک برنامه تجاری
  • تضمین آینده شغلی
  • (احتمالا) درآمد بالا

خب، حالا میایم سراغ این که شما دقیقا نیاز دارید چه مراحلی رو طی کنید. اینها تجربه شخصی من هستند و ممکنه کامل نباشند. پس لطفا بعد از خوندن این مقاله، خودتون هم دنبال منبع باشید 🙂

شناخت نیاز بازار

«نیاز بازار» چیزیه که احتمالا تو کار زیاد بشنویم. اما بیاید عمیق‌تر بهش فکر کنید. نیاز بازار دقیقا چیه؟ بازار از دو بخش عرضه‌کننده و تقاضاکننده تشکیل شده. تقاضاکننده یا مشتری؛ یک انسانه. یک شهروند مثل من و شما. پس شاید اولین و بهترین «نیاز بازار» نیازی باشه که من در حال حاضر دارم. منطقی‌تر بگم که اون چیزی که نیاز منه، مطمئنا نیاز تعداد زیادی آدم دیگه هم هست. این یعنی اگر این نیاز منحصر به شما بود، ممکن بود اصلا راه حل‌های احتمالی به سرتون نزنه.

بعنوان یک تجربه، میتونم بگم وقتایی که با دوستانم صحبتی کردم تازه فهمیدم چه نیازهایی بوده که داشتم، میدونستم دارم ولی راه حل درستی نداشتم. اما صحبت‌ها باعث شده به راه حل برسم و نیازهای دیگران هم رفع کنم حتی. پس این موضوع رو جدی بگیرید.

طراحی راه‌حل

اول مقاله اشاره کردم که برنامه‌نویسی علیرغم این که در دنیای امروز حل یه سری مساله ریاضی نیست، اما ما همچنان به مدل‌سازی‌های ریاضیاتی برای طراحی یک برنامه خوب نیاز داریم. در واقع بعد از این که نیازهای بازار رو بسنجیم، نیاز داریم که تا حد امکان اونها رو ساده کنیم و از راه‌حل‌های ذهنیمون، مدل ریاضی بسازیم.

ساخت این مدل‌های ریاضی؛ نتیجه‌ش میشه الگوریتم‌های ما. نتیجه‌ش میشه دیتابیس‌های ما. پس یعنی بعد شناخت بازار، نیاز داریم تا حد زیادی ریاضی‌کاری کنیم و ببینیم که چی به چیه. تا برسیم به یه ساختاری که بتونه به برنامه تبدیل بشه.

چیدن پلن

این مرحله، خودش حتی شامل واحد‌های درسی میشه. نمی‌دونم عبارت «مهندسی نرم‌افزار» به گوش شما خورده یا نه؛ اما مهندسی نرم‌افزار، حرفش دقیقا همینه. یعنی شما وقتی یه چیزی داری و میخوای پیاده‌ش کنی، نیاز به پلن چیدن داری.

خب، فکر کنم اگر بخوام همینطوری توضیح بدم خیلی خیلی پیچیده و مصنوع میشه. بیایم موردی بررسی کنیم که یه پلن خوب چطوریه. در واقع چیزی که در ذیل این مطلب میاد؛ پلنیه که خودم برای یه پروژه چیدم (البته با کمی دخل و تصرف 🙂 )

  • معرفی اجمالی پروژه
  • بررسی پروژه های مشابه
  • طرح مساله
  • طرح راه حل
  • طرح ساختارهای داده‌ای
  • طرح ساختارهای الگوریتمی
  • طرح روش پیاده‌سازی
    • زبان، فرمورک و …
    • مدت زمان احتمالی پیاده سازی
    • امکاناتی که در فازهای مختلف نیاز داریم
    • پکیج‌ها و ابزارهای کمکی
  • توسعه‌پذیر کردن طرح پیاده شده
  • آماده‌سازی برای ارائه

با چیدن چنین پلنی، شما میتونید به خوبی روند توسعه رو پیش ببرید. ابزارهایی مثل ترلو و تسکولو و … هم هستند که بهتون کمک کنن در انجام دادن این مراحل.

پیاده‌سازی

فکر کنم اینجا دیگه میرسیم به خود خود خود برنامه‌نویسی. راستش این همه توضیح دادم که به اینجا برسیم. برای پیاده سازی، چی نیاز داریم؟

  • یه خط اینترنت
  • یه هدفون
  • یه پلی‌لیست از موزیک مورد نیاز برای برنامه‌نویسی (دیگه این بستگی به سلیقه‌تون داره 😉 )
  • مقدار خوبی ماده قندی و قهوه

اما آیا اینا کافین؟ خیر. اینها خوبن. در واقع با اینترنت شما به دنیای بی‌کران مستندات و اطلاعات متصل هستید. با استفاده از هدفونتون به پلی‌لیست گوش میدید و خب احتمالا وقتی خسته می‌شید یه فنجون قهوه داغ خیلی می‌چسبه. یا مثلا وقتی قندتون میفته، یه شیرینی میخورید.

اما برای پیاده سازی، ما ذهنیت نیاز داریم. راستش ذهنیت ما باید اینطوری باشه :

  • شناخت ابزار مناسب: ابزارهای زیادی همیشه دم دست ما هستند. اما این به خودمون برمی‌گرده که از کدوم استفاده کنیم برای انجام کارمون. نمی‌دونم شما دیدید یا نه. اما با چاقو میوه خوری هم میشه پیچ‌های ریز رو باز کرد. حالا سوال اینه، آیا کار منطقیه؟ نه! آچارهای ریز هستند که به طرفة‌العینی، پیچ رو برای ما باز میکنن. پس مهمه که ابزارها رو بررسی کنید و بهترین رو انتخاب کنید.
  • استفاده از ابزارهای کنترل سورس: خب، کنترل سورس، به شکل خوب و عجیبی؛ به تسریع روند توسعه کمک می‌کنه. اما مهم‌ترین بخشش که کمتر کسی بهش توجه می‌کنه اینه که این ابزارها، روند توسعه ما رو قابل ردگیری می‌کنند. یعنی چی؟ یعنی میشه فهمید سه روز پیش دقیقا چه حرکتی زدیم و آیا حرکتی که امروز می‌زنیم، درسته؟ و از این چیزا 🙂
  • تجدید نظر، هرجا که لازم بود : خب این آخرین مورد این لیسته. راستش دوست دارم با یه مثال جمعش کنم! کرنل لینوکس یه برنامه خیلی بزرگه که قریب به سی‌ساله داره توسعه داده میشه. توسعه اولیه این برنامه تا سال ۲۰۱۲ ادامه داشت. تقریبا بیست سال روی یک مدل پافشاری شده بود. اما می‌دونید اتفاق بد چی بود؟ این که در سال ۲۰۱۵ توسعه‌دهنده‌ها فهمیدن که یکم دیگه بگذره عملا هیچ غلطی نمی‌تونن بکنن (اگر با چنین لحنی می‌گم به این خاطره که دقیقا به همین وضعیت دچار شده بودند) و خب تصمیم گرفتن تو کل کرنل، تجدید نظر کلی کنن. این یعنی چی؟ یعنی نترسید و هرجا که دیدید دارید گند میزنید، حتی شده برگردید و از اول کار رو انجام بدید، این کار رو بکنید.

این هم موارد مورد نیاز برای پیاده سازی. خب یه نصیحت ریزی می‌کنم و بعدش هم کلا مطلب رو می‌بندم 🙂

بلندپروازی نکنید 🙂

رویاپرداز و بلندپرواز بودن خوبه. جف بزوس و بیل گیتس و ایلان ماسک و …، یه بخش بزرگی از موفقیتشون رو مدیون همین بلندپروازیشون هستند. اما بگذریم، بیش از اندازه بلندپرواز بودن هم گاهی کار دست آدم میده.

پس بهتره که «خیلی» بلندپرواز نباشید و حد معقولی هدفگذاری کنید برای پروژه‌ها. اینطوری پروژه‌ها هم به موقع انجام میشن و صدالبته، کیفیت لازم رو خواهند داشت.

حرف آخر

حرف آخری ندارم، راستش مطلب اونقدر طولانیه که اگر تا اینجا اومدید، دمتون گرم! من سعی کردم هرچی که این اواخر برای خودم پیش اومد و با رعایتش کیفیت کارم بالاتر رفت رو بنویسم. فقط الان بعنوان حرف آخر، میتونم بگم که لطفا اگر تجربه مشابهی دارید، در بخش کامنت‌های همین پست بنویسید.

آزاد و شاد باشید.

Share

ساختن یک API و چیزهایی که از آن یاد گرفتم

مصادف با عید قربان امسال، پروژه API ترجمه فارسی قرآن کریم رو منتشر کردم. این پروژه، پروژه سختی برای من نبود اما چیزای جالبی ازش یاد گرفتم که خب بد نیست در موردش مطلبی بنویسم. اما قبل از اون، لازمه یک چیزی رو توضیح بدم …

چه شد که این پروژه رو شروع کردم؟

حقیقتش شروع این پروژه به این دلیل بود که شدیدا دنبال ابزار مشابهی می‌گشتم. با این که بعد از این که این پروژه رو دپلوی کردم، یک دوستی در توییتر به من پیشنهاد استفاده از این ابزار رو داد؛ اما بهرحال من ابزار رو توسعه داده بودم و دپلوی هم کرده بودم.

خلاصه که، شروع این پروژه برای من جالب بود. چرا که پروژه به خودی خود سخت نبود اما وسطاش، دقیقا جایی که داشتم فرانتند براش میساختم، چالشی شد. به همین خاطر تصمیم گرفتم که این مطلب رو بنویسم و توضیح بدم که چرا این چالش برای من پیش اومد 🙂

مفهوم تازه : CORS

خب، وقتی که ما بکند و فرانتند پروژه رو از هم جدا می‌کنیم، در واقع داریم دوتا origin مختلف رو به هم وصل می‌کنیم. طبق استانداردهای وب؛ اصولا چنین کاری در مرورگرها؛ بخاطر مسائل امنیتی مجاز دونسته نشده. به همین خاطر، ما مفهوم تازه‌ای به اسم «چند ریشه‌ای» یا Cross-Origin رو خواهیم داشت.

حقیقتا وقتی فرانتند رو با جاوااسکریپت می‌نوشتم؛ دیدم که یک سری ارور بهم میده و توی اون ارورها بهم میگه که بکند من، برای «اشتراک گذاری منابع چندریشه‌ای» یا Cross-Origin Resource Sharing تهیه نشده. دوست داشتم از خود کد جاوااسکریپتم درستش کنم اما چون قرار بود روی هاست همین وبلاگ قرار بگیره و نه سرور مجزایی؛ ترجیح دادم که به جای node.js از وانیلا جی اس استفاده کنم (توضیح : وانیلا اصطلاحا به نرم افزار یا ابزار دست نخورده گفته میشه) و خب راهکاری براش پیدا نکردم (شاید هم چون درست دنبالش نگشتم) ولی از اونجایی که بکند رو با روبی و سیناترا نوشته بودم، براش راهکار پیدا کردم و این راهکار رو در یک ویرگول به اشتراک گذاشتم (لینک).

همین یک کار کوچک، باعث شد که من مفهوم کورز و صد البته نحوه کانفیگ درستش در بکند رو یاد بگیرم، از این جهت هم واقعا خوشحالم چرا که اکثر توسعه دهنده های فرانت، مدام از این قضیه که در بکند این مشکل حل نمیشه، نالانند ((:

چیزی که سالها عقبش انداخته بودم : زرین پال!

تقریبا از وقتی که فهمیدم اینترنت چیه، دنبال راهی برای کسب درآمد ازش بودم. فکر کنم دوم سوم دبیرستان بودم که سایت زرین پال به وجود اومد و اون موقع (چون به سن قانونی نرسیده بودم) نمی‌تونستم ازش استفاده کنم؛ یا این که باید از کسی میخواستم که قبول کنه به اسمش اکانت باز کنم (مثلا پدر یا مادرم).

از وقتی به سن قانونی رسیدم هم هرروز میخواستم برم و اکانت زرین پال درست کنم تا ازش برای حمایت و فروش و … روی اینترنت استفاده کنم. خلاصه که بالاخره همزمان با ریلیز این پروژه، این اتفاق هم افتاد ((: تازه دقیقتر بخواهیم حساب کنیم، برای این مساله هم مجبور شدم کارت بانکیم رو تمدید کنم و هم برای کارت هوشمند ملی اقدام کنم!

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

Share

امنیت حسابهای اجتماعی

امروز صبح در تلگرام پیامی برای من فوروارد شد که حاوی یک اسکرین شات از توییت خود شرکت توییتر بود. این اسکرین شات :

همونطوری که می‌بینید، توییتر میگه یک باگ پیدا کردن که باعث شده یک سری پسوردها، بدون این که ماسک بشن، لاگ شدن. یعنی چی؟

فرض کنیم ما یک پسورد میسازیم، پسورد ما موقعی که داریم وارد میکنیم یک چیزی مثل MySecurePassword@123456 عه. این پسورد تقریبا تمام فاکتورهای یک پسورد امن رو داره. ولی اگر به صورت Plain Text بخوایم ذخیره‌ش کنیم این که جای خود، یک میلیون کارکتر دیگر هم داشته باشه احتمال لو رفتنش بسیار بالاست. (داخل پرانتز عرض کنم خدمت آقای علیرضا شیرازی، مدیریت محترم بلاگفا که تا چند سال پیش هم همینطوری پسورد ها رو نگهداری میکرد، جای این که در توییتر و … ملت رو بخاطر مواخذه کردنتون بلاک کنید، پاسخ میدادید که چرا اینطور بود! چون همون موقع هم بسیاری از اسکریپت های مدیریت محتوا پسوردها رو ماسک می‌کردن!).
حالا بخوایم MySecurePassword@123456 رو در دیتابیسی ذخیره کنیم باید چه کنیم؟ باید از «هش» و الگوریتم های مربوطه استفاده کنیم. مثلا الگوریتم MD5 (لینک جهت مطالعه). حالا این عبارت نسبتا سخت رو من با کمک ابزارهایی که دم دستم بود به MD5 هش میکنم و نتیجه میشه :

23b7618b2a23e171e6cda057a9736423

و وقتی من پسورد رو وارد کنم، اسکریپتی که برای لاگین نوشتم، یا API ای که وظیفه لاگین کردن من رو برعهده میگیره، اول پسورد رو هش میکنه بعد در دیتابیسش چک میکنه و اگر هش یکی بود، اجازه میده من به سیستم دسترسی داشته باشم. برای مثال این یک سیستم لاگین بسیار ساده بود که خودم نوشته بودم :

کد   
post '/welcome' do
 begin 
  params[:user][:password] == params[:user][:password_again]
  user = User.create(:username => params[:user][:username], :password => Digest::MD5.hexdigest(params[:user][:password]))
  redirect to("/welcome")
 rescue
  redirect to("/signup_error")
 end
end

و این یعنی ذخیره ایمن پسورد در یک دیتابیس (در اینجا از دیتابیس های مونگو استفاده کردم). و حالا اگر اون قسمتی که مربوط به هش کردن پسورد نمیشد رو، در کد قرار میدادم چه میشد؟ وقتی قرار بود Query بزنم مثلا به یوزر mamad و پسوردش 1125 بود، اینطور بر میگردوند :

کد   
{
"username":"mamad", 
"password":"1125"
}

و مثلا اگر شما قرار بود با API ای که من برای عضوگیری سرویس نوشتم کار کنید (مثلا لاگین کردن به وسیله سرویس من در اپلیکیشن، بازی یا سیستم حضور غیاب و … )، پسوردها رو به سادگی میتونستید ببینید. اما چیزی که الان بر میگرده اینه :

کد   
{"username":"mamad","password":"c21002f464c5fc5bee3b98ced83963b8"}

و خب شما نمیتونید به پسورد دسترسی پیدا کنید، مگر این که ابزار یا دیکشنری مربوط به شکستن این الگوریتم رو داشته باشید. البته معمول هم نیست شما JSON مربوط به اطلاعات کاربران رو برگردونید! چون باز هم دیتای کاربر به خطر میفته.

فکر کنم به قدر کافی در مورد پسورد و نحوه ذخیره سازیش توضیح داده باشم، هدف این بود که مباحثی مربوط به هک شدن و نفوذ به تلگرام هم در این پست مطرح کنم که متاسفانه این پست بیش از چیزی که فکر کردم، طولانی شد. پس در مورد تلگرام در پست جداگانه ای خواهم نوشت 🙂

 

Share

مرگ وبلاگ نویسی، گشت و گذاری در سرویس های وبلاگ فارسی

شاید حدود ۱۰ سال پیش، وقتی به تازگی وارد ۱۲ سالگی شده بودم، شروع به ساخت وبلاگ در یکی از قدیمی ترین سرویس های وبلاگدهی فارسی، یعنی بلاگفا کردم. بلاگفایی که تا همین یکی دو سال پیش، به معنای واقعی از پرترافیک ترین وبسایت های فارسی به شمار میرفت.
دقیقا همان روزها، بلاگفا در صفحه اصلیش، دست کم دو تبلیغ نشان میداد، اخبارش و وبلاگ های بروز شده را لیست می‌کرد و گهگاه در شکل خبرهای فوری، امکانات حذف یا اضافه شده به سیستمش رو اطلاع رسانی می‌کرد. به این شکل مثلا فهمیدیم که مدتی blogfa.ir هم در دسترسه، و هر وبلاگی که شما بسازید هم در زیردامنه blogfa.com و هم blogfa.ir قرار میگیره.
البته، آن روزها پرشین بلاگ (قدیمی ترین سیستم بلاگدهی فارسی) و بلاگ اسکای و … هم رونق زیادی داشتند. در واقع، هرکس که میتونست هزینه های یک سرویس بلاگدهی (بخاطر سرور و منابع بالایی که نیاز داره و … ) رو تامین کنه و دانشی از برنامه نویسی وب داشت، یک سیستم بلاگدهی بالا میاورد. اما اونهایی که خیلی مطرح بودند، همین بلاگفا و بلاگ اسکای و پرشین بلاگ بودند.
دوستانی هم بودند که ترجیح میدادند – علیرغم فیلترینگ – از سرویس هایی مثل وردپرس یا بلاگر استفاده کنند، و ما هم با سختی و زحمت هایی که اون زمان برای عبور از سد داشتیم، وبلاگ ها رو میخوندیم و گهگداری هم اینتراکشنی داشتیم.

اما الان چه بلایی سر بلاگ ها اومده؟ امروز بعد از چند سال صفحه اصلی بلاگفا رو باز کردم! دیدم دیگه خبری از اخبار و لیست بلاگهای بروز شده نیست، همه‌ش شده لینک در صفحه اصلی، و صفحه اصلی صرفا شده یه محل برای لاگین کردن وبلاگ نویس ها!
لیست وبلاگ های بروز شده رو باز کردم و یکی دو تا وبلاگ رو خوندم، یکیشون دقیقا همین دهم آبان ویرایش شده بود و یکی هم حدود سه روز پیش. قبلا، این بروزرسانی ها، ساعتی بود. مثلا الان لیست رو میخوندیم، میدیدیم که در ۴ ساعت گذشته دست کم ۱۰ وبلاگ بروزرسانی شدند، اما الان این اختلافها به روز رسیدند!

گرچه، دلیل «مرگ وبلاگ نویسی» مشخصه، دیگه کسی نمیره از بلاگفا سرویس بگیره و بلاگ بنویسه، معمولا یه کانال تلگرامی میزنن و حرفاشون رو اونجا میزنن، دریغ از این که نمیدونن موندگار نیست، حداقل اونقدری که وبلاگ های روی بلاگفا هستند!

Share

قطعه کد «سلام دنیا» در زبان های مورد علاقه من – سری دوم

توی این مطلب یه تعداد از زبان های مورد علاقم رو معرفی کردم و درونشون قطعه کد سلام دنیا یا همون Hello World رو نوشتم. الان قصد دارم یه تعداد زبان دیگه رو معرفی کنم و این کد رو درون اون زبانها اجرا کنم. این زبانها هم جنبه فان دارن و در عین حال خیلی هم کاربردین.

۱. Arendelle :

این زبان، که سایتش از این آدرس  در دسترسه، ساخته دست دوست خوبم پویا کاری هست (اطلاعات شخصی ایشون توی وبسایت لینک شده). یک زبان برنامه نویسی فان برای کودکان که کلاینت آی او اس و آندروید هم داره.

کد   
'Hello, World'

۲. Apple Swift

زبان سوییفت اپل (نه اون سوییفتی که برای برنامه نویسی موازی و همروند استفاده میشه) به تازگی اوپن سورس شده و حقیقتا نتونستم تحمل کنم و نصبش کردم اون هم روی اوبونتو! و خب کار باهاش خیلی فانه (و به زودی هم یه سری مطلب در موردش میذارم) و البته اگر فرمورک های درست و حسابی تحت لینوکس هم براش ارائه شه، میشه گفت میتونه به یکی از بی رقیب ترین ها تبدیل شه!

کد   
print("Hello, World")

۳. Ada

خب، زبان Ada هم از زبانهایی بود که همیشه میخواستم یاد بگیرم، مدتها پیش در موردش خوندم و جالب ترین نکته این بود که اسم گذاریش از روی اولین برنامه نویس جهان بوده، پس مصمم شدم که حتما یکم باهاش بازی کنم 🙂

کد   
with Ada.Text_IO; use Ada.Text_IO:
procedure Hello is
 begin
  Put_Line("Hello, World");
 end Hello;

۴. Verilog HDL

این زبان هم برای شبیه سازی سخت افزار ازش استفاده میشه. شدیدا کاربردی و باحاله و میتونید کلی پروژه کول پیدا کنید که روی این زبان هستن، مثلا پیاده سازی اوپن سورس از پردازنده های مختلف مثل MIPS, x86, sparc و … .

کد   
module main;
 initial
  begin
   $display("Hello, World");
   $finish;
  end
endmodule

 

خب، این یکی مطلب کوتاه تر از نسخه قبلیش بود! اما یه نکته خیلی ریزی داشت، و اونم اینه که توی این چهارتا زبان میشه چهارتا طیف کاملا متفاوت رو دید. شما هم اگر پیشنهادی دارید دریغ نکنید و بذارید بدونیم 🙂

موفق باشید.

Share

پیاده سازی لیست پیوندی در روبی

لیست پیوندی، یکی از ساختمان داده هایی هست که معمولا توی درس ساختمان داده درس داده میشه (البته در مورد کاربردش در زندگی واقعی چیزی نمیدونم، ممنون میشم بهم بگید) و خب معمولا سر کلاس، توی زبانهایی مثل C یا ++C درس میدنش. اما من داشتم توی نت میگشتم و به این مقاله رسیدم. که این مقاله، توضیح داده چطور میشه توی روبی این ساختمان داده رو پیاده کرد. خب به صورت ساده میریم سراغ پیاده سازی و کم کم پیچیدش میکنیم.

کد   
class Node
 attr_accessor :node, :next
 
 def initialize(node)
  @node = node
 end
end

خب تا اینجا، عملکرد ساده لیست پیوندی رو داریم. همون node و next که next معمولا از جنس اشاره گره. خب ما قاعدتا یک متد دیگری هم نیاز داریم. متدی که نیاز داریم، متدیه که بهمون بگه چیا توی لیستمون ذخیره کردیم. اصولا یکی از مهم ترین متد هاییه که میتونیم توی این کلاس، اضافه کنیم. متد رو به این شکل مینویسیم :

کد   
def self.node_list(node, msg = nil)
    msg ||= ""
    return msg[0..-4] if node.nil?
    node_list(node.next, msg << "#{node.node} -> ")
  end

بسیار خوب! حالا یک متدی مینویسیم که این لیست رو برای ما، برعکس کنه. گرچه چنین متدی نیاز نیست، اما چون توی روبی از این متد برای هش ها و لیست ها (آرایه ها) استفاده شده، بهتره ما هم به لینک لیستمون اضافش کنیم. خب یک متد هم به اسم Reverse ایجاد میکنیم به این شکل:

کد   
def self.reverse(node)
    return node if node.next.nil?
 
    head, swap, node.next = node.next, node, nil
    link = head.next
 
    while link != nil
      head.next = swap
      swap = head
      head = link
      link = link.next
    end
 
    head.next = swap
    head
  end

حالا میتونیم با استفاده از این کلاس، از لیست های پیوندی استفاده کنیم. البته دقت کنید که ما در اینجا در مورد حذف و اضافه کردن Node ها حرفی نزدیم. بلکه صرفا نمایش و معکوس کردن لیست رو بررسی کردیم. امیدوارم کد به کمکتون اومده باشه :).

Share

رویای کریستالی برنامه نویسانه

خب، اول از همه بگم که نمیدونستم چه عنوانی رو باید انتخاب میکردم، و طبق فرمول «احمقانه ترین ایده ممکن» این عنوان رو روی پست گذاشتم. بگذریم، توی این پست میخوام یه پدیده جدید و خیلی خوب رو معرفی کنم. میدونید که من مدت زیادی هست که روبی کار شدم ( و حتی پایگاهی برای توسعه دهندگان روبی ایجاد کردم)  روبی زبان خیلی خوبیه ولی خب قاعدتا نمیشه به نیتیو کد تبدیلش کرد. همونطور که پایتون و … نمیشه نیتیو کد کامپایل کرد. اما با یه چیزی رو به رو شدم که دقیقا خود روبی بود، ولی نیتیو کد میشد. من که بهش سلام کردم، شما هم بهش سلام کنید. زبان برنامه نویسی کریستال یک زبان ruby – inspired هست که کاملا کامپایلری عمل میکنه. سینتکس کاملا سینتکس روبی هست و از این بابت خیالتون راحت باشه که اگر روبی بلدید، یاد گیری این زبان براتون چند دقیقه بیشتر زمان نخواهد برد. اجازه بدید چند مثال رو بررسی کنیم.

برنامه Hello World

کد   
puts "Hello, World"

 

چقدر فرق با روبی حس کردید؟ درسته! هیچ فرقی با روبی نداره. مثالهای بعدی هم هیچ فرقی ندارند.

برنامه شرطی (چک کردن سن قانونی)

کد   
if age >= 18
 puts "Legal"
else 
 puts "Not Legal"
end

 

استفاده از حلقه (برنامه چاپ اعداد ۰ تا ۱۰)

کد   
n = 0
while n <= 10
 puts n
 n += 1
end

 

برنامه شیء گرا (نوشتن کلاس Greeter )

کد   
class Greeter
 def initialize(name)
  @name = name
 end
 
 def say_hi
  puts "Hello, I am #{@name}"
 end
end

 

کد ها رو دیدید؟ خیلی خوب! اگر دوست دارید که این ها رو به نیتیو کد تبدیل کنید همین الان به وبسایت کریستال (که ابتدای پست لینک دادم) مراجعه کنید و شروع به خوندن داکیومنت هاش کنید. مطمئنا کوچکترین تفاوتی در ظاهر با روبی نداره و از این جهت، روبیست ها میتونن به سادگی یادش بگیرند.

Share

نوشتن یک Data Parser ساده

چندین پست قبل، در مورد نوشتن یک زبان برنامه سازی ، مطلبی نوشته بودم. در این مطلب قصد داریم یکی از بخشهای مهم هر زبان یعنی Parser رو بررسی کنیم. اگر یک جست و جوی ساده در اینترنت انجام دهید، حتما خواهید دید که اکثر آموزشهای ساخت زبان برنامه سازی، عملیات parse کردن داده رو با parser generator های موجود مثل bison و … انجام دادن. اما چرا اون رو خودمون ننویسیم؟

برای نوشتن یک Parser ساده تنها نیاز داریم به این که از Regex ها استفاده کنیم. البته، چیزی که در این مطلب نوشته میشه به هیچ وجه شما رو برنامه نویس نمی‌کنه، فقط ممکنه راه رو برای برنامه نویس شدن شما باز کنه.

خب، بریم سر اصل مطلب. میشه گفت تقریبا همه با زبان Lisp و Scheme و سینتکسشون آشنا میشن. این زبان ها سینتکس های جالبی دارن و از همه مهم تر این سینتکس ها نسبتا راحته، و در همان نتایج جست و جو، شما هزاران آموزش پیاده سازی Lisp و Scheme خواهید دید. یک عملیات ساده در Lisp و Scheme به این شکله :

کد   
(+ 1 2)

خب ساختار پرانتز مبنا، باعث میشه کار ما برای بازسازی عملیات های ساده در این زبان ها، بسیار بسیار ساده تر بشه. بیایم اول ببینیم که دیتا پارسر ما باید چه کنه؟

  1. باید این خط از برنامه بهش داده بشه
  2. باید اون رو تجزیه تحلیل کنه و انواع داده ای رو جدا کنه
  3. عملگر رو تشخیص بده
  4. عملیات رو انجام بده و خروجی مناسب رو بگردونه

خب، ما میخوایم نوع داده ایمون عدد باشه، حرف باشه، و بعد از اولین پرانتز، عملگر تعریف شه.

برای این کار، ابتدا دستورات زیر رو در نظر میگیریم :

کد   
( + 1 2 )
( display 'Hello')

خب، الان باید یه تابع کوچولو بنویسیم که نوع داده ای رو بهمون نشون بده. این تابع رو من توی روبی مینویسم و به این شکل در میاد :

کد   
def parse(str)
 str = str.split(' ')
 str[1] = str[1].to_sym
 for i in str
  if /[a-zA-Z]/ === i
   puts "#{i} is STRING"
  elsif /[0-9]/ === i
   puts "#{i} is NUMBER"
  elsif /[:a-z\+\-]/ === i
   puts "#{i} is OPERATOR"
  else
   puts "#{i} is not defined}
  end
end
end

ابتدا، تمام اعضای یک رشته که با فاصله از هم قرار گرفته اند را جدا کردیم (در واقع فاصله ای که در قطعه کد Scheme قرار داده شده، برای Parser ما مهم است) ، سپس با یک دستور شرطی نوع آن را بررسی کردیم. عضو شماره ۱ هر آرایه هم به یک Symbol تبدیل شده است (بعدها سمبل ها را بعنوان اوپراتور ها استفاده خواهیم نمود). بیاید این تابع را اجرا کنیم. آن هم با دو دستور داده شده.

نتیجه به این شکل خواهد بود :

Screenshot from 2015-08-21 19:16:40

همانگونه که شاهدید، پرانتز هارا نمیشناسد، display را هم به عنوان اوپراتور قبول ندارد، حال باید چه کرد؟ برای پرانتز ها باید دو شرط دیگر اضافه کنیم. پس برنامه ما به این شکل خواهد بود :

کد   
def parse(str)
 str = str.split(' ')
 str[1] = str[1].to_sym
 for i in str
  if /[a-zA-Z]/ === i
   puts "#{i} is STRING"
  elsif /[0-9]/ === i
   puts "#{i} is NUMBER"
  elsif /:[a-z\+\-]/ === i
   puts "#{i} is OPERATOR"
  elsif /\(/ === i
   puts "#{i} is LPAREN"
  elsif /\)/ === i 
   puts "#{i} is RPAREN"
  else
   puts "#{i} is not defined
  end
end
end

خب، کد جدید را تست میکنیم وبا تست کد جدید، شما شاهد نتیجه درست خواهید بود.

در این مطلب قصد آن بود که شما ببینید چگونه میتوان فهمید که زبان Lisp ، بررسی میکند که یک داده از چه نوعی است. برای پردازش دستورات درون یک repl هم کافیست تا با یک حلقه بی نهایت، دستوری مشابه دستور زیر بنویسید :

کد   
while true
 print "Lisp > "
 cmd = gets.chomp
 parse(cmd)
end

تبریک، شما یک دیتا پارسر نوشته اید. در مراحل بعدی، سعی میکنم تا توضیح دهم چگونه یک Lisp یا Scheme کوچک درست کنیم.

 

Share