مقدمة: لماذا الكود النظيف مهم في C++
\n\nC++ هي لغة قوية ومرنة تسمح بكتابة كود نظامي عالي الكفاءة وحلول تطبيقية معقدة. لكن هذه المرونة غالبًا ما تؤدي إلى الفوضى: الدوال المثقلة، التحويلات الضمنية، إدارة الذاكرة اليدوية، والماكرو يمكن أن تحول المشروع إلى "مستنقع" في غضون أشهر. مفهوم Clean Code (الكود النظيف)، الذي شاعه روبرت مارتن، ينطبق على C++ بشكل كامل، ولكن مع مراعاة خصوصية اللغة.
\n\nفي هذه المقالة، سنستعرض المبادئ الأساسية للكود النظيف في C++ ونوضح تطبيقها بأمثلة واقعية. ستتعلم كيفية كتابة كود يسهل قراءته واختباره وصيانته.
\n\n1. التسمية والهيكلة: أساس قابلية القراءة
\n\n1.1. أسماء ذات معنى للمتغيرات والدوال
\n\nالقاعدة الأولى للكود النظيف هي أن الاسم يجب أن يكشف عن القصد. في C++، هذا مهم بشكل خاص بسبب وجود التحميل الزائد والقوالب.
\n\nمثال سيء:
\n\nint d; // elapsed time in days\nvoid proc(int a, int b); // ما هما a و b؟\n\nمثال جيد:
\n\nint elapsedTimeInDays;\nvoid processData(const std::vector<int>& inputData, int maxIterations);\n\n1.2. الفئات ومساحات الأسماء
\n\nاستخدم مساحات الأسماء للتجميع المنطقي. تجنب المتغيرات العامة - فهي نمط سيء.
\n\nnamespace 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\n2. الدوال: صغيرة وذات مسؤولية واحدة
\n\n2.1. مبدأ المسؤولية الواحدة (SRP)
\n\nيجب أن تقوم الدالة بشيء واحد فقط. إذا كانت الدالة تقوم بأكثر من إجراء واحد - قم بتقسيمها.
\n\nمثال سيء:
\n\nvoid 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\nbool 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\n2.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\n3. إدارة الذاكرة و RAII
\n\n3.1. استخدم المؤشرات الذكية
\n\nفي C++ الحديثة (C++11 وما بعده)، تعتبر إدارة الذاكرة اليدوية عبر new/delete قديمة. استخدم std::unique_ptr و std::shared_ptr.
// سيء: تسرب الذاكرة ممكن\nvoid process() {\n Resource* res = new Resource();\n // ... إذا حدث استثناء هنا، ستتسرب الذاكرة\n delete res;\n}\n\n// جيد: تحرير تلقائي\nvoid process() {\n a