لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 02/03/23 في كل الموقع
-
2 نقاط
-
2 نقاط
-
على ما يبدو انك لم تقم بعمل git add ولا git commit لكل الملفات، أو ربما كنت داخل مجلد فرعي عندما كتبت الاوامر. جرب كتابة الأمر : git add . وتأكد من انك في المسار الصحيح (المسار الاصلي) ثم اكتب الأمر : git commit -m "message content" وبعدها : git push2 نقاط
-
مرحبا ، لدي هذا الكود في أحد المتحكمات في مشروع Laravel وأحصل على خطأ public function store(Request $request) { $values = []; $request->validate([ 'order_number' => 'required', 'client_id' => 'required|exists:clients,id', 'description' => 'required', 'products' => 'required|exists:products,id', 'amount' => 'required', ]); $order = Order::create($request->all()); foreach ($request->products as $product) { $values[] = [ 'order_id' => $order->id, 'product_id' => $product, 'amount' => $request->amount, ]; $amount = Product::find($product); $total_value = $request->amount + $amount->amount; //المشكلة تحدث هنا $amount->update(['amount' => $total_value]); } $order->products()->attach($values); return redirect('/')->with('msg', 'Order Saved successfully!'); } تأتي جميع القيم كقيمة واحدة باستثناء amount الذي يأتي كمصفوفة وليس كقيمة واحدة. هذا هو الخطأ الذي أحصل عليه: Unsupported operand types: array + string هذا هو نموذج Product protected $fillable = [ 'name', 'price', 'amount', ]; public function orders() { return $this->belongsToMany(Order::class); } وهذا هو dd ($ request-> amount) ؛2 نقاط
-
شكرا. أنا وجدت حلا و أرجو التصحيح أو التعديل إن كان غير مناسب أولا: nstalling json-server ثانيا: في ملف package.json و بالتحديد داخل ال "scripts" نضيف: "json-server": "json-server --watch data/data.json --port 5000", ثالثا: التحول إلى terminal و كتابة التعليمة التالية: npm run json-server بالطبع يسعدني جدا وجود إجابات أخرى.2 نقاط
-
كما وضح عمر في التعليق السابق فإن Node.js غير مدعوم في حزم الاستضافة المشتركة والسحابية. وإذا كنت ترغب في استخدام Node.js ، يمكنك تثبيت هذه الميزة المفيدة على خطط VPS ويعتبر الإستضافة الأفضل وهي الالإختيار الأول Vercel تعتبر الإستضافة الأفضل لمشروع Next JS كما في التوثيق الرسمي ل Next JS وهي بواسطة منشئي Next.js ويمكنك إتباع الخطوات كما في التوثيق الرسمي ل Next JS من خلال هذا الرابط Netlify ربما يكون Netlify هو المضيف الأكثر شعبية بين المطورين ، وأعتقد أن واجهة المستخدم البسيطة والبديهية والسريعة تلعب دورًا في ذلك. يمكنك رفع المشروع على Netlify بسهولة عن طريقة الخطوات التالية قم برفع موقع Next.js على GitHub أو غيره قم بإنشاء موقع Netlify جديد من المستودع الخاص بموقع Next.js عن طريق ال Netlify CLI أو استخدام واجهة مستخدم تطبيق Netlify. أضف Next علىNetlify plugin لتمكين الميزات الديناميكية لـ Next بما في ذلك المسارات الديناميكية ومسارات API ووضع المعاينة. يمكنك قراءة هذه المقالة على موقع netlify للمزيد من التفاصيل يوجد العديد من الشركات الأخرى ولكن هذه هي أفضل إختيارات لديك2 نقاط
-
ماهو نوع الاستضافة الخاصة بك. فلا يمكن رفع تطبيق Next متكامل على استضافة Hostinger التشاركية (shared hosting). إلا اذا كان التطبيق عبارة عن frontend فقط وعندها تقوم برفعه مثل اي ملف html و css بعد ان تقوم بعمل export وحتى تستطيع رفع تطبيق Next على Hostinger يجب ان تملك استضافة VPS. في حال لم تقم بشراء الاستضافة بعد فهنالك استضافات رخيصة من نوع shared hosting وذات جوده عالية تدعم node وبالتالي تدعم Next مثل namecheap.2 نقاط
-
1 نقطة
-
1 نقطة
-
كيف يمكنني فهم الدروس بشكل اسرع لانني اريد التقديم علي الشهادة وأجد ان الموضوع صعب يعني مثلا في مسار "بناء تطبيق شبيه ب whatsapp" لا يمكنني فهم كل الدروس واخاف عند التقديم علي الامتحان ان لا استطيع الاجابه علي الاسئلة1 نقطة
-
1 نقطة
-
ازاي يتم عمل صفحة جديدة لكل سؤال في اكاديمية حسوب وما التقنيات المستخدمه في عمل ذلك وما الية عمل ذلك1 نقطة
-
انا ادرس JavaScript في كورس علوم الحاسوب هل تنصحوني بقرائة كتاب JavaScript من اكادمية حاسوب مع الدورة ام اركز على الدورة واقرأ الكتاب بعد الدورة ام لا يوجد حاجة لقرائته1 نقطة
-
كيف يمكنني تحديد تخصصي البرمجي؟ هل يفضل البدء في برمجة الجوال او برمجة الويب؟ شكرا 3>1 نقطة
-
وعليكم السلام ورحمه الله وبركاته. اخي الكريم هل قمت بعمل Commit لملفات مشروعك الجديدة ؟ اعتقد انك نسيت اضافة ملفات مشروعك. لاضافة جميع ملفات مشروعك اكتب ما يلي: ١- اكتب الامر * git add ٢- "git commit -m "add all my project file تستطيع استبدال add all my project file بأي نص تريده ثم بعد ذلك اكتب الامر git push origin main وسيتم رفع ملفاتك على ال repository ع ال GitHub. 🌸🌸🌸🌸1 نقطة
-
اهلا محمود , هذه هي خطوات انشاء repo علي github بطريقه سليمة : 1- افتح الTerminal وانتقل إلى المجلد الذي تريد إنشاء المستودع فيه. 2- أدخل الأمر التالي لتهيئة مستودع Git جديد: git init 3- استخدم أمر git add لإضافة الملفات إلى المستودع: git add <file> 4- أدخل التعديلات باستخدام أمر git commit مع رسالة وصفية: git commit -m "Initial commit" 5- لربط المستودع المحلي بمستودع عن بعد (مثل في GitHub)، يمكنك استخدام أمر git remote: git remote add origin <repository-url> 6- أدخل التعديلات إلى المستودع عن بعد باستخدام أمر git push : git push -u origin master1 نقطة
-
لدي الكود التالي الذي يمر عبر مجموعة من المجموعات ، ويبحث عن بيانات ثم يحفظ التفاصيل في مصفوفة جديدة: for (const group of originalGroups) { let groupInfo = await this.myService.getData( group ); console.log(groupInfo); this.groups.push({ name: group.name, _id: group._id, info: groupInfo, }); }` عندما تنتهي حلقة for ، وأقوم بطباعة البيانات ، يكون لديهم جميعا نفس البيانات لأنها تأخذ آخر واحدة تم إرجاعها في الحلقة for وتطبقها على جميع المجموعات. هل يمكن لأي شخص مساعدتي؟ شكرا لك مقدما1 نقطة
-
المشكلة تحدث بسبب أنك تحاول جمع متغير من نوع مصفوفة Array مع سلسلة String. وهذا غير ممكن. لاحظ أنك المتغير $request->amount المرسل بواسطة الركويست هو من نوع مصوفة Array. اذا كنت تحاول جمع كل عناصر المصفوفة فيمكن استخدام الفانكشن array_sum. فيكون حل المشكلة هكذا: $total_value = array_sum($request->amount) + $amount->amount;1 نقطة
-
1 نقطة
-
1 نقطة
-
لحل المشكلة عن طريق موجه الاوامر هنالك بعض الحلول : جرب تشغيل موجه الأوامر في وضع المسؤول وكتابة الامر التالي : Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted ثم حاول مرة ثانية. إذا لم يعمل جرب الأمر : ExecutionPolicy RemoteSigned ثم حاول مرة ثانية. إذا لم يعمل جرب الأمر التالي ثم حاول مرة ثانية : Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass وإذا لم ترد حل المشكلة عن طريق موجه الاوامر اذهب إلى : settings -> Update & Security -> For Developers -> PowerShell (الاعدادات) ثم (الخصوصية والامان أو التحديثات و الامان حسب اصدار الويندوز) ثم من اجل المطورين ثم ابحث عن PowerShell. ثم فعل الخيار التالي :1 نقطة
-
1 نقطة
-
حاول القيام بتنفيذ الأمر Set-ExecutionPolicy RemoteSigned في نافذة powershell تقوم بفتحها ك administrator حيث أن سبب هذه المشكلة هي سياسة ال powershell لذلك تغييرها حالياً ربما يحل المشكلة لذلك قم يتنفيض هذا الأمر ثم أعد تشغيل برنامج vs code وتنفيذ الأمر الذي تريده1 نقطة
-
@مصطفى امير صالح حسين صديقي, لو كان لديك عملاء تصمم لهم مواقع فالاربح لك استعمال استضافة ريسلر حتى تبيع خدمة التصميم وخدمة الاستضافة والدومين بشكل متكرر دوري وبالتالي أرباح دورية.1 نقطة
-
السلام عليكم. يظهر لي الخطأ التالي في مشروع react Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17 أعتقد أنه يشير علي بتحديث نسخة react. كيف أقوم بهذا التحديث. علما و أني جربت الحلول التالية: أولا: import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <App /> </React.StrictMode> ); ثانيا. import {StrictMode} from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render( // 👈️ deprecated starting React 18 <StrictMode> <App /> </StrictMode>, document.getElementById('root'), ); كل هذه الحلول لم تجد نفعا. شكرا على المساعدة.1 نقطة
-
1 نقطة
-
في هذه المرة قال لي بأن ReactDom غير معرف index.js:7 Uncaught ReferenceError: ReactDOM is not defined1 نقطة
-
عدل الكود للشكل : import React from "react"; import ReactDOM from 'react-dom'; import * as ReactDOMClient from 'react-dom/client'; import "./index.css"; import App from "./App"; const root = ReactDOMClient.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <App /> </React.StrictMode> ); تم تعديل الكود السابق وإضافة الـ : import ReactDOM from 'react-dom';1 نقطة
-
الآن ظهرت رسالة الخطأ التالية: react-dom.development.js:86 Warning: You are importing createRoot from "react-dom" which is not supported. You should instead import it from "react-dom/client" حاولت التعديل بالطرق الإضافات التالية: // 👇️ For client createRoot or hydrateRoot import * as ReactDOMClient from 'react-dom/client'; // 👇️ For renderToPipeableStream or renderToReadableStream import * as ReactDOMServer from 'react-dom/server'; للأسف دون جدوى1 نقطة
-
الشكل الصحيح هو : import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <App /> </React.StrictMode> ); وابسط شكل لها هو كالتالي : const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<h1>Hello, world!</h1>); انظر التوثيق الرسمي لـ reactjs وتأكد من ان اصدار react و react-dom لديك هو اكبر من 18.1 نقطة
-
السلام عليكم. كيف با امكاني ارسال رسائل واتس اب عن طريق برنامج سي شارب وقواعد بيانات1 نقطة
-
اهلا سماح, "M-5Tree" و "M-Tree" ليست كلمات معروفة على وجه الخصوص في مجال تعلم الآلة وشجرة القرار. من المحتمل أن يكونا تغيرات أو تمديدات لخوارزمية شجرة القرار، ولكن بدون مزيد من السياق أو المعلومات، من الصعب تحديد الفروق بالضبط بينهما. عموما، شجرة القرار هي خوارزمية تعلم الآلة شعبية تستخدم للمهام الصناعية وتصنيف الصناعية. تقسم خوارزمية شجرة القرار البيانات إلى عينات أصغر على أساس الخاصية الأكثر أهمية وتبني نموذجا مشابها للشجرة لإجراء التوقعات.1 نقطة
-
يمكنك القيام بشيء ما مثل : export default function MainRoutes() { const [lan, setLan] = useState("en"); return ( <Router> <Routes> {lan === "en" && <Route path='/' element={<CompanyEn />} />} {/* <Route path='/ar' element={ <CompanyEn /> } /> */} {lan === "ar" && <Route path='/ar' element={<CompanyArOne />} />} </Routes> </Router> ); } وبهذه الطريقة لن يتم تحميل اي ملف من المكون العربي إلا إذا كانت اللغة عربية ولن يتم تحميل اي مكون من اللانجليزي إلا اذا كانت انجليزية. ويمكنك اضافة الشرط لأكثر من مكون مثل : export default function MainRoutes() { const [lan, setLan] = useState("en"); return ( <> {lan === "en" && <Routes> <Route path='/' element={<CompanyEn />} /> <Route path='/example' element={<Example />} /> </Routes> }{lan === "ar" && <Router> <Route path='/ar' element={<CompanyArOne />} /> <Route path='/ar/example' element={<Example />} /> </Router> } </> ); }1 نقطة
-
M5Tree و Decision Tree و M-Tree كلها خوارزميات التعلم الآلي المستخدمة في مهام التنبؤ والتصنيف. M5Tree: هو شكل من أشكال خوارزمية شجرة القرار ، والذي يستخدم نموذج الانحدار الخطي لعمل تنبؤات على أوراق الشجرة. تهدف خوارزمية M5Tree إلى تحسين دقة تنبؤات شجرة القرار. شجرة القرار (Decision Tree): هي خوارزمية بسيطة لكنها قوية تبني نموذجًا يشبه الشجرة من القرارات وعواقبها المحتملة. يمثل كل فرع من فروع الشجرة قرارًا محتملاً ، وتمثل كل عقدة ورقية النتيجة. يتم استخدام أشجار القرار لكل من مشاكل الانحدار والتصنيف. M-Tree: هو نوع من بنية بيانات الفهرسة المكانية المستخدمة للبحث الفعال عن أقرب الجيران في المساحات المترية عالية الأبعاد. يستخدم بشكل شائع في رؤية الكمبيوتر وأنظمة إدارة قواعد البيانات لتحسين أداء البحث. بخلاف M5Tree و Decision Tree .1 نقطة
-
اضافة اللغة العربية لا يلزم ان تقوم بفص الصفحات التي تدعم العربية عن الأنجليزية افضل طريقه هي بعمل العناصر الموقع بالكامل اوكل قسم باللغه الأنجليزية اولا ثم العربيه لأن التغيرات ستكون بسيطه اما عن استخدام rtl في bootstrap فكما ذكر الأستاذ محمد الخطيب في التعليق السابق وهو بالتحكم في اتجاة الصفحه عن طريق الأب بدلاً من كل عنصر بمفرده وستقوم بعمل ملف css للتعديلات التي ستحتاجها عند التحويل الي العربية ويتم ربطه بنفس الطريقه وبالنسبة للمحتوي نفسه فسنجعله ديناميكي بأن نقوم بعمل ملف js لكل لغه في كل ملف object في ه جميع النصوص التي ستتخدم في الموقع ومن ثم قم بإستدعائها وربطها const data = { title: "hello", link: "google.com", }; export default data; او اجعل نوع الملف json او قم بعمل fetch ان كان سيتم ربط الموقع في المستقبل بال back-end لا تهم الطريقه النتيجه واحدة1 نقطة
-
يمكنك تنفيذ النصائح التي اخبرك بها الأستاذ بلال, بالاضافة الى انك يمكنك استخدام هياكل بيانات افضل من تخزين الاسماء والارقام على هيئة مصفوفتين, على سبيل المثال, يمكنك إنشاء object ويكون الkey للobject هو الاسم والvalue هي رقم الهاتف او العكس, سيحسن ذلك من الكود خاصتك بشكلٍ أفضل1 نقطة
-
تعلم البرمجة من الكتب يمكن أن تكون مفيدة أو تكون مضيعة للوقت لذلك سأقوم بتوضيح بعض الأشياء التي يجب البحث عنها عند تحديد الكتب التي يجب قراءتها لتحسين معرفتك ومتى تقرأها. ابحث عن الكتب الأعلى جودة : قد يبدو هذا واضحًا ، لكن لا تضيع وقتك مع الكتب القديمة أو المكتوبة بشكل سيئ. أنت تريد أن تقرأ كتبًا من أشخاص يتمتعون بالمعرفة فيما يتحدثون عنه وأيضًا مكتوبون جيدًا ويقدمون قيمة حقيقية لك. اقرأ عن المفاهيم وليس التقنيات: لأن التقنيات تتغير بسرعة والكتب المتعلقة بها أصبحت قديمة.إذا كنت تريد تعلم React ، على سبيل المثال ، فمن الأفضل أن تتعلم من خلال قراءة الوثائق وإنشاء مشاريعك الخاصة. قد يستغرق تعلم React بضعة أشهر لكن عملية التعلم هذه تبدو مختلفة كثيرًا الآن عما كانت عليه قبل بضع سنوات.في حين أن المفاهيم في كتاب مثل Clean Code أو The Pragmatic Programmer هي أفكار خالدة. ببساطة لأنهم يعلمونك مهارات قابلة للتحويل يمكنك أن تحملها معك في مهنتك في البرمجة . استخدم الكتب كمواد تعليمية تكميلية وليست مواد تعليمية أولية لذلك يعتبر التركيز على الدروة التعليمية حالياً أفضل لك حيث أن الإستفادة الحالية لك من الدورات التعليمية أفضل بكثير من الكتب ربما لاحقاً تحتاج لبعض الكتب لزيادة المعلومات البرمجية لديك1 نقطة
-
نعم ، يبدو أن الرمز صحيح. إنه برنامج بسيط يتيح لك البحث عن رقم هاتف أو اسم وإضافة مستخدمين جدد. ومع ذلك ، هناك بعض الأشياء التي يمكن تحسينها: في دالة search_by_phone_number ، الشرط أثناء while len(phone_number) != 10 and not int(phone_number) سيتم تقييمه دائمًا إلى True لأن عامل التشغيل يتطلب أن يكون كلا الشرطين صحيحًا not int(phone_number) سيكون دائمًا صحيحًا كما int(phone_number) إلى ValueError إذا لم يكن phone_number عددًا صحيحًا. لا يتعامل الرمز مع الأخطاء التي قد تحدث ، مثل إذا قام المستخدم بإدخال رقم هاتف غير صحيح في دالةsearch_by_phone_number. لا يتعامل الرمز مع التكرارات ، لذا فإن إضافة مستخدم برقم هاتف أو اسم موجود بالفعل سيؤدي إلى إضافة نفس رقم الهاتف أو الاسم عدة مرات.1 نقطة
-
لا اعتقد ان chat gpt سيحل محل مبرمجي الـ font-end في اي وقت قريب وهو اليوم يساعد مبرمجي الـ font-end و لا يحل محلهم. فهو يقوم بتحليل عمل كمية كبيرة من المواقع حتى يستطيع اعطاء نصائح ومساعدتك في كتابة اكواد معقدة، ولكنه لن يتمكن من انشاء الموقع الذي تريده بهذه السهولة. وحتى لو قام بإنشاء الموقع فينبغي وجود مبرمجين حتى يقوموا بفهم هذا الموقع وبالتالي يكونوا قادرين على تطويره حتى يناسب طلبهم (كأنه يعطيك قالب قابل للتعديل بدلاً من ان تبدأ من الصفر تماما). ولا انفي انه من الممكن ان يحل محل مبرمجي الـ font-end في وقت ما لاحقاً ولكن سنبقى بحاجة لمبرمجين على دراية بتقنيات font-end حتى يقوموا باستخدام الـ chat بالشكل الصحيح.1 نقطة
-
هذا يعتمد على الاتفاق الذي اجريته قبل بدئ العمل، وإذا لم يكن هنالك اي اتفاق سابق فيمكنك اعطاءه اسم المستخدم وكلمه المرور أو إعطاءه الدومين والموقع فقط. والافضل بين الخيارين السابقين هو ان تعلمه كيف يستخدم الموقع و تمكنك من ادارة الموقع والعميل ليس بحاجة للوصول إلى الاستضافة وادارة الموقع ولا يعرف كيف يفعل ذلك في اغلب الحالات.1 نقطة
-
يُعتبر مبدأ المسؤوليّة الواحدة Single Responsibility Principle (أو اختصارًا SRP) المبدأ الأوّل من مبادئ التصميم SOLID، وهو مفيد بصورة خاصّة في التصميم كائنيّ التوجّه object-oriented design. يعتمد هذا المبدأ على تجزئة مكوّنات النظام البرمجي بحيث يكون لكلّ جزء منه مهمّة (مسؤوليّة) واحدة ووحيدة. ينص هذا المبدأ على ما يلي: لا يظهر من النص السابق أي إشارة مباشرة إلى المسؤوليّة الواحدة. لتوضيح الربط بين المسؤولية الواحدة وبين نص المبدأ السابق، لننظر إلى المثال التالي الذي يحوي صنفًا مكتوبًا بلغة ++C ويُستخدم للاتصال بخادوم قواعد بيانات MySQL. اسم هذا الصنف MySQL أيضًا، ويمتلك واجهة لتأسيس الاتصال مع خادوم MySQL وإغلاقه، وإرسال استعلامات SQL إلى الخادوم واستقبال ومعالجة النتائج: class MySQL { public: bool connect(); void disconnect(); bool executeQuery(std::string queryString); MySQLResult* getQueryResult(); }; من الواضح أنّ لهذا الصنف مهمّتان أساسيّتان، الأولى هي إدارة عملية الاتصال مع خادوم MySQL (فتح وإغلاق الاتصال) والثانية هي التواصل مع الخادوم في إجراء الاستعلامات واستقبال النتائج (تنفيذ استعلامات SQL). لو افترضنا الآن حدوث السيناريو التالي: أصبح خادوم MySQL يقبل الاتصالات المشفّرة فقط. حدثت بعض التغييرات ضمن الخادوم بحيث أنّه بدأ بالاستجابة بشكل مختلف لبعض الاستعلامات. سيؤدي ذلك بالطبع إلى حدوث تغييرين ضمن صنف MySQL السابق، أو بمعنى آخر، سيكون هناك سببان لتغيير الصنف MySQL. ويُعدّ هذا خرقًا لمبدأ المسؤولية الواحدة كما هو واضح. يُعتبر وضع أكثر من مهمّة قابلة للتغيير (من أجل سبب ما) لأحد الأصناف خطأً تصميميًّا. قد لا تبدو تلك مشكلةً في الوقت الحالي، ولكن أيّ نظام برمجي يتغيّر ويتطوّر. فما يبدو حلًّا مقبولًا في الوقت الحاضر، قد يُفضي إلى نتائج سيّئة في المستقبل. يمكن استخدام الحل التالي لمشكلتنا السابقة: class MySQLConnection { public: bool open(); /* former connect() */ void close(); /* former disconnect() */ }; class MySQLQuery { MySQLConnection* session; public: bool execute(std::string queryString); MySQLResult* getResult(); }; يبدو مبدأ المسؤوليّة الواحدة بسيطًا، ولكنّه في الحقيقة صعب التطبيق. والسبب في ذلك، هو أنّ وضع المسؤوليّات المتعدّدة لصنف ما معًا، هو أمر بديهي ومألوف بالنسبة إلينا، أمّا عملية الفصل والتجزئة إلى أصناف أصغر لكلٍّ منها مسؤوليّة واحدة، فقد لا تبدو جذّابةً أوّل الأمر. بالنسبة لي، عندما عدت وراجعت بعض تصميمات الأصناف القديمة لديّ، قلّما وجدت صنفًا من الممكن جعله يراعي هذا المبدأ. ولكن عندما أمعنت النظر والتفكير وجدت أنّ الفصل في المهام سيقلّل من تعقيد التصميم، وسيجعل الشيفرة أيسر للقراءة والفهم. بالمقابل، فإنّ تطبيق هذا المبدأ بشكل صارم، ليس فكرةً جيّدة. فعلى المرء أن يكون حكيمًا في تحديد متى يمكن تطبيق هذا المبدأ، وخصوصًا عندما يجد أنّ الملف الخاص بأحد أصنافه بات يحتوي على أكثر من 500 سطر من الشيفرة البرمجيّة! ترجمة -وبتصرّف- للمقال Single Responsibility Principle لصاحبه Radek Pazder.1 نقطة
-
يُعتبر مبدأ الفتح والإغلاق Open/Closed Principle أو اختصارًا OCP، من المبادئ التي تساعد مطوّري البرمجيّات على تحقيق تصاميم برمجيّة عالية الجودة. على أيّة حال، قد يكون من الصعب أحيانًا أن نوضّح ما الذي نعنيه بالبرمجيّات عالية الجودة. بالعودة إلى المبدأ OCP، يعود الفضل إلى برتراند ماير في وضع مصطلح مبدأ الفتح والإغلاق، حيث ظهر أوّل الأمر في كتابه البنية كائنيّة التوجّه للبرمجيّات "Object Oriented Software Construction" ينص هذا المبدأ على ما يلي: الذي يعنيه هذا المبدأ، هو أنّنا عندما نُصمّم جزءً من تطبيق برمجي، فإنّه من الضروري أن نضع في حسباننا إمكانيّة التوسّع المستقبليّ، فكلّنا يعلم أنّ المتطلّبات الخاصّة بالزبائن تتغيّر على الدوام وبسرعةٍ كبيرة. لذلك فإنّ الشيفرة البرمجيّة ستتغيّر وتتوسّع لتلبّي المزيد من المتطلّبات والمزايا، وقد لا يؤدّي هذا الأمر على الدوام إلى عواقب حميدة على الصعيد البرمجي. الهدف الذي يُنشده هذا المبدأ هو أن ننظر إلى المستقبل (ابنِ الآن، وخطّط للمستقبل) بحيث نصمّم تطبيقاتنا البرمجيّة بحيث لا تحتاج إلى تغيير في الشيفرة المكتوبة مسبقًا عند إضافة مزايا ووظائف جديدة إليها. لندع الشيفرة البرمجيّة تُعبّر عن نفسها مع المثال التالي: def area(geometric_entity): if geometric_entity.type() == SQUARE: return geometric_entity.a * geometric_entity.a elif geometric_entity.type() == CIRCLE: return PI * geometric_entity.r * geometric_entity.r else: raise UnknownEntityError("I literally have no idea.") قد توحي الشيفرة السابقة بالبساطة أوّل الأمر، ولكنّها تُظهر جانبًا أساسيًّا من مبدأ OCP. فإذا أردنا مثلًا أن تدعم الدالّة السابقة إمكانية حساب مساحة مستطيل فيمكن ذلك بسهولة وذلك بإضافة مقطع elif جديد. ولكن بالمتابعة على هذا المنوال، وفي حالة حساب مساحة شكل هندسي غير قياسي، فستتحول الأسطر البرمجيّة البسيطة السابقة إلى ما يزيد عن 1500 سطر برمجي لحساب مساحة هذا الشكل باستخدام تكامل ريمان Riemann Integral، مما سيجعل هذه الأسطر كوحش برمجيّ إذا لم يلتهمك، فإنّ مدير المشاريع سيفعل ذلك حتمًا! النقطة التي نريد الوصول إليها، أنّه في كلّ مرّة نريد فيها إحداث تغيير في البرنامج لدعم مزايا جديدة، فإنّه من الممكن أن يؤدّي هذا التغيير إلى مشاكل في عمل المزايا القديمة التي كانت تعمل بشكل جيّد أصلًا، وهذا أمر غير مرغوب بالطبع. وهذا ما يحذّرنا منه مبدأ OCP، فيجب أن تكون العناصر البرمجيّة مفتوحة للتوسعة (دعم مزايا إضافيّة) ولكنها مغلقة للتعديل (عدم الحاجة إلى تعديل الشيفرة التي تدعم المزايا القديمة). قد يتبادر إلى ذهن البعض أنّه في حالة حدوث مشاكل جرّاء هذا التعديل فمن الممكن إصلاحها باستخدام وحدات الاختبار unit tests ومنقّحات الأخطاء debuggers، ولكن لماذا نلجأ لمثل هذه الأساليب إذا كان بإمكاننا تجنّبها أصلًا؟ فدرهم وقاية خير من قنطار علاج. وكما أنّه من الصعب وضع تعريف رسميّ لمعيار الجودة للبرمجيّات، فكذلك الأمر بالنسبة لهذه المبادئ. فلا توجد قواعد صارمة للتقيّد بها، فكل شيء يعود للخبرة الشخصيّة والتخطيط الجيّد. ترجمة -وبتصرّف- للمقال Open/Closed Principle in Software Design لصاحبه Radek Pazdera.1 نقطة