Clean Code في C++: المبادئ والأمثلة التطبيقية

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا الكود النظيف مهم في C++

\n\n

C++ هي لغة قوية ومرنة تسمح بكتابة كود نظامي عالي الكفاءة وحلول تطبيقية معقدة. لكن هذه المرونة غالبًا ما تؤدي إلى الفوضى: الدوال المثقلة، التحويلات الضمنية، إدارة الذاكرة اليدوية، والماكرو يمكن أن تحول المشروع إلى "مستنقع" في غضون أشهر. مفهوم Clean Code (الكود النظيف)، الذي شاعه روبرت مارتن، ينطبق على C++ بشكل كامل، ولكن مع مراعاة خصوصية اللغة.

\n\n

في هذه المقالة، سنستعرض المبادئ الأساسية للكود النظيف في C++ ونوضح تطبيقها بأمثلة واقعية. ستتعلم كيفية كتابة كود يسهل قراءته واختباره وصيانته.

\n\n

1. التسمية والهيكلة: أساس قابلية القراءة

\n\n

1.1. أسماء ذات معنى للمتغيرات والدوال

\n\n

القاعدة الأولى للكود النظيف هي أن الاسم يجب أن يكشف عن القصد. في C++، هذا مهم بشكل خاص بسبب وجود التحميل الزائد والقوالب.

\n\n

مثال سيء:

\n\n
int d; // elapsed time in days\nvoid proc(int a, int b); // ما هما a و b؟
\n\n

مثال جيد:

\n\n
int elapsedTimeInDays;\nvoid processData(const std::vector<int>& inputData, int maxIterations);
\n\n

1.2. الفئات ومساحات الأسماء

\n\n

استخدم مساحات الأسماء للتجميع المنطقي. تجنب المتغيرات العامة - فهي نمط سيء.

\n\n
namespace network {\n    class TcpConnection {\n    public:\n        void connect(const std::string& host, int port);\n        void send(const std::vector<char>& data);\n    private:\n        int socket_;\n    };\n} // namespace network
\n\n

2. الدوال: صغيرة وذات مسؤولية واحدة

\n\n

2.1. مبدأ المسؤولية الواحدة (SRP)

\n\n

يجب أن تقوم الدالة بشيء واحد فقط. إذا كانت الدالة تقوم بأكثر من إجراء واحد - قم بتقسيمها.

\n\n

مثال سيء:

\n\n
void processOrder(Order& order) {\n    // التحقق\n    if (order.total < 0) throw std::invalid_argument("Negative total");\n    // الحفظ في قاعدة البيانات\n    database.save(order);\n    // إرسال البريد الإلكتروني\n    emailService.send(order.customerEmail, "Order confirmed");\n}
\n\n

مثال جيد:

\n\n
bool validateOrder(const Order& order);\nvoid saveOrderToDatabase(const Order& order);\nvoid sendConfirmationEmail(const Order& order);\n\nvoid processOrder(Order& order) {\n    if (!validateOrder(order)) return;\n    saveOrderToDatabase(order);\n    sendConfirmationEmail(order);\n}
\n\n

2.2. تجنب الآثار الجانبية

\n\n

يجب ألا تقوم الدالة بتغيير الحالة العامة دون ضرورة واضحة. استخدم المراجع الثابتة وأعد القيم بدلاً من تعديل الوسائط.

\n\n
// سيء: يعدل المتجه المدخل\nvoid addPrefix(std::vector<std::string>& words, const std::string& prefix) {\n    for (auto& word : words) {\n        word = prefix + word;\n    }\n}\n\n// جيد: يعيد متجهًا جديدًا\nstd::vector<std::string> addPrefix(const std::vector<std::string>& words, const std::string& prefix) {\n    std::vector<std::string> result;\n    result.reserve(words.size());\n    for (const auto& word : words) {\n        result.push_back(prefix + word);\n    }\n    return result;\n}
\n\n

3. إدارة الذاكرة و RAII

\n\n

3.1. استخدم المؤشرات الذكية

\n\n

في C++ الحديثة (C++11 وما بعده)، تعتبر إدارة الذاكرة اليدوية عبر new/delete قديمة. استخدم std::unique_ptr و std::shared_ptr.

\n\n
// سيء: تسرب الذاكرة ممكن\nvoid process() {\n    Resource* res = new Resource();\n    // ... إذا حدث استثناء هنا، ستتسرب الذاكرة\n    delete res;\n}\n\n// جيد: تحرير تلقائي\nvoid process() {\n    a                

المدونات

توصيات الكتب