۹ مشکل آزاردهنده اینترنتی که با افزونه‌ ها برطرف می‌شوند

اینترنت سرزمینی وسیع و بی‌انتهاست که تمام نیازهایتان را در خود گردآوری کرده و با سرعت سرسام‌آوری به رشد خود ادامه می‌دهد. اما همین سرعت زیاد باعث بروز مشکلاتی شده که از تجربه کردنشان لذت نخواهید برد.

اما همیشه برای هر مسئله‌ای یک راه حل نیز وجود دارد. در این مطلب قصد داریم ۹ مشکل آزار دهنده‌ی اینترنتی -که هیچکس با آن‌ها بیگانه نیست- را با استفاده از افزونه‌ها حل کنیم. با ما همراه باشید.

۱) لو رفتن داستان فیلم‌ها و سریال‌ها

مشکل: اینترنت پر شده از مطالبی که فیلم یا سریال مورد علاقه‌تان را لو می‌دهد.

راه حل: برای جلوگیری از نمایش اینگونه مطالب، تنها کاری که باید انجام دهید نصب یک افزونه‌ی ساده به نام Spoiler Protection است. افزونه‌ی اینترنتی یاد شده برای هر دو مرورگر فایرفاکس و کروم در دسترس قرار دارد و با استفاده از آن می‌توانید به صورت دستی نام فیلم و سریال مورد نظر خود را وارد کنید تا دیگر همه‌ی اطلاعات مربوط به آن‌ها محو شود. این موضوع در وبسایت‌های مهمی مثل Google News، فیسبوک، توییتر و چندی دیگر اتفاق خواهد افتاد.

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

دانلود افزونه Spoiler Protection (کروم و فایرفاکس) 

۲) پنجره‌های پاپ‌آپ

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

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

دانلود افزونه Pop-Up Blocker (گوگل کروم)

۳) کوکی‌ها و ترکرها

مشکل: پلتفرم‌ها و وبسایت‌های تبلیغاتی به خاطر زیر نظر گرفتن فعالیت‌های آنلاین کاربران بدنام شده‌اند. دو مورد از کلیدی‌ترین اجزای سازنده‌ی این فرایند ترکر‌ها و کوکی‌ها هستند. هر دو مورد یاد شده بخش‌های کوچکی از اطلاعات محسوب می‌شوند که با زیر نظر گرفتن حساب‌های کاربری شما سعی دارند حتی بدون لاگین شدن هم مطالبی را به نمایش بگذارند که بیشتر به آن‌ها علاقه دارید. موضوعی که به هر ترتیب برای کاربران خوشایند نیست.

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

دانلود افزونه Ultrablock (گوگل کروم)

۴) تصاویر ناخوشایند و نامناسب

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

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

دانلود افزونه vRate (گوگل کروم)

۵) اخبار دروغ

مشکل: حجم بسیاری از اخبار منتشر شده در فضای مجازی دروغ است و به ندرت پیش می‌آید که با مشاهده‌ی یک خبر بتوان به راحتی به آن اطمینان کرد. متاسفانه حصول اطمینان از صحت یک خبر به همین سادگی‌ها نیست.

راه حل: در حالی که هیچ راه حل نهایی و قابل اطمینانی برای این مشکل وجود ندارد، اما می‌توان با استفاده از برخی افزونه‌های اینترنتی تا حدی جلوی حجم وسیع این معضل را گرفت. افزونه‌ی ZenMate SafeSearch که برای مرورگر کروم در دسترس قرار گرفته است به شما این امکان را می‌دهد تا به سرعت متوجه شوید که آیا خبری که مشاهده می‌کنید نمونه‌ی مشابهی در منابع مورد تایید خبری Google News دارد یا نه.

دانلود افزونه ZenMate SafeSearch (گوگل کروم)

۶) فراموشی رمز عبور سایت‌ها

مشکل: صفحات مجازی زیادی در اینترنت وجود دارند که برای هرکدام رمز عبور و نام کاربری متفاوتی داریم. به خاطر سپردن همه‌ی رمز‌های عبور مورد استفاده و مدیریت آن‌ها کار ساده‌ای نیست. خصوصا این روز‌ها که توصیه می‌شود برای هر حساب کاربری در فضای مجازی از رمز عبور متفاوتی استفاده کنید.

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

دانلود افزونه LastPass برای کروم و فایرفاکس

۷) حجم زیاد تصاویر، ویدیوها و مقالات برای چک کردن

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

راه حل: اینجا جاییست که سرویس «ذخیره برای بعد» یا Save for Later کارایی خود را نشان می‌دهد. این سرویس این امکان را فراهم می‌کند تا همه‌ی لینک‌ها را ذخیره سازی کنید تا بعدا و زمانی که وقت کافی داشتید به مشاهده و بررسی آن‌ها بپردازید. در حالی که افزونه‌های زیادی برای این امر در دسترس قرار دارند اما Pocket -که تنها برای کروم عرضه شده- می‌تواند یکی از بهترین گزینه‌ها باشد چرا که با بیشتر پلتفرم‌ها سازگاری دارد. علاوه بر این Pocket با استفاده از هوش مصنوعی و ارزیابی فعالیت‌هایتان می‌تواند لینک‌هایی که احتمالا به آن‌ها بیشتر علاقمند هستید را به شما پیشنهاد دهد.

دانلود افزونه Pocket (گوگل کروم) 

۸) مصرف بالای دیتا و تمام شدن بسته‌ اینترنتی

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

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

۹) جستجو در تاریخچه مرورگر

مشکل: اگر ندانید که به دنبال چه صفحه‌ای می‌گردید، حتی گشت و گذار در بخش تاریخچه‌ی مرورگر هم فایده‌ای ندارد.

راه حل: برای این مشکل استفاده از افزونه‌ی History Search را توصیه می‌کنیم. افزونه‌ای برای مرورگر‌ها که همه‌ی صفحاتی که به بررسی‌شان پرداخته‌اید را وارد لیست می‌کند. راهنمای جستجو به شما این اجازه را می‌دهد تا به طور مستقیم از میان محتوای وبسایت‌های لیست شده به دنبال صفحه‌ی مورد نظرتان بگردید. این افزونه تقریبا با هر نوع وبسایت و مرورگری سازگاری دارد. البته به یاد داشته باشید که اگر می‌خواهید تا حد امکان امنیت و شخصی سازی را در مرورگر‌تان حفظ کنید استفاده از این مرورگر (به خاطر مکانیزم انجام وظیفه‌اش) خیلی مناسب نخواهد بود.

دانلود افزونه History Search (کروم، فایرفاکس، اپرا، اج، سافاری)

نوشته ۹ مشکل آزاردهنده اینترنتی که با افزونه‌ ها برطرف می‌شوند اولین بار در دیجیاتو پدیدار شد.

گردآوری توسط ایده طلایی

آموزش زبان برنامه‌نویسی Rust – قسمت۸: Borrowing

با مالکیّت، مهم‌ترین و خاص‌ترین ویژگی زبان Rust، در جلسه‌ی پیش آشنا شدیم. حالا می‌خواهیم ببینیم که چطور می‌توانیم مقادیر را به توابع ارسال کنیم، بدون اینکه مالکیّت آن‌هارا منتقل کنیم.
در این جلسه می‌خواهیم درمورد referencing صحبت کنیم. یکی از پرکاربردترین بخش‌ها در هر برنامه‌ی کامپیوتری که مشکلات کار با آن بیشترین زحمت و زمان‌را از برنامه‌نویس‌ها می‌گیرید.
مشکلاتی که می‌خواهیم با کمک Rust برای همیشه حلشان کنیم.

مشکل چیست؟

آخرین چیزی که در جلسه‌ی پیش دیدیم کد زیر بود:

fn main() {
    let mut a = String::from("hello");
    a = i_am_owner(a);
    println!("a in main function: {}", a);
}
fn i_am_owner(input: String) -> String {
    println!("The input value is: {}", input);
    return input;
}

دیدیم که با دادن متغیّر a به تابع i_am_owner به عنوان پارامتر ورودی،‌ مالکیّت (Ownership) این متغیّر به آرگومان ورودی تابع منتقل می‌شود و ما دیگر نمی‌توانیم از آن در scopeی که تابع فراخوانی شده است استفاده کنیم.
برای رفع این مشکل، همانطوری که در تکّه کد بالا می‌بینید، در پایان تابع i_am_owner دوباره همان String را خروجی داده‌ایم و درون تابع main، متغیّر a را برابر خروجی این تابع قرار داده‌ایم تا مالکیّت داده را دوباره به آن بازگرداینم.
حالا می‌خواهیم ببینیم که چطوری می‌توانیم بدون انتقال مالکیّت یک مقدار، امکان استفاده از آن‌را به یک تابع بدهیم.

به مالکیّت من دست نزن!

بیایید کد بالا را کمی تغییر بدهیم. کد زیر را با دقّت نگاه کنید:

fn main() {
    let a = String::from("hello");
    i_am_owner(&a);
    println!("a in main function: {}", a);
}
fn i_am_owner(input: &String) {
    println!("The input value is: {}", input);
}

در اینجا ۴ تا تغییر رخ‌داده است:
۱-متغیّر a لازم نیست دیگر تغییر کند. به همین خاطر با پاک‌کردن mut در تعریف آن دوباره این متغیّر را immutable کرده‌ایم. (اگر مفاهیم mutable و immutable را فراموش کرده‌اید، با کلیک روی این نوشته به قسمت مربوط به آن بروید و خیلی سریع این مفاهیم را به‌خاطر بیاورید.)
۲)نوع ورودی تابع i_am_owner را تغییر داده‌ایم. حالا به جای String، پارامتر input از نوع String& است.
۳)هنگام فراخوانی i_am_owner در خط دوم تابع main، دیگر a را برابر خروجی این تابع قرار نداده‌ایم. چون در این کد دیگر مالکیّت مقدار آن به تابع منتقل نشده است که لازم باشد آن‌را پس‌بگیریم.
۴)به جای اینکه a را به عنوان ورودی به تابع بفرستیم، مقدار a& را واردش می‌کنیم. اینطوری دیگر مالکیّت این متغیّر به پارامتر ورودی تابع منتقل نمی‌شود. امّا چرا؟ بیایید دقیق‌تر نگاه‌کنیم.

Reference

وقتی که علامت & پشت یک نوع یا متغیّر قرارمی‌گیرد، یعنی داریم از یک reference صحبت می‌کنیم.
در حقیقت reference به یک مقدار اشاره می‌کند.
یک کارت ویزیت را تصوّر کنید. روی آن کارت، آدرس محل کار کسی که کارت‌را به شما داده است نوشته شده است. این کارت یک رفرنس به آن محل کار است.
ما ورودی تابع i_am_owner را از String به String& تغییر داده‌ایم. پس از حالا به بعد این تابع به جای اینکه کل یک String را به عنوان ورودی بگیرد، یک رفرنس به آن‌را قبول می‌کند. بنابراین مالکیّت String ورودی دیگر به آن منتقل نمی‌شود و رفرنس گرفته شده هم با تمام شدن scope این تابع، بدون هیچ مشکلی پاک می‌شود.
اینطوری مقدار اصلی دست‌نخورده باقی می‌ماند و همچنان متعلّق به متغیّر اصلی است (اگر مفهموم scope در Rust را فراموش کرده‌ای، با کلیک روی این نوشته یک نگاه سریع به آن بیندازید و بعد برگردید).
هروقت که پشت یک مقدار &را بگذاریم، یک رفرنس به آن می‌گیریم. حالا می‌توانیم بدون هیچ مشکلی آن رفرنس را به عنوان ورودی به هر تابعی بدهیم.
پارامتر ورودی تابع، یعنی input، یک رفرنس به متغیّر a است.
اتّفاقی که با دادن رفرنس a به تابع i_am_owner به عنوان ورودی می‌افتد شبیه شکل زیر است (تصویر از این آدرس برداشته شده است):

پارامتر ورودی تابع، یعنی input، یک رفرنس به متغیّر a است. متغیّر a هم، همانطوری که در قسمت قبل دیدیم، خودش یک اشاره‌گر به بخشی از حافظه در heap است.
بنابراین می‌بینید که drop شدن input پس از پایان‌یافتن scope تابع، آسیبی به متغیّر a و مقدارش نمی‌زند.

Dereferencing

متضاد رفرنس دادن، dereferencing نامیده می‌شود. یعنی به مقداری که reference دارد به آن اشاره می‌کند دسترسی پیدا می‌کنیم.
برای دسترسی به مقدار یک رفرنس، باید قبل از آن علامت * را قرار بدهیم. البته همانطوری که دیدید ما اینجا این کار را نکردیم. چون خود rust به خاطر ویژگی Smart pointers می‌تواند تفاوت استفاده از یک رفرنس یا مقدارش‌را تشخیص بدهد.
بعداً مفصلاً به این ویژگی خواهیم پرداخت، فعلاً کافی است بدانید که می‌توانستیم تابع‌را به شکل زیر هم بنویسیم و فعلاً این دوتا با هم تفاوتی ندارند:

fn main() {
    let a = String::from("hello");
    i_am_owner(&a);
    println!("a in main function: {}", a);
}
fn i_am_owner(input: &String) {
    println!("The input value is: {}", *input);
}

خب حالا دیدید که چگونه از رفرنس‌ها برای عدم انتقال مالکیّت استفاده کردیم؟ به این کار در Rust اصطلاحاً borrowing یا همان قرض‌گرفتن می‌گویند.
همانطوری که ما در دنیای واقعی وقتی چیزی می‌خواهیم آن‌را «قرض»می‌گیریم، در اینجا هم وقتی بخش دیگری از برنامه به یک مقدار نیاز دارد، آن مقدار را به او قرض می‌دهیم.
وقتی که ماشینتان‌را به کسی قرض می‌دهید، همچنان شما مالک آن ماشین هستید. اینجا هم مالک آن مقدار همچنان متغیّر اصلی است و دیگران صرفاً به صورت قرضی دارند از آن مقدار استفاده می‌کنند.
خب حالا بیایید ببینیم اگر بخواهیم مقداری که قرض‌گرفته‌ایم را تغییر بدهیم چه اتّفاقی می‌افتد؟

fn main() {
    let a = String::from("hello");
    i_am_owner(&a);
    println!("a in main function: {}", a);
}
fn modifier(reference: &String) {
    reference.push_str(" a new string to push to the old one");
}

اینجا درون تابع modifier می‌خواهیم یک string دیگر را به String اوّلیّه که به عنوان ورودی گرفته‌ایم اضافه کنیم.
وقتی که می‌خواهیم برنامه‌را کامپایل کنیم با ارور زیر مواجه می‌شویم:

error[E0596]: cannot borrow immutable borrowed content `*reference` as mutable
 --> src/main.rs:8:5
  |
۷ | fn modifier(reference: &String) {
  |                        ------- use `&mut String` here to make mutable
۸ |     reference.push_str(" a new string to push to the old one");
  |     ^^^^^^^^^ cannot borrow as mutable

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

ساخت رفرنس mutable

یادتان هست برای اینکه بتوانیم یک متغیّر را تغییر بدهیم چه کار می‌کردیم؟ با افزودن کلمه‌ی کلیدی mut به تعریف آن متغیّر، آن‌را تبدیل به یک مقدار mutable می‌کردیم.
حالا برای اینکه بتوانیم مقداری که یک رفرنس به آن اشاره می‌کند را تغییر بدهیم، احتمالاً باید کاری مشابه انجام بدهیم.
بیایید اوّل ببینیم اگر صرفاً خود متغیّر اوّلیّه را mutable کنیم، آیا امکان تغییردادن داده‌ی آن با استفاده از رفرنسی که از آن داریم وجود دارد یا نه؟
کد زیر را ببینید:

fn main() {
    let mut a = String::from("hello");
    modifier(&a);
    println!("a in main function: {}", a);
}
fn modifier(reference: &String) {
    reference.push_str(" a new string to push to the old one");
}

در این کد صرفاً کلمه‌ی کلیدی mut را به تعریف متغیّر a اضافه‌کرده‌ایم تا این متغیّر mutable شود و بتوانیم مقدار آن‌را تغییر بدهیم.
اگر این کد را کامپایل کنیم، کامپایلر Rust به ما warning و ارور زیر را برمی‌گرداند:

warning: variable does not need to be mutable
 --> src/main.rs:2:9
  |
۲ |     let mut a = String::from("hello");
  |         ----^
  |         |
  |         help: remove this `mut`
  |
  = note: #[warn(unused_mut)] on by default

error[E0596]: cannot borrow immutable borrowed content `*reference` as mutable
 --> src/main.rs:9:5
  |
۷ | fn modifier(reference: &String) {
  |                        ------- use `&mut String` here to make mutable
۸ |
۹ |     reference.push_str(" a new string to push to the old one");
  |     ^^^^^^^^^ cannot borrow as mutable

اوّل از همه برویم سراغ warning. این اخطار می‌گوید که لزومی ندارد که متغیّر a را mutable کنیم. به علاوه به عنوان راهنمایی از ما می‌خواهد که کلمه‌ی mut را از تعریف آن حذف کنیم.
چرا چنین چیزی را از ما می‌خواهد؟ چون هیچ‌کجا مقدار این متغیّر تغییر نکرده است. پس انگار تغییری که ما می‌خواستیم روی رفرنس آن بدهیم مورد قبول Rust نیست.
در اروری که بعد از آن اخطار به ما داده شده است، همان چیزی تکرار شده که در مرحله‌ی قبل دیدیم. یعنی هنوز هم رفرنس ما immutable است، هرچند که خود متغیّر را mutable کردیم.
حالا بیایید یک راه دیگر را امتحان کنیم. این بار به جای اینکه متغیّر را mutable کنیم، رفرنس آن‌را mutable می‌کنیم:

fn main() {
    let a = String::from("hello");
    modifier(&mut a);
    println!("a in main function: {}", a);
}
fn modifier(reference: &mut String) {
    reference.push_str(" a new string to push to the old one");
}

برای اینکه یک رفرنس mutable داشته باشیم، کافی است بعد از علامت & کلمه‌ی mut را اضافه کنیم و بعد از آن type یا نام متغیّر را قرار دهیم.
حالا اگر بخواهیم این برنامه‌را کامپایل کنیم چه اتّفاقی می‌افتد؟

error[E0596]: cannot borrow immutable local variable `a` as mutable
 --> src/main.rs:3:19
  |
۲ |     let a = String::from("hello");
  |         - consider changing this to `mut a`
۳ |     modifier(&mut a);
  |                   ^ cannot borrow mutably

باز هم به ارور خوردیم.
همانطوری که در خط اول ارور گفته شده است، ما نمی‌توانیم یک متغیّر immutable را به عنوان یک متغیّر mutable قرض بدهیم. به همین خاطر کامپایلر از ساخته‌شدن چنین رفرنسی جلوگیری می‌کند.
امّا وسط پیام ارور، کامپایلر برای ما یک راهنمایی قرار داده است. کامپایلر از ما خواسته است که متغیّر a را هم به عنوان یک متغیّر mutable تعریف کنیم. از آنجایی که هیچ پیام خطایی درمورد اضافه بودن رفرنس mutable وجود ندارد، پس احتمالاً نیمی از راه را دست آمده ایم.
بیایید این بار بدون اینکه رفرنس‌را تغییر بدهیم، صرفاً متغیّر a را mutable کنیم:

fn main() {
    let mut     a = String::from("hello");
    modifier(&mut a);
    println!("a in main function: {}", a);
}
fn modifier(reference: &mut String) {
    reference.push_str(" a new string to push to the old one");
}

حالا بیایید این کد که در حقیقت ترکیبی از دو تلاش قبلیمان است را کامپایل و اجرا کنیم:

a in main function: hello a new string to push to the old one

برنامه به خوبی کامپایل شد و بدون مشکل خروجی ای که می‌خواستیم را تولید کرد.
بنابراین برای اینکه بتوانیم از طریق رفرنس‌دهی یک مقدار را تغییر دهیم، باید از رفرنس‌های mutable استفاده کنیم. خلاصه‌ی همه‌ی کارهایی که در این بخش برای ساخت یک رفرنس mutable کردیم می‌شود:
۱)متغیّر اصلی باید mutable باشد.
۲)خود رفرنس هم باید mutable باشد. برای این کار باید بعد از علامت & کلمه‌ی mut را قرار دهیم.
خب حالا که دیدیم چطوری می‌توان یک رفرنس mutable ساخت، ببنیم که چطوری می‌شود به یک مقدار چندین رفرنس داد.

رفرنس‌دهی چندگانه

امیدوارم که عنوان این بخش به اندازه‌ی کافی ترسناک باشد تا حواستان‌را کامل به این مبحث جمع کنید. چیزی که می‌خواهیم ببینیم خیلی ساده است، امّا موقع نوشتن برنامه خیلی‌هارا به دردسر می‌اندازد و زمان می‌برد تا برنامه‌نویس به این مفهموم عادت کند.
بیایید اوّل یک برنامه‌ی خیلی ساده را درنظر بگیریم.
در این برنامه ما می‌خواهیم یک String را همراه با دو متن مختلف نمایش بدهیم. برای هرکدام از این شیوه‌های نمایش هم یک تابع جداگانه داریم.
همانطوری که بالاتر دیدیم، برای این کار باید از رفرنس‌ها استفاده کنیم تا مالکیّت مقدار اوّلیّه منتقل نشود و بتوان آن را به تابع‌های دیگر هم داد.
کد زیر چیزی است که داریم:

fn main() {
    let a = String::from("hello");
    let reference1 = &a;
    let reference2 = &a;
    ali(reference1);
    hossein(reference2);
    println!("a in main function: {}", a);

}

fn ali(original_text: &String) {
    println!("Ali says: {}", original_text);
}

fn hossein(text: &String) {
    println!("{} hossein", text);
}

اگر این برنامه‌را کامپایل و اجرا کنیم، بدون هیچ مشکلی خروجی‌ای که انتظارش را داریم تولید می‌شود:

Ali says: hello
hello hossein
a in main function: hello

حالا فرض کنید که می‌خواهیم یک تابع سومی هم داشته باشیم. قرار است تابع mohammad ورودی‌ای که می‌گیرد را تغییر بدهد و به آخر آن علامت ! را اضافه کند.
برای این کار برنامه‌ی زیر را می‌نویسیم:

fn main() {
    let mut a = String::from("hello");
    let reference1 = &a;
    let reference2 = &a;
    let reference3 = &mut a;
    ali(reference1);
    mohammad(reference3);
    hossein(reference2);
    println!("a in main function: {}", a);
}
fn ali(original_text: &String) {
    println!("Ali says: {}", original_text);
}
fn hossein(text: &String) {
    println!("{} hossein", text);
}
fn mohammad(original_input: &mut String) {
    original_input.push_str("!");
}

خب حالا اگر این برنامه‌را بخواهیم کامپایل کنیم چه اتّفاقی می‌افتد؟

error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable
  --> src/main.rs:14:27
   |
۱۲ |     let reference1 = &a;
   |                       - immutable borrow occurs here
۱۳ |     let reference2 = &a;
۱۴ |     let reference3 = &mut a;
   |                           ^ mutable borrow occurs here
...
۱۹ | }
   | - immutable borrow ends here

error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
  --> src/main.rs:18:40
   |
۱۴ |     let reference3 = &mut a;
   |                           - mutable borrow occurs here
...
۱۸ |     println!("a in main function: {}", a);
   |                                        ^ immutable borrow occurs here
۱۹ | }
   | - mutable borrow ends here

خب با یک ارور بلندبالا مواجه شدیم. بیایید قدم به قدم با ارور جلو برویم و ببینیم که چه اتّفاقی افتاده است.
اوّل ارور این متن نوشته شده است:

cannot borrow `a` as mutable because it is also borrowed as immutable

کامپایلر به ما می‌گوید که نمی‌تواند یک رفرنس mutable به متغیّر a اضافه کند، چون پیش از آن، و البته به صورت همزمان (در یک scope)، رفرنس‌های immutable به این متغیّر ساخته شده است.
در دو بخش بعدی ارور هم کامپایلر به ما نشان می‌دهد که مشکل کجای کد رخ‌داده است:

--> src/main.rs:14:27
   |
۱۲ |     let reference1 = &a;
   |                       - immutable borrow occurs here
۱۳ |     let reference2 = &a;
۱۴ |     let reference3 = &mut a;
   |                           ^ mutable borrow occurs here
...
۱۹ | }
   | - immutable borrow ends here

اینجا کامپایلر به ما نشان می‌دهد که ابتدا یک immutable borrow رخ داده است، یعنی یک رفرنس immutable به متغیّر a ساخته شده است، و بعد یک mutable borrow.

در بخش بعدی هم کامپایلر توضیحات مشابهی می‌دهد.

امّا چرا کامپایلر Rust به ما اجازه‌ی ساخت رفرنس mutable را همراه رفرنس‌های immutable نمی‌دهد؟

محدودیت‌های ساخت رفرنس

زبان Rust به ما اجازه نمی‌دهد که وقتی که داریم از یک رفرنس mutable استفاده می‌کنیم، رفرنس دیگری داشته باشیم.
محدودیت ساخت رفرنس‌های متعدد به یک داده زمانی اجرایی می‌شود که هر۲ شرط زیر برقرار باشند:
۱) دو یا چند اشاره‌گر (رفرنس) به صورت هم‌زمان به یک داده دسترسی داشته باشند.
۲) حدّاقل یکی از این اشاره‌گرها برای نوشتن روی داده استفاده شوند (رفرنس mutable).

امّا چرا این حالت مشکل‌زا است و Rust جلوی اتّفاق افتادنش را می‌گیرد؟

Data Race

وقتی که چند رفرنس immutable به صورت همزمان به یک داده اشاره می‌کنند مشکلی ایجاد نمی‌شود. هرکدام می‌توانند بدون اینکه خللی به کار دیگران وارد کنند داده‌را بخوانند.
امّا وقتی که بیش از یک رفرنس داریم و حدّاقل یکی از آن‌ها mutable است قضیه فرق می‌کند.
فرض کنید که تنها یک اشاره‌گر برای نوشتن داریم و بقیه‌ی رفرنس‌ها immutable هستند. بخش‌هایی از کد که دارند از این رفرنس‌های immutable استفاده می‌کنند، انتظار آن‌را ندارند که داده وسط کارشان تغییر کند. امّا بخشی از برنامه که توانایی نوشتن روی داده را دارد، می‌تواند در حین کار آن‌ها داده‌را تغییر بدهد و کارشان‌را خراب کند.
حالا اگر بیش از ۱ اشاره‌گر نویسنده داشته باشیم قضیه بدتر می‌شود. در این حالت هر رفرنس mutable هم می‌تواند کار بخش‌هایی که صرفاً دارند داده‌را می‌خوانند خراب کند، و هم می‌تواند با قراردادن داده‌های خود مابین داده‌های رفرنس mutable دیگر، داده‌های آن‌را هم خراب کند.
به این حالت اصطلاحاً data race می‌گویند. data race یکی از بدترین باگ‌هایی است که می‌تواند در یک برنامه ایجاد شود و پیداکردن آن بسیار سخت است.
زبان Rust برای اینکه مطمئن شود هرگز data race رخ نمی‌دهد، به شما اصلاً اجازه‌ی این‌را نمی‌دهد که به صورت هم‌زمان یک رفرنس mutable ایجاد کنید و درکنارش رفرنس‌های دیگری هم داشته باشید.
این‌طوری وقتی برنامه با موفّقیّت کامپایل شد، می‌توانید مطمئن باشید که در آن data race وجود ندارد.
علاوه‌بر حالتی که دیدیم، اگر برنامه‌ای بنویسید که مثلاً دوتا mutable reference هم داشته باشد باز با اروری مشابه چیزی که دیدیم مواجه می‌شوید.

معنی هم‌زمان بودن اشاره‌گرها

باید به کلمه‌ی هم‌زمان بودن در اوّلین شرط از شرایط محدودیت‌های ساخت رفرنس خیلی دقّت کنید.
ما زمانی دوتا رفرنس به صورت هم‌زمان داریم که آن‌ها درون یک scope واحد تعریف شده باشند.
مثلاً در همین برنامه‌ای که بالاتر نوشتیم، متغیّرهای reference1، reference2 و reference3 همه در scope تابع main قرار دارند. پس ما به صورت هم‌زمان ۳ تا رفرنس به متغیّر a داریم.
حالا به برنامه‌ی زیر که دقیقا‌ً همان کاری را می‌کند که انتظار داشتیم برنامه‌ی قبلی انجام بدهد نگاه کنید:

fn main() {
    let mut a = String::from("hello");
    ali(&a);
    mohammad(&mut a);
    hossein(&a);
    println!("a in main function: {}", a);
}
fn ali(original_text: &String) {
    println!("Ali says: {}", original_text);
}
fn hossein(text: &String) {
    println!("{} hossein", text);
}
fn mohammad (original_input: &mut String) {
    original_input.push_str("!");
}

اگر این برنامه‌را کامپایل و اجرا کنیم می‌بینیم که دقیقاً همانطوری که انتظارش‌را داشتیم کار می‌کند و خروجی زیر را تولید می‌کند:

Ali says: hello
hello! hossein
a in main function: hello!

امّا چرا این کار کرد و برنامه‌ی قبلی نه؟
پاسخ در همان کلمه‌ی هم‌زمان است. اینجا هم ما ۳ رفرنس مختلف به متغیّر a داریم که یکی از آن‌ها mutable است. امّا این بار این ۳ رفرنس هم‌زمان ایجاد نشده اند. چون هرکدام مربوط به یک scope مختلف هستند.
یعنی رفرنس اوّل متعلّق به scope تابع ali است، دومی متعلّق به scope تابع mohammad و سومی هم متعلّق به تابع hossein.
علاوه بر اینکه این ۳ رفرنس متعلّق به scope های مختلف هستند، این برنامه‌ هم به صورت sequential اجرا می‌شود نه parallel. یعنی هرکدام از این توابع پس از تمام شدن تابع قبلی فراخوانی می‌شوند، نه هم‌زمان با اجرای آن‌ها. پس هرگز اینجا data race ایجاد نمی‌شود.
به همین خاطر است که کامپایلر Rust این بار اجازه‌ی داشتن چندین رفرنس‌را به یک مقدار می‌دهد.
این نکته شمارا از خیلی از اشتباهات آینده مصون می‌کند، البته اگر آن‌را همیشه به خاطر داشته باشید.

رفرنس‌های آویزان!

به عنوان آخرین بخش این آموزش به یکی دیگر از مشکلاتی که در دیگر زبان‌ها هنگام استفاده از رفرنس‌ها ایجاد می‌شود می‌پردازیم.
Dangling reference به رفرنسی گفته می‌شود که به جایی از حافظه اشاره می‌کند که دیگر داده‌ای که انتظارش می‌رود در آنجا نیست.
این اتّفاق زمانی می‌افتد که با آزاد شدن حافظه، آن مکان الان به جای دیگری اختصاص پیدا کرده است یا اینکه دیگر داده‌های قبلی به خاطر free شدن به صورت valid در آن‌جا قرار ندارند.
مثلاً برنامه‌ی ساده‌ی زیر را به زبان c درنظر بگیرید:

#include 
#include 
char* dangle_generator() {
    char * a = (char*) malloc(sizeof(char) * 10);
    a = "hello";
    free(a);
    return a;
}

int main() {
    char* b = dangle_generator();
    printf("%s", b);
    return 0;
}

اگر این برنامه‌را کامپایل کنید هیچ مشکلی رخ نمی‌دهد. حالا سعی کنید برنامه‌ی کامپایل شده را اجرا کنید:

munmap_chunk(): invalid pointer
Aborted (core dumped)

موقع اجرا به مشکل بدی خوردیم. وجود dangling reference ها درون برنامه می‌تواند همه‌چیز را خراب کند، و مثل اکثر باگ‌های مربتط با اشاره‌گرها، پیداکردن مشکل هم کار خیلی سختی است.
حالا بیایید مشابه برنامه‌ی بالا را به زبان Rust بنویسیم:

fn main() {
    let b = dangle_generator();
    println!("a in main function: {}", b);
}
fn dangle_generator() -> &String {
    let a = String::from("hello");
    &a
}

حالا اگر این برنامه‌را کامپایل کنیم با چه چیزی روبه‌رو می‌شویم؟

error[E0106]: missing lifetime specifier
 --> src/main.rs:6:26
  |
۶ | fn dangle_generator() -> &String {
  |                          ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
  = help: consider giving it a 'static lifetime

باز هم مثل همیشه کامپایلر همیشه در صحنه‌ی Rust وارد عمل می‌شود و به شما یک پیام خطای دقیق و کامل می‌دهد.
ابتدای پیام خطا مربوط به ویژگی lifetime زبان Rust می‌شود که فعلاً با آن کاری نداریم و بعداً به صورت مفصّل درموردش صحبت می‌کنیم‌، امّا در بخش help پیغام خطا به ما می‌گوید که چه مشکلی پیش‌آمده است.
متن ارور می‌گوید که در انتهای تابع می‌خواهیم یک مقدار قرض‌گرفته شده را برگردانیم (یعنی یک رفرنس)، امّا مقداری برای قرض‌گرفتن وجود ندارد.
حالا این یعنی چی؟ متغیّر a یک متغیّر محلّی درون تابع dangle_generator است. بنابراین با به انتها رسیدن scope این تابع، این مقدار هم drop می‌شود و دیگر در دسترس نیست. حالا ما داریم تلاش می‌کنیم یک رفرنس به مقداری که از بین خواهد رفت‌را برگردانیم. یعنی می‌خواهیم به چیزی که اصلاً دیگر وجود ندارد رفرنس بدهیم.
اینجا Rust از به وجود آمدن یک dangling reference جلوگیری می‌کند.
پس یکی دیگر از کرامات زبان Rust این است که وقتی برنامه کامپایل شد، می‌توانید مطمئن باشید که هیچ باگی مربوط به dangling reference ها درونش وجود ندارد.
اگر بخواهیم این مشکل به وجود نیاید، کافی است به جای رفرنس، کل مقدار را از تابع خروجی بدهیم. این‌طوری مالکیّت آن مقدار منتقل می‌شود و همه‌چیز به خیر می‌گذرد.

در قسمت بعدی درمورد slicing صحبت می‌کنیم. آخرین ویژگی‌ای که مستقیماً به بحث مالکیّت (Ownership) مربوط می‌شود.
با دانستن آن عملاً اطّلاعات لازم را برای کار با مهم‌ترین ویژگی زبان Rust پیدا می‌کنیم، می‌توانیم به مفاهیم مهم و پرکاربرد دیگر بپردازیم و به نوشتن برنامه‌های کامل به این زبان نزدیک شویم.
اگر سؤالی درمورد این مفهوم داشتید می‌توانید در قسمت نظرات بیان کنید. شاید سؤال شما سؤال دیگران هم باشد. خوشحال می‌شوم که با همدیگر عمیق‌تر یادبگیریم.

این نوشته برای اوّلین بار خیلی وقت پیش در وبلاگ شخصی من منتشر شده است. برای دیدن این مطلب در آنجا، خواندن قسمت‌های جدیدتر و مطالب دیگری که در ویرگول منتشر نمی‌کنم، روی این نوشته کلیک کنید.

اگر قسمت قبلی‌را نخوانده‌ای همین حالا به آنجا برو تا با Ownership، مفهوم بنیادی زبان Rust آشنا بشوی.

اوّلین بار است که این مجموعه‌ی آموزشی‌را می‌بینی؟ با کلیک روی این نوشته به اوّلین قسمت آن برو و شروع به یادگیری کن.

نوشته آموزش زبان برنامه‌نویسی Rust – قسمت۸: Borrowing اولین بار در ویرگول پدیدار شد.

گردآوری توسط ایده طلایی

هک شبکه بانکی شیلی با سوء استفاده از کارمند ساده لوح و اسکایپ

یک تماس اسکایپ و کارمندی ساده لوح موجب شدند هکرهای کره شمالی به شبکه کامپیوتری شرکت Redbanc نفوذ کنند؛ شرکتی که تمامی زیر ساخت های ATM بانک های کشور شیلی را به هم متصل می کند.

اصلی ترین مظنونین این نفوذ گروه لازاروس هستند که با نام Hidden Cobra هم شناخته می شوند. این گروه با دولت پیونگ یانگ نیز در ارتباط هستند. این گروه هکری یکی از خطرناک ترین ها است و در سال های اخیر به موسسه های مالی، بانکی و صرافی های ارزهای مجازی حمله کرده است.

این حمله گروه لازاروس در اواخر سال ۲۰۱۸ میلادی اتفاق افتاده و تنها زمانی توجه عموم را به خود جذب کرد که یکی از سناتورهای شیلی در هفته پیش از شرکت Redbanc در توییتر درخواست کرد که رخنه امنیتی مربوطه را فاش نکند. این شرکت البته یک روز پس از ارسال توییت سناتور به موضوع هک شدن اعتراف کرد ولی جزئیاتی از فرایند نفوذ منتشر نشد.

حمله سایبری

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

گفته شده که شرکت استخدام کننده با گروه لازاروس در ارتباط است و ظاهراً طعمه بزرگی را پیدا کرده. در ادامه از کارمند شرکت Redbanc برای مصاحبه کاری به زبان اسپانیایی و از طریق اسکایپ درخواست شده است. در حین مصاحبه از کارمند درخواست شد که یک فایل با نام ApplicationPDF.exe را دانلود و سپس روی سیستم نصب کند. به کارمند بخت برگشته گفته شد که این برنامه می تواند به فرایند استخدام کمک کند و یک فرم درخواست استاندارد را تولید نماید؛ غافل از اینکه در پس برنامه هدف دیگری پنهان شده بود.

لازاروس

تصویری از برنامه ای که کارمند ساده لوح روی کامپیوتر نصب کرد.

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

اطلاعات جمع آوری شده شامل نام کاربری کامپیوترها ، جزئیات سخت افزارها و سیستم عامل های این شرکت، تنظیمات پراکسی ها، لیستی از تمامی پردازش های جاری، RPC (پروتکلی برای درخواست سرویس از یک برنامه روی کامپیوتر دیگر در شبکه) و فایل های به اشتراک گذاشته شده از طریق SMB (در صورت فعال بودن در دستگاه های میزبان آلوده شده) و وضعیت اتصال سرویس ریموت دسکتاپ بوده اند. این اطلاعات جمع آوری شده می توانستند به هکرها بگویند که کدام کامپیوترها آلوده شده اند تا در آینده بتوانند اسکریپت های مورد نظر خود را به کامپیوترها تزریق کنند.

معضلی که شرکت Redbanc با آن مواجه شد نشان می دهد که چگونه یک کارمند شرکت به سادگی و با کلیک روی یک لینک اشتباه یا اجرای یک فایل مخرب می تواند منجر به فاش شدن اطلاعات حیاتی شرکت ها شود.

نوشته هک شبکه بانکی شیلی با سوء استفاده از کارمند ساده لوح و اسکایپ اولین بار در دیجیاتو پدیدار شد.

گردآوری توسط ایده طلایی

آیا دوره‌های آموزشی بسیار طولانی میتوانند مفید باشند؟

نکاتی درباره‌ی بهترین و موثرترین دوره‌های آموزشی

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

http://aparat.com/v/uxNQ7

۶، ۶۰، یا ۶۰۰ ساعت؟ کدام دوره‌ی آموزشی را انتخاب کنم؟

ممکن است برای شما هم پیش بیاید. میخواهید شروع به یادگیری یک تخصص کنید و با چندین دوره‌ی آموزشی مختلف مواجه میشوید:

  • یک دوره‌ی جمع و جور ۶ ساعته
  • یک دوره ی ۶۰ ساعته
  • یک دوره‌ی ۲ ساله و ۶۰۰ ساعته!

در تصمیم گیری نهایی دچار مشکل شده‌اید و نمیدونید که کدام یک از این دوره‌های آموزشی رو انتخاب کنید و یادگیری رو شروع کنید. در این مقاله میخوایم در خصوص این موضوع صحبت کنیم که بهترین دوره‌های آموزشی چه ویژگی هایی دارند.

سوال‌هایی که باید از خودمان بپرسیم

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

تمام ساعت آموزشی دوره مفید است؟

مهم‌ترین سوالی که وجود دارد این است. آیا تمام آن ۶۰ تا ۶۰۰ ساعت آموزش مفید است؟

به شخصه در دوره‌های چند ده ساعته‌ای شرکت کردم که در آن‌ها مدرس بیش از ۱۰ ساعت فقط منتظر بود که یک فایل دانلود شود، یک نصب یک برنامه اتفاق بیفتد، یا اینکه ۲۰ دقیقه کد را بالا و پایین کند تا باگ کدی که نوشته‌ را پیدا کند.

اصلی‌ترین دلیلی که باعث زیاد شدن ساعات یک دوره‌ی آموزشی میشود، معمولا این است که آن دوره‌ی آموزشی وقت های مرده و تلف شده‌ی بسیاری دارد.

حوصله داریم؟ سنگ بزرگ نشونه‌ی …

سوال بعدی این است، که آیا اصلا ما حوصله‌ و وقت دیدن چند ده ساعت آموزش را داریم یا خیر.

ضرب المثلی وجود دارد که میگوید: «سنگ بزرگ نشانه‌ی نزدن است»

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

میشه توی زمان کمتری همین هارو یاد گرفت؟

سوال مهم بعدی این است. آیا میشود همین مباحث رو توی ۱۰ ساعت یاد گرفت؟

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

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

آیا واقعا به ۶۰ ساعت دانش نیاز داریم؟

نکته‌ای که باید دقت کنیم این است که آیا اصلا به چند ده ساعت آموزش نیاز داریم؟

شاید بخواهیم فقط بصورت مقدماتی با یک موضوع آشنا بشیم یا اینکه یک بخش خاص از یک موضوع رو یاد بگیریم. آیا واقعا نیازه که ۶۰ ساعت آموزش در خصوص اون تهیه کنیم؟

برای مثال ممکنه شما طراحی وب با HTML و CSS رو بلد باشید و فقط بخواید در خصوص طراحی وب واکنش گرا تخصص پیدا کنید. برای این موضوع نیاز نیست ۶۰ ساعت آموزش ببینید و یک آموزش چند ساعته شما را به حد خوبی از تخصص خواهد رساند.

چرا یاد نمیگیرم؟ / چرا پیشرفت نمیکنم؟

اگه نتونیم یک فرایند یادگیری موثر داشته باشیم، اینجوری کلافه میشیم

وقتی که شروع به یادگیری یک تخصص میکنیم و در ابتدا بسیار باانگیزه و خوشحال هستیم و برنامه ریزی میکنیم که در ۶ ماه آینده یکی از متخصص ترین افراد باشیم.

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

مثلا میخوایم PHP یاد بگیریم

فرض کنید که میخواهیم شروع به یادگیری زبان برنامه نویسی PHP کنیم. قبل از هرچیز نیاز داریم به منابع آموزشی. به همین منظور:

  • دوره‌ی مهدی خسروی رو میخریم
  • دوره‌ی خسرو مهدوی رو دانلود میکنیم
  • ۴۰ تا مقاله رو بوک مارک میکنیم
  • توی ۵ تا کانال و گروه تلگرامی عضو میشیم
  • ۱۰ تا کتاب انگلیسی رایگان دانلود میکنیم
  • ۵ تا دوره‌ی انگلیسی لیندا رو از دوستون میگیریم
  • یه کتاب خیلی خوب از نمایشگاه کتاب میخریم
  • یه پلی لیست خوب از یوتیوب پیدا میکنیم، و نهایتا میگیم: خببببب،‌ حالا میخوام یادگیری رو شروع کنم

اما با یک سوال بزرگ مواجه میشیم: کدوم یکی از اینهارو اول شروع کنم؟ کدومشون برای یادگیری بهتره؟

مشکل اصلی: تعدد انتخاب

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

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

وقت ما ارزشمند است

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

همانطور که گفتیم، همیشه باید به دنبال این باشیم که کارهای بیشتری را با کیفیت بیشتر در مدت زمان کمتری انجام دهیم.

قانون ۲۰ ساعت

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

اخیرا کتاب بسیار خوبی که متاسفانه هنوز به فارسی ترجمه نشده را خواندم. کتاب The First 20 Hours از Josh Jaufman، در این کتاب ایده‌های فوق العاده‌ای برای یادگیری سریع مطرح شده است.

آقای کافمن در این کتاب بر این عقیده است که برای یادگیری یک مهارت در حدی که بتوانیم از آن لذت ببریم، ۲۰ ساعت تمرین درست و اصولی کافی است.

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

اکثر مدرسان برنامه نویسی: من اینقدر بلدم که میتونم …

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

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

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

این افراد فقط به یک دلیل این کار را انجام میدهند. به این دلیل که این پیام را منتقل کنند که:

من فردی بسیار حرفه‌ای هستم و در برنامه نویسی و آموزش بهترین میباشم. چون سخت ترین مباحث را بلدم و میتوانم کارهای بسیار عجیب و غریبی با برنامه نویسی انجام دهم. بیایید و از آموزش‌های من استفاده کنید.

اما متاسفانه این افراد، یک اصل بزرگ که انیشتین به خوبی به آن اشاره کرده است را فراموش کرده‌اند:

بهترین مدرس‌های و دوره‌های آموزشی در دنیا چه ویژگی‌هایی دارند؟

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

بسیار ساده

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

ساده بودن را با ارائه‌ی نکات پیش افتاده و ساده اشتباه نگیرید. حرفه‌ای‌ترین مدرس‌ها کسانی هستند که میتوانند سخت‌ترین مفاهیم را بسیار ساده مطرح کنند تا دانشجوها انگیزه ادامه‌ی یادگیری را پیدا کنند.

بسیار کوتاه

کوتاه بودن دوره‌‌های آموزشی یکی دیگر از ویژگی‌هایی است که بین اکثر آموزش‌های حرفه‌ای مشترک است. مخصوصا اگر دوره‌های سایت Lynda را مشاهده کرده باشید، به ندرت دوره‌‌ای طولانی‌تر از ۶-۷ ساعت پیدا میکنید و اکثر دوره‌ها میانگین زمانی ۳ ساعت را دارند.

بسیار خاص

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

  • آموزش HTML5
  • آموزش CSS3
  • آموزش طراحی وبسایت واکنش گرا
  • آموزش جاوا اسکریپت
  • آموزش جی کوئری
  • ترکیب جاوا اسکریپت و جی کوئری برای ساخت وبسایت
  • و…

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

کاملا عملی

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

حواسمون به اینا باشه:

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

صفر تا صد

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

پیشنهاد میکنم مقاله برنامه نویسی چیست؟ را هم حتما مطالعه کنید.

۶۰۰ ساعت آموزش کاربردی

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

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

بهترین و باسوادترین برنامه نویس ایران

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

این موضوع این نکته را دربر دارد که همانطور که یک فوتبالیست حرفه‌ای، شاید نتواند یک مربی حرفه‌ای باشد، یک برنامه نویس حرفه‌ای هم شاید توانایی تدریس حرفه‌ای نداشته باشد.

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

علی دایی نمونه موفق یک فوتبالیست و مربی خوب. اما آیا همه میتوانند مثل او هم در فوتبال بازی کردن درخشان باشند و هم در مربی گری؟ )

تدریس و توانایی انتقال مفاهیم، خود یک تخصص است که متاسفانه بسیاری از مدرسان ما از آن محروم هستند.

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

میانبر، ترفند، راز و…

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

بله، کسب تخصص سخت است و بله، باید برای یادگیری یک تخصص زمان کافی بگذارید. هیچ میانبر و راه کوتاهی وجود ندارد.

حرف آخر 🙂

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

نظر شما دربا‌ره‌ی دوره‌های آموزش ناکارآمد چیست؟ آیا تجربه‌ی ناموفقی در خصوص انتخاب اشتباه یک دوره‌ی آموزشی اشتباه داشته‌اید؟

منبع: یادیفای

نوشته آیا دوره‌های آموزشی بسیار طولانی میتوانند مفید باشند؟ اولین بار در ویرگول پدیدار شد.

گردآوری توسط ایده طلایی