درسهایی از 2 سال بررسی روابط عمومی: 9 اشتباه برنامه نویسی

سلام به همه! اگر یک پیروان معمولی هستید ، ممکن است کمی درباره من بدانید. اما اگر اینطور نیست ، بگذارید سریع خودم را معرفی کنم: من یک توسعه دهنده تمام پشته هستم و دو سال گذشته در یک استارتاپ کار کرده ام. در این مدت ، من درخواست های بی شماری را بررسی کرده ام و متوجه اشتباهات کد نویسی مکرر شده ام. امروز ، من هیجان زده ام که این بینش ها را با شما به اشتراک بگذارم. این بر روی Node.js. متمرکز خواهد شد.
1. متغیرهای ثابت: چه موقع از پرونده ثابت جهانی جلوگیری کنید
یک اشتباه رایج که من می بینم تعریف ثابت در یک پرونده جهانی است که فقط در یک عملکرد از آنها استفاده می شود. این امر دامنه جهانی را آلوده می کند و متغیر را به طور غیر ضروری در حافظه نگه می دارد.
چرا این یک مشکل است
تعیین ثابت در یک فایل جداگانه برای استفاده فقط در یک عملکرد معنی ندارد و پیچیدگی غیر ضروری را به پایگاه کد اضافه می کند. مسئله اصلی اینجاست آلاینده فضای نام جهانیبشر هنگامی که شما یک ثابت در سطح جهان را تعریف می کنید ، در کل برنامه در دسترس است و در حافظه باقی می ماند ، حتی اگر در خارج از محدوده بسیار محدود مورد نیاز نباشد.
راه حل
ثابت را تعریف کنید محلی در عملکردی که در آن مورد نیاز است. اگر در چندین پرونده استفاده می شود ، آنها را به یک فایل جداگانه منتقل کنید.
کد بد:
// constants.js
export const MAX_RETRIES = 3;
// In another file
import { MAX_RETRIES } from './constants';
function fetchData() {
if (retries > MAX_RETRIES) {
// handle error
}
}
کد بهتر:
function fetchData() {
const MAX_RETRIES = 3; // Defined locally
if (retries > MAX_RETRIES) {
// handle error
}
}
این باعث می شود کد شما تمیزتر و کارآمدتر شود.
2. متغیرهای محیط: از واسطه پرش کنید
در node.js ، ما به طور معمول اسرار را در متغیرهای محیط ذخیره می کنیم و به آنها دسترسی پیدا می کنیم process.env.KEY_NAME
بشر با این حال ، یک اشتباه رایج که من دیده ام اختصاص مقدار یک متغیر محیط به یک ثابت و سپس دسترسی به آن از طریق آن ثابت است.
چرا این یک مشکل است
این باعث می شود غیرمستقیم غیر ضروری اضافه شود. اگر فقط قصد دسترسی دارید process.env.KEY_NAME
به هر حال ، نیازی به اختصاص آن به ثابت نیست. این کد را بهبود نمی بخشد و فقط خواندن و نگهداری آن را سخت تر می کند.
راه حل
به متغیرهای محیط دسترسی پیدا کنید مستقیما از طریق process.env.KEY_NAME
به جای اختصاص آنها به یک ثابت ، مگر اینکه مقدار لازم باشد چندین بار در یک دامنه بزرگ استفاده شود.
کد بد:
const DB_HOST = process.env.DB_HOST;
const DB_PORT = process.env.DB_PORT;
function connect() {
console.log(DB_HOST, DB_PORT);
}
کد بهتر:
function connect() {
console.log(process.env.DB_HOST, process.env.DB_PORT);
}
این باعث تمیز کردن کد می شود و تکالیف غیر ضروری را کاهش می دهد.
3. سیاهههای مربوط به تورفتگی: اشکال زدایی خود را تمیز کنید
من اغلب به سیاهههای مربوط می شوم که برای اشکال زدایی مفید هستند اما فاقد تورفتگی یا زمینه مناسب هستند. سیاهههای مربوط بدون ساختار ، استخراج بینش معنی دار را سخت تر می کنند.
چرا این یک مشکل است
سیاهههای مربوط به زمینه یا قالب بندی مناسب می توانند سیاهههای مربوط به تولید را درهم و برهم کنند و جستجو و تجزیه و تحلیل آنها را دشوار می کند. بدون ساختار مداوم ، یافتن اطلاعات مربوطه به کابوس تبدیل می شود.
راه حل
ورود به سیستم فقط در صورت لزوم و اطمینان حاصل کنید که سیاههها هستند ساخت یافته با زمینه مربوطه از قالب بندی مداوم (به عنوان مثال ، جدول زمانی ، سطح ورود به سیستم) استفاده کنید تا گزارش ها خواندن و جستجو را آسان تر کنید.
کد بد:
function fetchData(username){
try {
//some api call
} catch(err){
console.log("error",err);
}
}
کد بهتر:
function fetchData(username){
try {
//some api call
} catch(err){
console.error(`[fetchData] [ERROR] Error in fetching data for username ${username}`,err);
}
}
5. رسیدگی به تماس های مستقل Async: وعده های موازی را اجرا کنید
بگذارید بگوییم که ما عملکردی داریم که کار را از دو کد سرویس به دست می آورد مانند زیر در NodeJS به نظر می رسد
const serviceOneData = await fetch()
const serviceTwoData = await fetch()
آیا می توانید مشکل را در کد پیدا کنید؟
آیا می توانید مسئله را مشاهده کنید؟
مشکل اینجاست که ما منتظر هر یک هستیم fetch()
برای تکمیل تماس بگیرید متوالی، به این معنی که تماس دوم تا زمان پایان کار شروع نمی شود. این ناکارآمد است ، به خصوص اگر این تماس ها مستقل از یکدیگر باشند.
چرا این یک مشکل است
اجرای تماس های ناهمزمان به دنباله به این معنی است که شما هستید مسدود کننده اعدام و روند کلی بیش از حد لازم طول می کشد. از آنجا که این دو تماس به یکدیگر بستگی ندارند ، هیچ دلیلی وجود ندارد که قبل از شروع کار دیگر منتظر بمانید.
راه حل
برای بهبود کارآیی ، می توانیم هر دو تماس ناهمزمان را اجرا کنیم به طور موازی با استفاده از Promise.all()
بشر این اجازه می دهد تا هر دو درخواست به طور همزمان پردازش شوند و زمان انتظار کلی را کاهش دهند.
const [serviceOneData, serviceTwoData] = await Promise.all([
fetch('serviceOne'),
fetch('serviceTwo')
]);
6. اعتماد به جبهه
هنگام انجام عملیات CRUD ، Frontend معمولاً هنگام ایجاد یا به روزرسانی یک سند ، داده ها را به عنوان یک شی ارسال می کند. در باطن ، داده ها پخش شده و مستقیماً برای ایجاد یا به روزرسانی سند استفاده می شوند. این روش معمولاً برای ایجاد و به روزرسانی استفاده می شود.
چرا این یک مشکل است
این رویکرد می تواند خطرناک باشد زیرا کاربران به طور بالقوه می توانند جلوی آن را دستکاری کرده و داده هایی را که نباید به روز شوند ارسال کنند ، یا زمینه هایی را که قصد تغییر ندارند ، به روز کنند.
به عنوان مثال ، مجموعه ای را با یک زمینه تصور کنید ownedBy
این صاحب یک سند را مشخص می کند. اگر این قسمت پس از ایجاد سند به روز نشده باشد ، اما کاربر با استفاده از اپراتور پخش ، آن را در یک درخواست به روزرسانی ارسال می کند (...req.body
) می تواند ناخواسته ownedBy
میدان
db.findOneAndUpdate({}, {...req.body})
راه حل
برای جلوگیری از این مسئله ، کورکورانه به جبهه اعتماد نکنید. دو روش اصلی برای حل این مشکل وجود دارد:
-
اعتبار سنجی دقیق: اعتبار سنجی دقیق را اضافه کنید تا بررسی کنید که آیا کلیدهای به روز شده مجاز هستند یا خیر. اگر هر قسمت غیر منتظره در بار جلوی بار یافت می شود ، درخواست را رد کنید.
-
از استفاده از اپراتور گسترش خودداری کنید: به جای استفاده از اپراتور گسترش برای به روزرسانی اسناد ، شیء را ویران کنید تا اطمینان حاصل شود که فقط قسمتهای مجاز در عمل به روزرسانی گنجانده شده اند.
7. نظرات در حال حاضر
آیا تا به حال با خواندن آن با کدی روبرو شده اید که درک آن دشوار است؟ ممکن است مبهم به نظر برسد ، یا منطق تجارت در پشت آن ممکن است مشخص باشد ، و شما را در مورد اینکه چرا به روشی خاص نوشته شده است ، مطمئن نیستید. این امر می تواند به ویژه هنگامی که می خواهید کد را حفظ یا گسترش دهید ، چالش برانگیز باشد ، زیرا قصد اصلی بدون توضیحات مناسب از بین می رود.
هنگامی که کد فاقد نظرات است ، توسعه دهندگان آینده (از جمله خود آینده شما) ممکن است وقت خود را برای کشف استدلال در مورد منطق خاص هدر دهند ، که می تواند توسعه را کند کند و خطر معرفی اشکالات را افزایش دهد.
به عملکرد JavaScript زیر نگاهی بیندازید:
function getMatchingQuery(initialMatchQuery, value) {
const durationMap = {
lessThanThirtySeconds: { $gt: 0, $lte: 29 },
betweenThirtySecondsAndOneMinute: { $gt: 29, $lte: 60 },
betweenOneAndFive: { $gt: 60, $lte: 300 },
betweenFiveAndTen: { $gt: 300, $lte: 600 },
greaterThanTen: { $gt: 600 },
};
if (value && Array.isArray(value)) {
initialMatchQuery = {
...initialMatchQuery,
duration: { $gt: 0 },
};
if (value.length < 5) {
delete initialMatchQuery.duration;
value.sort((a, b) => a.key - b.key);
const mergedIntervals = [];
let currentInterval = { ...durationMap[value[0].id] };
for (let i = 1; i < value.length; i++) {
const range = durationMap[value[i].id];
if (currentInterval.$lte && currentInterval.$lte === range.$gt) {
if (range.$lte) {
currentInterval.$lte = range.$lte;
} else {
delete currentInterval.$lte;
}
} else {
mergedIntervals.push(currentInterval);
currentInterval = { ...range };
}
}
}
}
return initialMatchQuery;
}
در نگاه اول ، درک این عملکرد ساده نیست. بدون هیچ گونه اظهار نظر ، تعیین هدف و منطق آن دشوار است. تصور کنید که یک توسعه دهنده در تلاش برای اشکال زدایی یا اصلاح این عملکرد بدون هیچ زمینه ای است – این می تواند منجر به ناامیدی ، هدر رفتن زمان و به طور بالقوه عملکرد عملکرد شود.
یک روش ساده و در عین حال مؤثر برای حفظ این کد با اضافه کردن نظرات معنی دار است. نظرات به عنوان یک راهنما عمل می کنند ، توضیح می دهند که چرا تصمیمات خاصی گرفته شده است و کار با دیگران را برای دیگران (و خود آینده) آسان تر می کند.
8. رسیدگی به عملکرد اتمی در سطح کد
هنگام اجرای منطقی که اعتبار کاربر را تغییر می دهد ، معمولاً کاهش تعادل اعتبار هر بار که یک عمل خاص انجام می شود ، همانطور که در قطعه کد زیر نشان داده شده است:
const userCredit = user.credit
db.user.update(
{ username: user.username },
{ $set: { credit: userCredit - 5 } }
);
چرا این یک مشکل است
این رویکرد می تواند منجر به مسائلی شود که همان کاربر به طور همزمان به حساب خود از چندین دستگاه دسترسی پیدا کند. در چنین مواردی ، هر دو دستگاه می توانند کسر اعتباری را آغاز کنند ، و از آنجا که کد قبل از به روزرسانی مانده اعتبار را می خواند ، هر دو مورد ممکن است ارزش اولیه یکسان را دریافت کنند (برای مثال ، 10 اعتبار). در نتیجه ، هر دو دستگاه سعی می کنند اعتبار را به 5 کاهش دهند و به جای 0 مورد انتظار تنها 5 اعتبار باقی می مانند.
راه حل
برای جلوگیری از این مسئله ، از اپراتورهای اتمی پایگاه داده استفاده کنید. با استفاده از $inc
اپراتور ، کسر اعتبار به یک عملیات اتمی تبدیل می شود که تضمین می کند که به روزرسانی به درستی اعمال می شود ، حتی در سناریوهای همزمان:
db.user.update( { username: user.username }, { $inc: { credit: -5 } }
این روش تضمین می کند که اعتبار با 5 اعتبار به درستی کاهش می یابد ، صرف نظر از اینکه چه تعداد دستگاه یا فرآیند سعی در به روزرسانی اعتبار کاربر در همان زمان دارند. این امر قوام و یکپارچگی در پایگاه داده ، حتی با بار همزمان را تضمین می کند.
اگر مایل به کسب اطلاعات بیشتر در مورد خواص اسید در DB هستید
9. پیشینه کد خود را کنترل کنید:
من متوجه شده ام که بسیاری از توسعه دهندگان با افزودن حفاظت بیش از حد ، کد خود را بیش از حد ترکیب می کنند ، که اغلب بر خلاف اصل اساسی است که کد باید مطابق آنچه در نظر گرفته شده است کار کند. سرنگونی و امنیت بیش از حد کد می تواند منجر به پیچیدگی و ناکارآمدی غیر ضروری شود.
بگذارید با یک مثال توضیح دهم:
try {
// Business logic here
db.user.update({ username: username }, { $set: { credit: 100 } });
} catch (err) {
console.log("Failed to update", err);
}
در این کد ، به روزرسانی پایگاه داده برای تنظیم اعتبار کاربر 100 انجام می شود. بیشتر اوقات ، بانک اطلاعاتی عملیاتی است ، بنابراین احتمال خرابی حداقل است. بنابراین ، در این حالت ، اغلب نیازی به a نیست try-catch
اگر یک کنترل کننده خطای جهانی وجود داشته باشد ، بلوک کنید.
شما باید از try-catch
فقط در صورت نیاز به انجام منطق تجاری خاص در پاسخ به خرابی یا در صورت نیاز به خطا نیاز به کار خاص دارید. در غیر این صورت ، یک کنترل کننده خطای جهانی کافی است.
try{
// Business logic here
db.user.update({ username: username }, { $set: { credit: 100 } });
} catch (err){
//you going to do the business logic in response to a failure of db operation
}
ضد الگوی دیگری که من مشاهده کردم پرتاب خطایی پس از گرفتن آن است ، مانند این:
try {
// some code
} catch (err) {
console.log("err", err);
throw new Error(err.message);
}
در این حالت ، try-catch
بلوک زائد است. شما به سادگی می توانید حذف کنید try-catch
و اجازه دهید خطا به طور طبیعی پخش شود ، زیرا خطا در حال ورود به سیستم است و سپس دوباره پرتاب می شود ، که هیچ مقداری اضافه نمی کند.
باز برای بازخورد
رشد از یادگیری مداوم ناشی می شود و باز ماندن در بازخورد برای پیشرفت مهم است. اگر دیدگاه متفاوتی دارید ، احساس راحتی کنید – من از بحث های متفکرانه قدردانی می کنم. کدگذاری را ادامه دهید ، رشد خود را ادامه دهید!
سرانجام ، اگر مقاله مفید بود ، لطفاً دست و پنجه نرم کنید ، متشکرم!