اذهب إلى المحتوى

لوحة المتصدرين

  1. ياسر مسكين

    ياسر مسكين

    الأعضاء


    • نقاط

      7

    • المساهمات

      290


  2. Ail Ahmed

    Ail Ahmed

    الأعضاء


    • نقاط

      6

    • المساهمات

      426


  3. محمود سعداوي2

    محمود سعداوي2

    الأعضاء


    • نقاط

      5

    • المساهمات

      511


  4. Mustafa Suleiman

    Mustafa Suleiman

    الأعضاء


    • نقاط

      4

    • المساهمات

      8580


المحتوى الأكثر حصولًا على سمعة جيدة

المحتوى الأعلى تقييمًا في 04/15/24 في كل الموقع

  1. السلام عليكم لدي نفكرة عامة و لاكن احتاج الى تفصيل! تحديد المتطلبات من خلال التحدث مع العميل تصميم UI UX بالتعاون مع مصمم برمجة frontend + backend testing نشر التطبيق
    3 نقاط
  2. في تعملي حاوت انشاء برنامج ملاحظات بطريقة اخرى غير الموجوده في دورة react js ولاكن تواجهني مشكلة في الكود لا أعلم ما سببها وهذي هيا ملفات المشروع react-note.zip
    3 نقاط
  3. السلام عليكم. بعد تسجيل الدخول، يتوجه المستخدم ملفه الشخصي للقيام بإضافة ما يتوجب من معطيات. في هذه الحالة تكون المصفوفة profile فارغة لأنه لاتوجد بداخلها بيانات تتعلق بالملف الشخصي للمستخدم. يقوم المستخدم إذن بإنشاء ملفه الشخصي بواسطة الكود التالي: const profileSlice = createSlice({ name: "profile", initialState: { profile: [], loading: false, isProfileCreated: false, }, reducers: { setProfile(state, action) { state.profile = action.payload }, setLoading(state) { state.loading = true }, clearLoading(state) { state.loading = false }, setIsProfileCreated(state) { state.isProfileCreated = true; state.loading = false }, clearIsProfileCreated(state) { state.isProfileCreated = false; }, }, }); *** export function createProfile(newProfile) { return async(dispatch, getState) => { try { dispatch(profileActions.setLoading()) const { data } = await axios.post(PROFILE_URL, newProfile, { headers: { 'x-auth-token': getState().auth.user.token } }) dispatch(profileActions.setProfile(data)) dispatch(profileActions.setIsProfileCreated()) setTimeout( () => dispatch(profileActions.clearIsProfileCreated()), 2000 ); } catch (error) { const err = error.response?.data.msg if (err) { dispatch(alertActions.createAlert(err)); dispatch(alertActions.clearAlert(err)); } const errors = error.response.data.errors errors?.forEach((err) => { dispatch(alertActions.createAlert(err.msg)); dispatch(alertActions.clearAlert(err.id)); }); dispatch(profileActions.clearLoading()) } } } **** const navigate = useNavigate(); const dispatch = useDispatch(); const { loading, isProfileCreated } = useSelector((state) => state.profile); const { alerts } = useSelector((state) => state.alert); const addNewProfile = (e) => { e.preventDefault(); dispatch( createProfile({ status, company, website, location, skills, githubusername, bio, twitter, facebook, instagram, linkedin, youtube, }) ); alerts.map((alert) => dispatch(alertActions.clearAlert(alert.id))); }; useEffect(() => { if (alerts.length > 0) { setShow(true); setTimeout(() => { setShow(false); }, 3000); } }, [alerts]); useEffect(() => { if (isProfileCreated) { navigate("/dashboard"); } }, [navigate, isProfileCreated]); هنا يتم إنشاء الملف الشخصي، ويتم تسجيل كافة المعطيات بقاعدة البيانات. المشكل الذي أواجهه. في الكود التالي const { profile } = useSelector((state) => state.profile); console.log(profile) عندما أقوم بتحديث الصفحة تصبح profile مصفوفة فارغة. أرجو المساعدة.
    2 نقاط
  4. السلام عليكم يعطيكن العافية لو سمحتوا ممكن حدا يشرحلي لماذا طبعت get model بدل set... والدالة if لماذا استخدمتها؟ وهل عند التعامل مع التطبيقات رح يكون نفس المبدأ معقد؟🤔
    2 نقاط
  5. السلام عليكم. في الكود التالي: function DashboardScreen() { const { profile } = useSelector((state) => state.profile); return ( <div className="mt-16"> {profile.length === 0 ? ( <> <Title>Dashboard</Title> <div className="mx-4 mb-4 lg:mx-8"> <p className="text-lg text-zinc-800 my-4"> You have not yet setup a profile, please add some info. </p> <Button> <Link to="/dashboard/create-profile">Create Profile</Link> </Button> </div> </> ) : ( <> <MyComponent/> </> )} </div> ); } export default DashboardScreen; في البداية كل شيء تمام. لكن عندما أقوم بتحديث الصفحة يكون طول المصفوفة صفر. الرجاء المساعدة.
    2 نقاط
  6. <input type="text"></input> input { width: 600px; outline: none; border: none; background-color: #f5f5f5; border-bottom: 5px solid; border-image-source: linear-gradient( to right, #f54336 50%, #009687 50%, #009687 100% ); border-image-slice: 1; }
    2 نقاط
  7. السلام عليكم الرساله ده بتظهر علي الشاشه بتاعتي علي الكمبيوتر ببيعمل علي نظام windows وهي ده الرساله Activate windows Go to settingsto activate windows
    2 نقاط
  8. السلام عليكم عندي مشكله دلوقتي عايز اخلي الصوره في النص مش نازله تحت كده اعمل اي دا كود الزر <div class="acc-tool1"> <div class="acc-item"> <div onclick="window.open('https://youtube.com/@khatar_official');"> <div class="acc-title"> &nbsp; <i class="fab fa-download" style=" color: white; font-size: 18px; font-weight: 400;"></i> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; اشترك في قناتي علي اليوتيوب <div class="author-img2 radius100px"><img border="0" data-original-height="1949" data-original-width="3464" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEjcnncOCeoSzijTrJkMRofEAfTbPHxMi4YRNkhAP8PUuNIvaoKioud-tHURilzjXIi6heOrfmVKMhJ71oqD5p3hPsKq9kwmuHsoyxS1B9dequ8talfFmNV62QMWbLHtpF2b45moj_hB1EOAf1RMqtx2zzXRWGbMeQC5EXsFAtRmi76Uv55cxGazBhhoKDaI=s1600" width="320" /></div> </div></div></div></div>
    2 نقاط
  9. انا اتابع من خلال محتوى الدورة فقط ارى انه غير كافي لتعلمي كل حقل متلا react js هل عادي اكمل على الدورة ام علي تعلم من جهات اخرى للعمل في سوق شغل بشكل سليم ؟! كبف ذلك ؟!
    1 نقطة
  10. اولاً لماذا الدرس يتوقف عن التشغيل بشكل مفاجىء في كل المتصفحات وهل يوجد خلاصة للدروس او ملخص لكل درس وشكراً.
    1 نقطة
  11. الدروس تعمل بشكل طبيعي، لكنها شكوى متكررة بالفعل، أرجو تحديث الصفحة من خلال الضغط على CTRL + F5 لحذف الملفات المؤقتة، ثم التجربة إن استمرت المشكلة أرجو استخدام متصفح آخر بدون إضافات والتجربة لمعرفة أين المشكلة، وإخبارنا إن تم حل المشكلة. وبخصوص المُلخصات، فلا يوجد تلخيصات نصية للدروس للأسف، يمكنك الإعتماد على موسوعة حسوب كمرجع لك: https://wiki.hsoub.com/الصفحة_الرئيسية
    1 نقطة
  12. مرحباً, أنت تقوم ببعض العمليات على profile slice , ولكن ما تواجهه أنه البيانات تزول عندما تقوم بتحديث الصفحة أو إعادة تحميلها بأي شكل , هذا بالطبع سيحدث كون redux toolkit بشكل إفتراضي لا تقوم بحفظ البيانات بشكل دائم في المتصفح ( local storage او اي شكل اخر ) , وإنما تقوم بحفظها بشكل مؤقت في المتصفح وعند إعادة تحميل الصفحة سوف تزول جميع العمليات التي قمت بها . لحل هذه المشكلة ( او ما تبحث عنه ) يمكنك فعلها بطريقتين: إما باستخدام localStorage , وتقوم بحفظ وتعديل البيانات في localStorage كلما قمت بتعديل redux toolkit slice , وفي كل مرة تقوم بتشغيل التطبيق تفحص إذا كان هناك بيانات مخزنة في localStorage فتقوم بإستردادها ل profile slice , يمكنك تعديل الكود لديك كالشكل التالي : أولاً قم بتحديث create profile action لتتضمن تخزين البيانات في local storage : export function createProfile(newProfile) { return async(dispatch, getState) => { try { dispatch(profileActions.setLoading()) const { data } = await axios.post(PROFILE_URL, newProfile, { headers: { 'x-auth-token': getState().auth.user.token } }) dispatch(profileActions.setProfile(data)) dispatch(profileActions.setIsProfileCreated()) localStorage.setItem('profileData', JSON.stringify(data)); setTimeout( () => dispatch(profileActions.clearIsProfileCreated()), 2000 ); } catch (error) { const err = error.response?.data.msg if (err) { dispatch(alertActions.createAlert(err)); dispatch(alertActions.clearAlert(err)); } const errors = error.response.data.errors errors?.forEach((err) => { dispatch(alertActions.createAlert(err.msg)); dispatch(alertActions.clearAlert(err.id)); }); dispatch(profileActions.clearLoading()) } } } ثانياً ، عند بدء التطبيق، يمكنك التحقق مما إذا كانت هناك بيانات مخزنة واستخدامها , يمكنك وضع الكود التالي في layout او component الصفحة الاساسية . useEffect(() => { const storedData = localStorage.getItem('profileData'); if (storedData) { dispatch(profileActions.setProfile(JSON.parse(storedData))); } }, []); الطريقة الثانية , تسمى هذه التقنية redux persist , هي مكتبة تساعد في حفظ حالة التطبيق في تطبيقات React Redux عبر عملية التخزين المحلي. تسمح هذه المكتبة بالاحتفاظ بحالة Redux الحالية حتى بعد إعادة تحميل الصفحة أو إعادة فتح التطبيق عن طريق استخدام localStorage أو AsyncStorage في React Native.
    1 نقطة
  13. لا مشكلة في ذلك و بالتوفيق لك..
    1 نقطة
  14. تمام عفوا ما انتبهت على الرغم بس خلص الفيديو فكرت علقت تحته. عفوا ... شكرا
    1 نقطة
  15. مرحبا محمود أنت بالفعل تقوم بالإضافة إلى قاعدة البيانات وفى نفس الوقت تضيف فى المصفوفة ولكن عند تحديث الصفحة فى البداية لابد من جلب البيانات و إضافتها إلى المصفوفة ومن ثم إجراء العمليات على المصفوفة للقيام بهذه الإجراء اقترح عليك استخدام createAsyncThunk وهذه الدالة موجوده داخل الredux Toolkit لمعالجة العمليات الغير متزامنة في الأكشنز (actions) في Redux و تستطيع عن طريقها مشاركة البيانات التى تحصل عليها منAPI SERVER فى كل المكونات والوصول لها من أى مكون. وهذا مثال بسيط لاستخدامها import { createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; // تعريف ال async thunk export const fetchData = createAsyncThunk( 'data/fetchData', // نوع الأكشن async (arg, thunkAPI) => { try { const response = await axios.get('https://api.example.com/data'); return response.data; } catch (error) { // التعامل مع الأخطاء، يمكنك إرسال أكشن آخر أو إلقاء الخطأ return thunkAPI.rejectWithValue(error.message); } } ); // استخدام ال async thunk في الـ slice import { createSlice } from '@reduxjs/toolkit'; const dataSlice = createSlice({ name: 'data', initialState: { loading: false, data: null, error: null, }, reducers: {}, extraReducers: { [fetchData.pending]: (state) => { state.loading = true; state.error = null; }, [fetchData.fulfilled]: (state, action) => { state.loading = false; state.data = action.payload; }, [fetchData.rejected]: (state, action) => { state.loading = false; state.error = action.payload; }, }, }); export default dataSlice.reducer; حيث في هذا المثال: createAsyncThunk تنشئ async thunk action creator بإسم fetchData. يأخذ هذا المنشئ نوع الأكشن ('data/fetchData') ودالة غير مزامنة تقوم بأداء عملية مزامنة (هنا، طلب بيانات من API). createSlice تنشئ slice لتخزين الحالة (state) والأكشنز والريدوسيرز (reducers). extraReducers تعرف كيفية التعامل مع نتائج ال async thunk مثل (التعليق)pending, (الإكتمال)fulfilled, و(الرفض ) rejected. بالتوفيق..
    1 نقطة
  16. السلام عليكم هناك تطبيق سابق اعمل عليه انا حاليا، عند القيام ب npm install ثم npx react-native run-android اتلقى هذا الخطأ 1/ node_modules\react-native\react.gradle' as it does not exist 2/ A problem occurred configuring project ':app'. > compileSdkVersion is not specified. Please add it to build.gradle لم اجد الحل الانسب في النت على الرغم من قيامي بكل شيء. هل احدكم صادف هذا الخطأ او احدكم يمكنه المساعدة. شكرا.
    1 نقطة
  17. السبب حسب ماهو موضح في الخطأ فيبدو أن ملف react.gradle مفقود من مسار node_modules\react-native وبما أن المشروع قديم نوعا ما فيمكنك إعادة تثبيت React Native من خلال إزالته من مشروعك من خلال هذا الأمر: npm uninstall react-native react-native-cli يمكنك تجربة الحلول التالية لحل هذه المشكلة: ثم إعادة تثبيته باستخدام الأمر: npm install react-native react-native-cli لكن تأكد من استخدام إصدار Gradle متوافق مع React Native. يمكنك التحقق من إصدار Gradle المطلوب من خلال هذا الرابط هنا: في وثائق React Native ومن أن إصدار Gradle المحدد في ملف build.gradle (app) يتطابق مع الإصدار المثبت على جهازك. هذا الأمر سيساعد أيضا من خلال تنظيف Cache npm فقد تكون المشكلة منه في بعض الحالات، باستخدام الأمر: npm cache clean --force ثم قم بإعادة تثبيت React Native مرة أخرى ولا تنسى من التثبت من أن ملفات Gradle موجودة في المسار الصحيح. عادة ما تكون موجودة في android/app/build.gradle و node_modules/react-native/react/build.gradle. إذا كانت الملفات مفقودة، يمكنك محاولة تنزيلها من مستودع React Native على غيتهاب من هنا: مستودع React Native على Github
    1 نقطة
  18. هذه هي profileSlice const profileSlice = createSlice({ name: "profile", initialState: { profile: [], loading: false, isProfileCreated: false, }, reducers: { setProfile(state, action) { state.profile = action.payload }, setLoading(state) { state.loading = true }, clearLoading(state) { state.loading = false }, setIsProfileCreated(state) { state.isProfileCreated = true; state.loading = false }, clearIsProfileCreated(state) { state.isProfileCreated = false; }, addExperience(state, action) { state.profile.experience = action.payload } }, }); profileApiCall export function createProfile(newProfile) { return async(dispatch, getState) => { try { dispatch(profileActions.setLoading()) const { data } = await axios.post(PROFILE_URL, newProfile, { headers: { 'x-auth-token': getState().auth.user.token } }) dispatch(profileActions.setProfile(data)) dispatch(profileActions.setIsProfileCreated()) setTimeout( () => dispatch(profileActions.clearIsProfileCreated()), 2000 ); } catch (error) { const err = error.response?.data.msg if (err) { dispatch(alertActions.createAlert(err)); dispatch(alertActions.clearAlert(err)); } const errors = error.response.data.errors errors?.forEach((err) => { dispatch(alertActions.createAlert(err.msg)); dispatch(alertActions.clearAlert(err.id)); }); dispatch(profileActions.clearLoading()) } } }
    1 نقطة
  19. إذا كنت تستخدم Redux Toolkit لإدارة الحالة الخاصة بالتطبيق الخاص بك وتقوم بإضافة البيانات محليًا دون الرجوع إلى واجهة برمجة التطبيقات (API) أو التخزين المحلي، فسيتم فقدان البيانات عند تحديث الصفحة أو إعادة تحميلها. لحل هذه المشكلة، يجب عليك البحث عن طرق للحفاظ على البيانات المضافة محليًا بين جلسات التصفح. يمكن القيام بذلك عن طريق استخدام التخزين المحلي مثل LocalStorage أو IndexedDB للحفاظ على البيانات على مستوى المتصفح. في Redux Toolkit، يمكنك استخدام middleware مثل redux-persist لتحقيق هذا الغرض. يقوم redux-persist بتخزين حالة Redux في التخزين المحلي بطريقة تلقائية، مما يسمح باستعادة حالة التطبيق عند إعادة تحميل الصفحة. في النهاية، يمكنك استخدام المصفوفة المحلية كحالة افتراضية في Redux، ثم استخدام redux-persist للحفاظ على هذه البيانات بين جلسات التصفح. هذا يسمح لك بالاستفادة من قوة Redux في إدارة الحالة مع الحفاظ على البيانات المهمة عبر عمليات إعادة التحميل وإغلاق المتصفح. يمكنك تصفح هذه المصادر:
    1 نقطة
  20. بما أنك تستخدم Redux Toolki لإدارة الحالة الخاصة بالموقع وفى بادئ الأمر لم تحصل على بيانات المصفوفة من الواجهة البرمجية API SERVER أو من خلال التخزين المحلى localstorage مثلا وتقوم بالإضافة بنفسك إلى المصفوفة وهذا كله يتم على المتصفح ولا تضيف إلى المصفوفة فى قاعده البيانات أو التخزين المحلى فبالتأكيد عند عمل تحديث للصفحة تكون المصفوفة فارغة.
    1 نقطة
  21. 1 نقطة
  22. أنت بحاجة إلى تفعيل نسخة الويندوز وذلك بشراء كود للتفعيل بطريقة قانونية وستجد تفصيل هنا: ولا مشكلة في تركها بدون تفعيل، فالقيود التي يتم فرضها للنسخ الغير مفعلة ليست مؤثرة على عمل النظام، حيث سيتم منعك من التالي: ستظهر علامة مائية مزعجة على سطح المكتب تُشير إلى عدم تفعيل النسخة. لن تتمكن من تغيير لون خلفية سطح المكتب أو شاشة القفل أو غيرها من العناصر الشخصية. ستظهر لك إشعارات منتظمة تُذكّرك بتفعيل النسخة. تتوقف بعض التحديثات الأمنية المهمة عن العمل. لن تتمكن من استخدام بعض الميزات المتقدمة مثل "Hyper-V" و "Windows Defender Device Guard".
    1 نقطة
  23. تظهر رسالة "Activate Windows" على شاشة الكمبيوتر الذي يعمل بنظام التشغيل Windows عند عدم تنشيطه. ستختفي بمجرد تفعيلك وتنشيطك له، والتنشيط هو عملية التحقق من صحة نسخة Windows المثبتة على جهاز الكمبيوتر والتأكد من أنها مرخصة بشكل صحيح، بعد التفعيل سيتم إزالة علامة "Activate Windows" المزعجة من الشاشة مع الوصول إلى جميع ميزات Windows وستتلقي تحديثات الأمان المهمة من Microsoft. كما أنك ستتجنب القيود التي تفرضها Microsoft على النسخ غير المنشطة من Windows، مثل تقييد تغيير سمة سطح المكتب، وتقييد تخصيص شاشة القفل، وتقييد استخدام بعض الميزات المتقدمة. بالنسبة للطرق المتبعة لتنشيط Windows يمكنك استخدام مفتاح المنتج إذا كان لديك مفتاح منتج Windows، يمكنك استخدامه لتنشيط Windows من خلال الخطوات التالية: الضغط على زر البدء. حدد الإعدادات. انتقل إلى النظام. حدد التنشيط. انقر فوق تغيير مفتاح المنتج. أدخل مفتاح المنتج الخاص بك وانقر فوق تالي. اتبع التعليمات التي تظهر على الشاشة. وهذه بعض المصادر المفيدة: دعم Microsoft لتنشيط الوينداوز و تنشيط الوينداوز. يمكنك الاطلاع على هاته المقالة أيضا التي توضح كيفية التفعيل:
    1 نقطة
  24. بالفعل، من الصعب جدّا (أو لنقل من شبه المستحيل) أن تكون هناك دورة تعليمية تدرّسك كلّ ما تحتاج تعلّمه في مجال ما. دورة تطوير التطبيقات بلغة JavaScript (والتي يتم تدريس React JS فيها) ليست استثناء من هذه القاعدة. لذلك، فالجواب هو أنه لا يمكنك أن تكتفي بمتابعة محتوى الدورة فقط وتفترض أن هذا كاف للاشتغال في سوق العمل. بالطبع، سوف تحتاج إلى قراءة توثيق React مرّة واحدة على الأقل بعد أو أثناء دراستك للمسار. وسيكون من الأحسن لو تحاول أن تبدع قليلا خارج ما يقوم به المدرّب، إذ أنّه كلّما حاولت الاعتماد على نفسك أكثر كلّما زاد استيعابك للمعلومات وتحسنت فرصك للنجاح فيما بعد في ميدان عملك. لذلك، حاول أن تستثمر أقصى ما تستطيع من الوقت من أجل تحسين مهاراتك، حتى بالمواد الموجودة خارج الدورة. قد تجد معلومات مفيدة أيضا في مقالات أكاديمية حسوب: https://academy.hsoub.com/programming/javascript/react/ وأيضا من التوثيق المتوفّر على موسوعة حسوب: https://wiki.hsoub.com/React
    1 نقطة
  25. السلام عليكم ده المسائل Rock Paper Scissors Let's play! You have to return which player won! In case of a draw return Draw!. وده الاحل بتاعي def rps(p1 , p2): if p1 == 'Rock' and p2 == 'Scissors' or p1 == 'Scissors' and p2 == 'Paper' or p1 == 'Paper' and p2 == 'Rock': return 'Player 1 win' elif p2 == 'Rock' and p1 == 'Scissors' or p2 == 'Scissors' and p1 == 'Paper' or p2 == 'Paper' and p2 == 'Rock': return 'Player 2 win' else: return 'Draw!' print(rps('Rock' , 'Rock')) وده السوال هل يوجد حل افضل من كده في المسائل ده
    1 نقطة
  26. شكرااا جدا لحضرتك جزاك الله كل خير باذن الله
    1 نقطة
  27. كتابة الأكواد الجيدة والنظيفة هي مهارة يكتسبها المبرمج من خلال التعوّد على مجموعة من المبادئ والمعارف والقواعد التي تبيّن الكود النظيف من غيره، فمن الطبيعي أن تكون البدايات صعبة وغير جيدة، ثم مع الوقت ستكتسب المهارة، المهم أن تركز على كتابة الأكواد الصحيحة منطقيا والتي لا تؤثر على الوظيفية، ثم يمكنك تحسينها بالتوازن مع الكتابة النظيفة للأكواد. يمكنك تصفّح هذه المقالة للتعرف أكثر على فحوى الكود النظيف وكيفية كتابته:
    1 نقطة
  28. ماشاء الله شكرااا لحضرتك بس عند سوال كمان لو سمحت هو عند كتاب الكود هل يفضل ان اكتب الكود في افضل شكل ممكن في وقتها والا مع الاقت والتطوير هكون الكود افضل ؟
    1 نقطة
  29. يجب أن تعرف بأنه لا يوجد حل وحيد في المسائل البرمجية، فكل مبرمج يمكن أن تكون الشيفرة الخاصة به صحيحة ومنطقية، الشيفرة الخاصة بك تؤدي المطلوب لكن يمكن تحسينها من خلال استخدام هيكل أكثر تنظيما وإدارة الشروط بشكل أكثر فعالية بهذا الشكل مثلا: def rps(p1, p2): # Dictionary to define the winning scenarios win_conditions = {'Rock': 'Scissors', 'Scissors': 'Paper', 'Paper': 'Rock'} if p1 == p2: return 'Draw!' elif win_conditions[p1] == p2: return 'Player 1 wins!' else: return 'Player 2 wins!' # اختبار الدالة print(rps('Rock', 'Rock')) هنا قمت بإنشاء قاموس يحتوي على العلاقة بين كل شكل من أشكال اللعبة (حجر، ورقة، مقص) والشكل الذي يفوز عليه، على سبيل المثال، في القاموس win_conditions، إذا كان الشكل الأول "حجر"، فإن الفائز سيكون "مقص"، وهكذا. وبدلا من استخدام مجموعة كبيرة من الشروط المتداخلة، حددت شرطين رئيسيين: إذا كان الشكلان متساويان، فهو تعادل (Draw). إذا كان الشكل الذي اختاره اللاعب الأول يفوز على الشكل الذي اختاره اللاعب الثاني، فإن اللاعب الأول يفوز، والعكس صحيح. يمكنك الاطلاع أكثر على هاته المقالة للاستفادة أكثر:
    1 نقطة
  30. جيد جدا، أتمنى إرفاق الملف وسأرى ما يمكن فعله، يمكنك إرفاق مشروعك المصدري أيضا إن أردت.
    1 نقطة
  31. خلاص شكرا يا بشمهندس ياسر تم حل المشكله اشكرك جدا علي مساعدت حضرتك بس هو ممكن ابعتلك الكود وانت تختصره لان الكود كبير جدا علي المطلوب
    1 نقطة
  32. وعليكم السلام , يجب عليك وضع كلاس acc-title كالتالي : .acc-title { display: flex; align-items: center; justify-content: center; } ليتم وضع جميع العناصر بداخله على سوية واحدة , مثلاً ممكن أن يكون الكود كاملاً كالتالي ( يمكنك إرفاق كامل الكود مع styles الخاصة به للتوضيح أكثر ) : <!DOCTYPE html> <html> <head> <title></title> <style> .acc-tool1 { background-color: red; text-align: center; } .acc-title { display: flex; align-items: center; justify-content: center; } .author-img2 { margin-right: 10px; border-radius: 100px; } .acc-title i { margin-left: 10px; padding: 40px } </style> </head> <body> <div class="acc-tool1"> <div class="acc-item"> <div onclick="window.open('https://youtube.com/@khatar_official');"> <div class="acc-title"> <div class="author-img2 radius100px"><img height="40" width="40" src="https://blogger.googleusercontent.com/img/a/AVvXsEjcnncOCeoSzijTrJkMRofEAfTbPHxMi4YRNkhAP8PUuNIvaoKioud-tHURilzjXIi6heOrfmVKMhJ71oqD5p3hPsKq9kwmuHsoyxS1B9dequ8talfFmNV62QMWbLHtpF2b45moj_hB1EOAf1RMqtx2zzXRWGbMeQC5EXsFAtRmi76Uv55cxGazBhhoKDaI=s1600" /> </div> اشترك في قناتي علي اليوتيوب <i class="fab fa-download" style="color: white; font-size: 18px; font-weight: 400;"></i> </div> </div> </div> </div> </body> </html>
    1 نقطة
  33. يمكنك إضافة الأمر "vertical-align: middle;" إلى الصورة لتوسيطها داخل العنصر من خلال إضافة الخاصية مباشرة إلى الصورة في علامة الصورة بهذا الشكل: <img border="0" data-original-height="1949" data-original-width="3464" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEjcnncOCeoSzijTrJkMRofEAfTbPHxMi4YRNkhAP8PUuNIvaoKioud-tHURilzjXIi6heOrfmVKMhJ71oqD5p3hPsKq9kwmuHsoyxS1B9dequ8talfFmNV62QMWbLHtpF2b45moj_hB1EOAf1RMqtx2zzXRWGbMeQC5EXsFAtRmi76Uv55cxGazBhhoKDaI=s1600" width="320" style="vertical-align: middle;" /> قم بتجربته وأخبرني بالنتيجة.
    1 نقطة
  34. وعليكم السلام , دورة حياة أي مشروع برمجي تكون تحت مسمى SDLC وهي مجموعة مراحل يجب تنفيذها لبناء المشروع البرمجي بشكل صحيح ( كما تم شرحه من قبل المدرب عدنان ) , أما عن تنفيذ هذه المراحل فيكمن من خلال نماذج دورة حياة تطوير المشروع البرمجي SDLC Models ويوجد عدة نماذج لدورة حياة تطوير البرمجيات , كل نموذج له مزاياه وعيوبه ويناسب أنواع مختلفة من المشاريع والظروف : نموذج الشلال (Waterfall Model) هذا النموذج يتبع نهجا خطيا حيث تتقدم المراحل بتتابع وتباعد ثابت. تبدأ المراحل بالتحليل والتصميم وتنتهي بالتطوير والاختبار ثم التشغيل. يناسب المشاريع ذات المتطلبات الثابتة والمعروفة بوضوح. نموذج التطوير التسلسلي (Sequential Development Model) يشبه نموذج الشلال إلى حد كبير ولكن يسمح بتكرار المراحل إذا لزم الأمر. يمكن تكرار مرحلة معينة بعد اكتشاف العيوب في المراحل اللاحقة. يمكن أن يكون أكثر مرونة من نموذج الشلال ولكن قد يزيد من تكاليف التطوير النموذج التكراري (Iterative Model) ينشئ التطبيق في سلسلة من الدورات القصيرة المتكررة. كل دورة تنتهي بتسليم تطبيق يضيف ميزات جديدة أو يصحح العيوب ( أي يتم تسليم version ثم version اخر ). يسمح بتغيير المتطلبات والتحسين المستمر. النموذج التكراري التكيفي (Adaptive Iterative Model) يجمع بين النموذج التكراري والتحديد التكيفي. يتم تحديد الخطوات القادمة بناءً على الاستجابة للتغييرات التي تطرأ خلال التطوير. النموذج الرشيق (Agile Model) يركز على التعاون بين فريق التطوير والعملاء. يسمح بالتطوير التدريجي والتحسين المستمر عبر الدورات القصيرة والمرنة. يناسب المشاريع التي تتطلب استجابة سريعة للتغييرات والتكيف مع المتطلبات المتغيرة. يوجد عدة نماذج أخرى , لكن هذه أشهرها ولا أظن أنك ستحتاج إلى غيرها إلا في بعض الحالات النادرة. أيضاً غالب المشاريع في الشركات تعتمد على Agile Model , فهي مناسبة لمشاريع كبيرة وربما تكون متطلباتها غير واضحة بشكل كامل في البداية. وتعتبر الأكثر شهرة ( هذا لا يعني أنه لا يوجد مشاريع تعتمد على النماذج الأخرى ).
    1 نقطة
  35. بجانب ما اقترح مصطفى يمكنك أيضا التعديل على قيمة متغير الحالة notes - خصوصا وأنها قيم اختبارية: const [notes, setNotes] = useState([ { id: 1, text: "test", date: (new Date()).toLocaleString(), }, { id: 2, text: "test", date: (new Date()).toLocaleString(), }, { id: 3, text: "test", date: (new Date()).toLocaleString(), }, ])
    1 نقطة
  36. السلام عليكم اريد اضافة زر عند الضغط عليه تخرج نافذه بها التفاصيل الزر هو عبارة عن علامه + ف قسم works فقمت باستعمال ال model من bootstrap ولكن تظهر معي هذه المشكلة وهل يوجد طريقه ابسط لعمل ذلك بدون ال model جربت pure js ولكن تظهر النافذة ضمن ال works وتحدث مشاكل قمت بارفاث صورة للتوضيح portfolio.zip
    1 نقطة
  37. مراحل هندسة البرمجيات والتي يختصر لها بـ SDLC اختصارا عن Software Development Life Cycle غالبا ما تتبع منهجا موحدا وهو كالتالي: البحث والتخطيط Planning & Analaysis: ويتم فيه هاته المرحلة تحليل متطلبات العميل وفهمها وتحديد مختلف احتياجات المشروع من تجهيزات بشرية ومادية وكذلك بناء مخططات حالات الاستخدام وقصص المستخدمين وما الى ذلك .. التصميم Design: في هاته المرحلة يتم بناء مختلف واجهات الاستخدام وتخريجها كتصميم UI/UX .. التطوير Development: يتم تسليم مختلف التصاميم والمخططات لفرق التطوير للعمل على التطبيق وبناءه ويشمل ذاك تطوير الواجهات الأمامية والخلفية. الاختبار Testing: يتم تقديم ناتج المرحلة السابقة لفرق الاختبار لاختبار مختلف حالات الاستخدام التي تم تحديدها في المرحلة الأولى، ويتم التأكد من استيفاءها للغرض إما بشكل مؤتمت Automated أو بشكل يدوي من وجهة نظر المستخدم النهائي end user perspective .. النشر والتكامل Deployment & Integegration: يتم هاهنا نشر التطبيق والتأكد من تكامله مع مختلف البيئات المستهدفة التي سينشط فيها. الصيانة والمتابعة Maintenance: بعد نشر التطبيق يتم متابعته بشكل دائم لصيانة أي أعطال أو التخلص من أي مشاكل .. وقد يتم تقديم بعض هاته المراحل أو دمجها في بعض الأساليب البرمجية من مثل أسلوب TDD أين يتم دمج مرحلة الاختبار مع التطوير أو BDD أو غيرها .. وكل ذاك بحسب مرونة المشروع أو بحسب النهج المستخدم مثل نهج Agile..
    1 نقطة
  38. المشكلة لديك هي في محاولة عرض كائن التاريخ كما هو بالشكل التالي في مكون Note: <small>{date}</small> لاحظ أنك تقوم بتمرير كائن new Date() ولا يمكن عمل render للكائن بدون تحويله إلى تاريخ نصي، وذلك ممكن من خلال دالة toDateString، كالتالي: <small>{date.toDateString()}</small>
    1 نقطة
  39. تحديد المتطلبات من خلال التحدث مع العميل : في هذه الخطوة تقوم بسؤال العميل ماهي المتطلبات التي يردها في مشروعه وتدوينها بمكان ما ثم تحليلها اي على سبيل المثال ان كان يريد عمل متجر الكتروني ستسفسره منه ما الذي يريد عرضه بالتفصيل هل هناك انواع لبضاعته ان كان كذلك فأن بحاجة لانشاء اكثر من نوع او سؤاله ان كان هناك شروط اي ان هناك اشتراك شهري للعميل او ان له كمية محددة يمكنه طلبها خلال شهر واحد او غير ذلك اي باختصار يجب سؤاله عن جميع ما يريده وشروط عمله بالتفصيل لتحويلها لمشروع برمجي تصميم UI UX بالتعاون مع مصمم : في هذه الخطوة تقوم بتصميم نماذج حسب ما يريد العميل وارسالها له وسؤاله ان كان يحتاج الى اي تعديلات ثم بعد الاتفاق على التصميم المطلوب تبدأ المرحلة التالية برمجة frontend + backend : هنا تقوم بتحويل التصميم الذي تم الاتفاق عليه الى كود برمجي بأستعمال ال frontend ثم ستقوم بتحويل متطلبات العميل والشروط التي تم الاتفاق عليها الى كود برمجي باستخدام ال backend ولكن قبل العمل بالجزء الخلفي يجب عليك الانتباه الى خطوة مهمة جدا والتي هي تنسيق جداول قاعدة البيانات : هنا ستبدأ بدراسة مشروعك ماهي الجداول التي انت بحاجة اليها وكل جدول ماذا يحتوى بيانات وماهي العلاقة بين الجداول كما انه هناك طريقة فرنسية تدعى Merise والتي هي اختصار ل methodology of analysis والتي هي عبارة عن خطوات بدأ من دراسة المشروع وتنتهي بعمل الجداول والعلاقة بينها ممكن ان تكون مفيدة جدا حيث انها مبنية على خطوات منظمة تسهل عملك testing : بعد الانتهاء من التطبيق ستعرضه لفترة تجريبية لاختبار تجربة المستخدم عليه ان كان هناك اي ملاحظات او مثلا صفحات صعبة الفهم بحاجة الى تعديلها وتذكر دائما عند عمل اي تطبيق عليك التفكير بطريقة تدعى stupid user وهي بمعنى المستخدم الغبي والتي تهدف الى انشاءك تطبيق يكون سهل الاستخدام وليس بهي اي تعقيدات بحيث ان جميع المستخدمين يمكنه فهم التطبيق والتعامل معه وتذكر دائما ان افضل تطبيق هو الذي يجمع بين سهولة الاستخدام وكثرة المميزات نشر التطبيق : هذه هي الخطوة الاهم بحيث ان لا داعي للتطبيق ان لم يتم نشره والاستفاده منه وتأتي حسب ماهي التقنيات لتي تستخدمها ف مثلا تطبيقات الهاتف لها طريقة في النشر والمواقع الاكترونية لها طريقة والى اخره... وبعد نشر التطبيق هناك خطوة مهمة والتي هي المراجعة والصيانة الدائمة له بحال حصل به اي مشاكل او كان بحاجة الى اضافات وبالتوفيق لك ...
    1 نقطة
  40. ما هو المستوى الذي وصلت إليه، أي ما هي التقنيات التي تعلمتها من البداية وحتى الآن مع ذكر اللغات التي تعلمتها فهي الأساس وليس التقنيات، ثم ما المشاريع التي قمت بها وما هو المسار البرمجي الذي تنوي التخصص به؟
    1 نقطة
  41. مصطلح إطار العمل أو الفريم وورك Framework يعد أحد المصطلحات الفنية والبرمجية التي تربك المبتدئين على وجه الخصوص في بداية مشوار تعلم البرمجة والتي لا يستطيع فهم دلالتها ولا إدراك مدى أهميتها بشكل جيد. وكثيرًا ما يتساءل المبرمج المبتدئ عن معنى إطار العمل Framework وعن مزايا ومحدويات استخدام أطر العمل Frameworks في عمله البرمجي وعملية البرمجة عمومًا، وهل يتوجب عليه تعلم إطار عمل للغة برمجة محددة، أم أن تعلمه للغة البرمجة نفسها يكفيه في سوق العمل، وهل تعلم إطار العمل صعب ويستغرق وقتًا، ومالفرق بين إطار العمل والمكتبة، وغيرها من الأسئلة من هذا القبيل. فإذا كنت مهتمًا بعرفة الإجابة على كل هذه التساؤلات فتابع قراءة هذا المقال للنهاية. ما هو إطار العمل Framework؟ إطار العمل Framework في البرمجة هو ببساطة آلية يتم من خلالها إعداد وتجهيز كافة الوظائف الضرورية والشائعة التي تستخدم بكثرة عند تطوير التطبيقات والأنظمة وإتاحتها للمبرمج ليستخدمها ويستفيد منها في عمله دون أن يحتاج لإعادة كتابة هذه الوظائف بنفسه من الصفر وبهذا نستنتج أن استخدام إطار العمل يختصر الكثير من الوقت ويجعل العمل البرمجي أكثر كفاءة. لتفهم الأمر بصورة أفضل تخيل أنك تحتاج لكتابة سيرتك الذاتية، سيكون أمامك خياران إما أن تفتح مستندًا فارغًا وتبدأ بكتابة كل شيء وتنسيقه بنفسك من الصفر، أو تعتمد على قالب جاهز للسيرة الذاتية يكون مقسمًا ومنسقًا وكل ما عليك هو ملء البيانات الضرورية الخاصة بك فقط دون أن تشغل بالك بالكثير من التفاصيل الأخرى سيكون الخيار الثاني أفضل وأسرع بالتأكيد. يساعدك إطار العمل في مشروعك البرمجي بطريقة مشابهة فهو يعمل كقالب أو هيكل أساسي عليك الالتزام به لإنشاء التطبيقات الخاصة بك، ويوفر لك مجموعة من الأدوات أو المكونات أو الحلول البرمجية الجاهزة لبناء تطبيقات مخصصة بطريقة آمنة وسريعة ومنظمة. ستجد الكثير من أطر عمل لكل لغات البرمجة الشائعة مثل جافاسكريبت وبايثون و PHP وجافا، ومن أجل استخدام أي إطار منها عليك بداية تعلم كيفية تطوير المشاريع في كل إطار منها والاستفادة من التسهيلات الكثيرة التي توفرها لك هذه الأطر. ما الفرق بين إطار العمل والمكتبة؟ كثيرًا ما يتم الخلط بين مفهوم إطار العمل Framework ومفهوم مشابه له في البرمجة وهو المكتبة Library ورغم التشابه بينهما في طريقة العمل واستخدامهما بالتبادل في بعض الأحيان، إلا أن مفهوم المكتبة أبسط وأكثر محدودية فالمكتبة تركز على توفير وظيفة محددة في حين يوفر إطار العمل مجموعة متكاملة من الميزات التي تمكنك من برمجة تطبيقات في مجال محدد. تُعرَّف المكتبة بأنها عبارة عن مجموعة من التعليمات البرمجية المختبرة القابلة لإعادة الاستخدام والتي تنفذ وظيفة معينة وتحل مشكلة محددة، في حين ينفذ إطار العمل حزمة وظائف متكاملة أو يوفر مخططًا عامًا لبناء التطبيقات في حين لا توفر المكتبات هذه الميزة كما تحدد أطر العمل قواعد وإرشادات كتابة التعليمات البرمجية الخاصة بك وتنظم الملفات والمجلدات الخاصة بمشاريعك، ويمكن أن تتضمن مجموعة من المكتبات وتستخدمها لتنفذ مهام معينة. على سبيل المثال من بين المكتبات الشائعة نذكر مكتبة ريآكت React وهي مكتبة برمجية مبنية بلغة جافاسكربت ومتخصصة في بناء واجهات المستخدم ومكتبة jQuery التي تختصر العديد من الأكواد والتعليمات البرمجية المكررة في جافا سكريبت لتسهيل عملية البرمجة، ومن بين أطر العمل الشائعة نذكر أنجولار Angular وفيو Vue.js وهما إطارا عمل بلغة جافا سكريبت مختصان في تصميم واجهات مواقع الويب. ما الفرق بين إطار العمل ولغة البرمجة؟ يمكن للمطور أن يستخدم لغة البرمجة ويكتب كافة التعليمات البرمجية اللازمة لبناء التطبيقات من الصفر كما يمكنه إن شاء الاستعانة بإطار عمل Framework مخصص لتطوير برامجه وتطبيقاته. ورغم أن استخدام إطار العمل يفيد المطورين ويسرع وتيرة عملهم، إلا أنه يحد من حريتهم في كتابة التعليمات البرمجية ويقيد إمكانيات التطوير ويمكنهم من بناء تطبيقات لأغراض محددة فقط، في حين أن استخدام لغة برمجة يمكنهم من تطوير ما يشاؤون من تطبيقات متنوعة، حتى إطار العمل نفسه تم بناؤه في النهاية بإحدى لغات البرمجة. باختصار لغة البرمجة هي الأساس ومن خلال تعلمها يمكنك بناء ما تشاء من تطبيقات، أما إطار العمل فهو مصمم لنوع محدد من التطبيقات مثل تطبيقات الويب أو تطبيقات الجوال أو تطبيقات علم البيانات أو الذكاء الاصطناعي وإنترنت الأشياء …إلخ ويفضل أن تتعلم استخدامه بعد أن تتعلم البرمجة وتتمكن من أساسياتها. أهمية إطار العمل في البرمجة تبرز أهمية إطار العمل framework بشكل أساسي في كونه يتيح لك إعادة استخدام التعليمات البرمجية بدلًا من إعادة كتابتها من جديد، وفيما يلي جملة من الفوائد التي يمكن أن يوفرها استخدام إطار العمل: يساعد على توفير كود أكثر أمانًا لكونه يتضمن شيفرات تتحقق من المصادقات والصلاحيات وتحمي تطبيقك من الاختراق وتعالج الكثير من الثغرات الأمنية الشائعة مثل CSRF و XSS و SQL Injection. تركيز الجهود على كتابة التعليمات البرمجية الخاصة بالمشروع فقط بدلًا من برمجة وظائف متكررة وشائعة الاستخدام. توحد أنماط وقواعد كتابة التعليمات البرمجية وتوفر مخططًا عامًّا يمكن لكافة الفرق البرمجية فهمه بسهولة. يساعد في تطوير مشروعك وإضافة ميزات جديدة له بسهولة دون الحاجة للتعديل على الكود الأساسي لإطار العمل. يغني عن إعادة اختراع العجلة ويوفر لك الوقت والتكلفة اللازمين لتطوير المشاريع والتطبيقات. يساعد في كتابة كود نظيف وغير مكرر. يسهل عملية اختبار الكود وتصحيح الأخطاء البرمجية. يقلل بالعموم من كمية الأخطاء البرمجية لأنك ستكتب كود أقل وبالتالي ستنتج لديك أخطاء برمجية أقل. محدوديات إطار العمل لا شكَّ أن استخدام إطار العمل يفيدك كمطور ويساعدك على تسريع وتحسين العمل البرمجي، إلا أن الاعتماد على أطر العمل وحدها يفرض عليك بعض القيود وإليك أبرزها: يوفر وظائف محددة ويختص في بناء تطبيقات في مجالات معينة فقط. الاعتماد عليها قد يعيق المبرمج من فهم لغات البرمجة بشكل متعمق وواضح. بعض أطر العمل معقدة ويستغرق تعلمها وفهمها بشكل جيد وتطوير التطبيقات باستخدامها الكثير من الوقت. نحتاج إلى اختيار إطار العمل المناسب للتطبيق فاختيار الإطار غير الملائم قد يؤثر سلبًا على أداء تطبيقاتك وتجربة المستخدمين. تصدر لها تحديثات جديدة بشكل دوري، لذا سيتوجب عليك البقاء على اطلاع دائم على كل جديد ومعرفة كل الميزات الجديدة المضافة للإطار والمميزات التي تم الاستغناء عنها في كل إصدار. توقف تحديث إطار العمل أو تغيره ينعكس على سير عملية تطوير التطبيق المبرمج فيه وأمانه مثلما حصل مع إطار العمل AngularJS عندما قررت غوغل التوقف عن تطويره وإطلاق نسخة عنه مختلفة تمامًا. صفات إطار العمل الجيد تتوافر عشرات أطر العمل في المجالات البرمجية المختلفة الأمر الذي يشعرك بالحيرة في تحديد الإطار الأفضل لمشروعك ويجعلك تتساءل كيف أختار إطار العمل المناسب؟ بالعموم يتصف إطار العمل الجيد بثلاث صفات أساسية وهي: التوثيق الجيد توفير الوظائف المطلوبة لعملك الشهرة والدعم المجتمعي لنوضح بمزيد من التفصيل كل صفة من هذه الصفات وأهميتها في اختيار إطار العمل الأفضل. التوثيق الجيد اختر إطار عمل موثقًا بشكل جيدًا كي تتمكن من العودة إليه عندما تحتاج لمعرفة المزيد من المعلومات حول استخدام ميزة معينة أو حل مشكلة تواجهك في استخدامه، فالتوثيق الجيد يوفر عليك الكثير من الوقت والجهد. توفير الوظائف المطلوبة لعملك ضع في اعتبارك أن لكل إطار عمل حدود معينة لذا من الضروري أن تبحث بشكل جيد في ميزات الإطار الذي تريد اعتماده وتتأكد من أنه يلبي متطلبات مشروعك ويحقق لك كافة الوظائف والميزات التي تحتاج لتحقيقها بالشكل الأنسب، وبنفس الوقت لا تختر إطار عمل شديد التعقيد أو مكتظًا بالميزات التي قد لا تحتاجها على الإطلاق! الشهرة والدعم المجتمعي لاشك أن شهرة إطار العمل ووجود مجتمع داعم له يدل على قوته والطلب الكبير عليه في سوق العمل، لذا احرص على استخدام إطار عمل معروف وله قاعدة مستخدمين نشطة ويفضل بعض المبرمجين الاعتماد على أطر عمل حرة ومفتوحة المصدر وغير مقيدة أو مدعومة من شركات معينة لتخوفهم من انعكاس أي طارئ يحصل لها أو تغير في سياستها على إطار العمل. ولذلك السبب ترى البعض يميل إلى استخدام إطار العمل Vue.js الذي انبثق من أروقة المجتمع الحر بدلًا من إطار العمل Angular الذي ولد بين أروقة شركة غوغل مثلًا، ولكن هنالك طرف مقابل يشير إلى تنظيم وقوة وسرعة تطوير أطر العمل التي تقف خلفهم الشركات نظرًا لدعمهم السخي طويل الآجل عادةً خصوصًا إن وقفت شركات تقنية كبيرة خلفهم والحديث يطول في هذه النقطة وهي خارج موضوع المقال فقط أحببت الإشارة إليها نظرًا لأهميتها في أي نقاش يدور حول المفاضلة بينها. أنواع أطر العمل frameworks في البرمجة هناك عدة أنواع من أطر العمل حيث يختص كل إطار بمجال استخدام معين، وفيما بعض أهم أنواع أطر العمل حسب التطبيقات أو الوظائف التي يؤديها: 1. أطر عمل تطوير الويب Web development frameworks تستخدم هذه الأطر في تطوير تطبيقات الويب ومن أشهرها إطار عمل أنجولار Angular وفيو جي إس Vue.js وهي أطر عمل جافا سكريبت شائعة تستخدم لتطوير الواجهات الأمامية للويب، وإطاري عمل إكسبرس Express و NestJS وهي أطر عمل Node.js لتطوير الواجهات الخلفية للويب، وإطاري عمل جانغو Django وفلاسك Flask وهي أطر عمل مفتوحة المصدر مكتوب بلغة بايثون مخصصة لتطوير الواجهات الخلفية للويب، وإطار عمل Ruby on Rails الذي يوفر لك كل ما تحتاجه لإنشاء تطبيق ويب بسهولة وسرعة وأمان وإطار عمل لارافيل Laravel المبني بالاعتماد على لغة PHP. 2. أطر عمل تطوير الجوال Mobile development frameworks من أشهرها في تطوير تطبيقات الجوال نذكر إطار عمل React Native مفتوح المصدر مكتوب بلغة جافا سكريبت طورته فيسبوك لتطوير تطبيقات جوال متوافقة مع كافة الأنظمة الأساسية، وإطار أيونيك Ionic الذي يستخدم تقنيات الويب HTML و CSS وجافا سكريبت من أجل تطوير تطبيقات الجوال وهو يتكامل مع أطر تطوير الواجهات الأمامية مثل Angular و Vue، وإطار عمل فلاتر Flutter وهو إطار عمل مفتوح المصدر للغة دارت Dart من جوجل لتطوير تطبيقات الجوال وهو يدعم أنظمة iOS و Android ويحتوي على عناصر واجهة مستخدم قابلة للتخصيص بالكامل، وإطار عمل أباتشي كوردوفا Apache Cordova الذي يمكنك من تطوير تطبيقات هجينة للهاتف الجوال. 3. أطر عمل علم البيانات Data science frameworks تعرف هذه الأطر كذلك بأطر التعلم الآلي Machine Learning Frameworks وهي تساعد علماء البيانات على إنشاء نماذج تعلم آلي وتصميمها بشكل أسرع وأسهل واستخراج المعلومات المفيدة من مجموعات البيانات بالاستفادة من تقنيات البرمجة والذكاء الاصطناعي والتعلم الآلي. وهناك العديد من أطر عمل علم البيانات ومن ضمنها scikit-Learn و XGBoost و TensorFlow و PyTorch. 4. أطر إدارة المحتوى Content management frameworks تعرف أيضًا باسم نظم إدارة المحتوى Content Management Systems أو اختصارًا CMS هي برمجيات توفر مكونات قابلة لإعادة الاستخدام لإنشاء وإدارة محتوى الويب وعرضه ضمن مدونات أو مواقع إلكترونية أو تطبيقات جوال وهي توفر ميزات أخرى مثل سهولة الاستخدام وتحسين محركات البحث والأمان. ومن أشهر هذه النظم نذكر نظام ووردبريس WordPress الشهير المستخدم في إنشاء ما يقارب من نصف المواقع الإلكتروني ودروبال Drupal الذي يعد نظام مثالي لتطوير المواقع التي تحتوي على الكثير من المحتوى وهو يتطلب معرفة تقنية أكثر من بقية نظم إدارة المحتوى. 5. أطر عمل أتمتة الاختبار Test Automation frameworks يستخدم مطورو البرمجيات أطر عمل الأتمتة من أجل إنشاء حالات اختبار التطبيقات والتأكد من سير عملها بكفاءة وتوفر لهم أدوات وتوصيات للتحقق من جودة البرمجيات واتباع معايير الترميز المناسبة. من أشهر أطر الاختبار نذكر سيلينيوم Selenium وهو إطار مفتوح المصدر لأتمتة اختبار تطبيقات الويب، وCypress المبني بجافا سكريبت والمخصص لاختبار الواجهة الأمامية لتطبيقات الويب، و Playwright للاختبار الشامل لتطبيقات الويب. هل يمكن البدء باستخدام إطار العمل دون تعلم لغة البرمجة؟ لاشك أن إطار العمل يوفر لك كمطور أداة قيمة لتطوير البرامج التطبيقات المختلفة، لكن السؤال الذي يطرح نفسه هل يغني تعلم أطر العمل واستخدامها في بناء التطبيقات العملية عن تعلم لغات البرمجة وفهمها بشكل متعمق؟ في الواقع حتى لو لم تكن ترغب في تطوير التطبيقات بإحدى لغات البرمجة وتميل للاستفادة من ميزات أحد أطر العمل فلا غنى لك عن تعلم لغة البرمجة وفهم أساسياتها إلى جانب إطار العمل فكلما فهمت لغة البرمجة بشكل أفضل سيسهل عليك فهم أطر العمل. كما أن تعلّم البرمجة يوسع أفق عملك ويمكنك من بناء العديد من التطبيقات في مختلف المجالات، أما إطار العمل فهو مصمم كما ذكرنا سابقًا لغرض واحد فقط وبالتالي سيقيدك بنوع محدد من التطبيقات. ويمكن باختصار أن نلخص الإجابة على هذا السؤال بجملة واحدة: يمكنك استخدام أطر العمل، لكن قبل ذلك تعلم أساسيات لغة البرمجة واتقنها ثم استفد من ميزات إطار العمل الخاص بتلك اللغة كما يحلو لك. الخلاصة تعرفنا اليوم على مفهوم إطار العمل Framework ودوره المهم في توفير الوظائف القياسية وتحديد الخطوط العريضة التي تنظم المشاريع البرمجية وتوفر وقت وجهد المطورين والمبرمجين، واكشتفنا أهم الفروقات بين أطر العمل وبين أدوات تطوير البرامج الأخرى مثل المكتبات ولغات البرمجة، وتعلمنا طريقة اختيار أفضل إطار عمل يناسب متطلباتنا وعددنا أهم صفات إطار العمل الجيد، وأخيرًا استعرضنا قائمة بأهم أطر العمل المستخدمة في مجالات مختلفة كتطبيقات الويب وتطبيقات الجوال وغيرها من المجالات. هل تستخدم في عملك أحد أطر العمل التي وردت في سياق المقال أو أطر عمل أخرى؟ ما هو هذا الإطار وفي أي مجال تستخدمه؟ هل هناك أي مشاكل تواجهها في التعامل مع هذا الإطار أم أنك راضٍ عن أدائه. شاركنا تجربتك في التعليقات أسفل المقال. اقرأ أيضًا تعلم أساسيات البرمجة قواعد البرمجة ببساطة للمبتدئين أسهل لغات البرمجة مهندس البرمجيات من هو وما هي مهامه تعرف على تخصص هندسة البرمجيات
    1 نقطة
  42. تضم لغة HTML مجموعة كبيرة من العناصر التي تساعدنا على إضافة المحتوى إلى صفحة الويب وتنسيقه. ومن الضروري فهم طريقة عمل هذه العناصر وما هي الميزات والسمات التي يمكن استخدامها مع كل عنصر. في المقال التالي سنوضح الفرق بين عناصر Inline-level وعناصر Block-level، وكيفية ترتيب هذه العناصر في ملف المشروع، وكيفية إضافة السمات والخصائص الأساسية. كيفية استخدام عناصر Inline-level وعناصر Block-level في HTML عند ترتيب العناصر في ملف HTML، من المهم أن تدرك كيف تتوضع هذه العناصر في صفحة الويب، وما هي المساحة التي تشغلها. يمكن أن تشغل عناصر معينة مساحة على صفحة الويب أكبر من حجم المحتوى الذي تتضمنه. سيساعدك فهم سلوك أنواع العناصر المختلفة على توقع كيفية تأثيرها على موضع العناصر الأخرى على الصفحة. عمومًا يوجد نوعين مختلفين من عناصر HTML وهي عناصر Inline-level وعناصر Block-level. وكل نوع يشغل مساحة محددة من صفحة الويب. فيما يلي سنوضح كيف تحديد الإعدادات الافتراضية لهذه العناصر موضعها على صفحة الويب. عناصر Inline-level عناصر Inline-level هي العناصر التي يُحدد عرضها الأفقي وفقًا لعرض المحتوى الذي تتضمنه. على سبيل المثال العناصر <strong> و<em> التي تحدثنا عنها في الفقرات السابقة. يمكننا استخدام أداة مطوري الويب في المتصفح Firefox لفحص حجم عناصر HTML على صفحة الويب. وإذا كنت تستخدم المتصفح Chrome، فيمكنك استخدام أداة مطوري البرامج لنفس الغرض. ولكن هذا المقال سيقدم إرشادات حول أدوات مطوري الويب في المتصفح Firefox. سنجرب عرض هذه العناصر في متصفح الويب لتوضيح الفكرة. ولذلك انتقل إلى ملف index.html وافتحه في متصفح الويب. ثم انقر على زر خيارات في شريط القائمة العلوي وحدد "أدوات أكثر" لتظهر قائمة جديدة، حدد "أدوات مطوري الويب". وبالتالي ستظهر نافذة الفاحص التي تسمح لك بفحص عناصر HTML وCSS لصفحة الويب. بعد ذلك حرك المؤشر فوق عبارة وستلاحظ أن النص سيبرز باللون الأزرق الفاتح. يظهر هذا الظل المدى الكامل للمساحة التي يشغلها العنصر الذي يقف فوقه المؤشر. ويمكنك أن تلاحظ أن المساحة المشغولة للعنصر كافية لاحتواء محتواه النصي. على عكس عناصر Block-level لا تشغل عناصر Inline-level خط المساحة الأفقية الخاص بها. وبالتالي ستترتب عناصر Inline-level جنبًا إلى جنب على صفحة الويب إذا لم تضف عنصر HTML إضافي مثل عنصر فاصل السطر <br>. غالبًا ما يكون الحجم الافتراضي مناسبًا إذا كنت ترغب في تمييز كلمات مفردة في الفقرة، مثلًا يمكنك استخدام العنصر <em> لتمييز إحدى الكلمات في الفقرة بدون دفع النص التالي إلى سطر جديد. سنعود الآن إلى ملف index.html وسنضيف العنصر <br> بين سطري التعليمات. <strong>My strong text</strong> <br> <em>My emphasized text</em> لاحظ أن الوسم <br> لا يحتاج إلى وسم إغلاق. احفظ المستند وأعد تحميله في متصفحك للتحقق من النتائج. يجب أن تظهر الصفحة على النحو التالي: ستلاحظ فصل العبارتين في سطرين متتاليين بسبب استخدام عنصر فاصل السطر <br>. للتحقق من حجم العناصر استخدم أداة مطوري الويب في المتصفح Firefox، ستلاحظ أن عرض كل عنصر من عناصر النص لا يزال يتحدد من خلال عرض محتوى النص. إذا كنت تستخدم Firefox Web Developer Inspector للتحقق من حجم العناصر، فيمكنك تأكيد أن عرض كل عنصر من عناصر النص لا يزال يتحدد من خلال عرض محتوى النص: عناصر Block-level تختلف هذه العناصر عن عناصر Inline-level في أنها تشغل سطرًا كاملًا من المساحة الأفقية على صفحة الويب. هذا يعني أن هذه العناصر تبدأ تلقائيًا في سطر جديد وأنها تدفع العناصر اللاحقة إلى سطر جديد أيضًا. على سبيل المثال عناصر العنوان من <h1> إلى <h6> هي عناصر HTML من نوع Block-level، وهذه العناصر تضع محتواها تلقائيًا في سطر جديد وتدفع أي محتوى يتبعها إلى سطر جديد. يمثل كل عنصر من عناصر العناوين الستة حجم عنوان مختلف. سنوضح هذه الفكرة من خلال مثال عملي. انسخ التعليمات التالية والصقها في ملف index.html. <strong>My strong text</strong> <br> <em>My emphasized text</em> <h1>Heading 1</h1> <h2>Heading 2</h2> <h3>Heading 3</h3> <h4>Heading 4</h4> <h5>Heading 5</h5> <h6>Heading 6</h6> ثم احفظ الملف وأعد تحميله في المتصفح، وستظهر الصفحة التالية: الآن سنستخدم أداة الفاحص لدراسة كيفية توضع عناصر Block-level على الشاشة وما هو الاختلاف بينها وبين عناصر Inline-level. استخدم أداة مطوري الويب ومرر المؤشر فوق كل عنصر لفحص المساحة المشغولة والتي ستظهر مظللة باللون الأزرق. ستلاحظ أن المساحة الأفقية التي تشغلها عناصر Inline-level تقتصر على حجم المحتوى النصي، بينما تمتد المساحة الأفقية المشغولة لكل عنصر من عنصر Block-level على كامل السطر. تدفع عناصر Block-level عناصر Inline-level إلى السطر التالي، حتى لو كتبت عناصر HTML على نفس السطر في الملف. وللتأكد من ذلك سنكتب عنصر Block-level وعنصر Inline-level على نفس السطر. وفقًا لما يلي: <strong>My strong text</strong><h1>My heading</h1><em>My emphasized text</a> وستظهر النتيجة في صفحة الويب كما توضح لقطة الشاشة التالية: لاحظ أن عنصر العنوان <h1> بدأ في سطر جديد ودفع عنصر النص التالي إلى سطر جديد، على الرغم من كتابة جميع العناصر على نفس السطر. الآن أصبح لديك فهم لكيفية وضع عناصر Block-level وعناصر Inline-level وكيفية تأثيرها على موضع العناصر القريبة. كيفية دمج عناصر HTML متعددة قد نحتاج أحيانًا إلى تطبيق أكثر من عنصر من عناصر HTML على جزء محدد من المحتوى. ولذلك تتيح لغة HTML تداخل عناصر متعددة لإظهار النص بتصميم معين. يقصد بتداخل عناصر HTML أنه من الممكن وضع عنصر معين داخل عنصر آخر. يسمح لك هذا التداخل بتطبيق وسوم HTML متعددة على جزء واحد من المحتوى. وسنوضح هذه الفكرة في المثال التالي: انسخ هذا المقتطف والصقه داخل ملف index.html: <strong>My bold text and <em>my bold and emphasized text</em></strong> احفظ الملف وأعد تحميله في المتصفح، وستظهر الصفحة التالية: يوصى دائمًا بإغلاق الوسوم المتداخلة بالترتيب العكسي لوسوم الفتح. في المثال التالي أغلق الوسم <em> أولًا لأنه كان آخر وسم يُفتح. وأغلق الوسم <strong> أخيرًا لأنه كان أول وسم يُفتح. This sentence contains HTML elements that are <strong><em>nested according to best practices</em></strong> والمثال التالي يوضح كيفية عمل عناصر HTML غير المتداخلة، حيث أغلق الوسم <strong> قبل الوسم <em>: This sentence contains HTML elements that are <strong><em>not nested according to best practices</strong></em> كيفية استخدام سمات HTML تستخدم سمات HTML لتغيير ميزات عناصر HTML مثل اللون والحجم. على سبيل المثال يمكنك استخدام إحدى السمات لتغيير لون عنصر النص أو لتعديل عرض وارتفاع عنصر الصورة. فيما يلي سنتعرف على كيفية استخدام سمات HTML لتعيين قيم للحجم وخصائص الألوان لعناصر HTML. توضع السمات في وسم الفتح بالطريقة التالية: <element attribute="property:value;"> إحدى السمات الشائعة هي Style، والتي تسمح لك بإضافة خصائص النمط إلى عنصر HTML. من الشائع استخدام ورقة أنماط stylesheet منفصلة لتحديد تصميم مستند HTML. ولكننا سنستخدم السمة Style في هذا البرنامج التعليمي لتعديل تصميم العناصر. كيفية استخدام السمة Style يمكنك تغيير خصائص متعددة لعنصر <h1> باستخدام السمة style. امسح محتويات الملف index.html واستبدلها بالسطر البرمجي التالي: <h1 style="font-size:40px;color:green;">This text is 40 pixels and green.</h1> قبل تحميل الملف في المتصفح، سنشرح كل جزء من أجزاء عناصر HTML: الوسم h1 هو وسم HTML يحول النص إلى عنوان كبير الحجم. style: وهي سمة يمكن أن تأخذ مجموعة متنوعة من الخصائص المختلفة. font-size: هي الخاصية الأولى التي نحددها للسمة style. 40px: هي قيمة حجم الخط للخاصية font-size وهي تحول حجم محتوى نص العنصر إلى 40 بكسل. color: هو الخاصية الثانية التي نحددها للسمة style. green: هو قيمة الخاصية color وهي تحدد لون محتوى النص إلى اللون الأخضر. لاحظ أن الخصائص والقيم مضمنة بعلامات اقتباس، وأن كل خاصية تنتهي بفاصلة منقوطة. احفظ الملف وأعد تحميله في المصفح وستحصل على النص بالشكل التالي: كيفية استخدام HTML لإضافة الصور على موقع الويب تضاف الصور إلى مستند HTML باستخدام عنصر <img>، ويتطلب هذا العنصر السمة src التي تمكّنك من تحديد موقع الملف حيث تُخزّن الصورة. يكتب عنصر الصورة <img> على النحو التالي: <img src="Image_Location"> لاحظ أن العنصر <img> لا يستخدم علامة إغلاق <img/>. لتجربة مثال عملي حول إضافة الصور إلى صفحة موقع الويب. حمّل صورة Sammy the Shark، واحفظها في مجلد المشروع الذي نعمل عليه في هذه السلسلة html-Practice. ملاحظة: لتحميل صورة Sammy the Shark انقر على هذا الرابط ثم انقر بزر الفأرة الأيمن على الصورة إذا كنت تستخدم نظام ويندوز أو اضغط على CTRL+Left إذا كنت تستخدم نظام Mac، ثم حدد "حفظ باسم"، واحفظها باسم small-profile.jpeg في مجلد مشروعك. افتح الملف index.html في محرر النصوص وامسح المحتوى الموجود واستبدله بـ: <img src="Image_Location"> ثم انسخ مسار ملف الصورة واستبدل Image_Location في التعليمة السابقة بمسار موقع الصورة المحفوظة. ملاحظة: تأكد من نسخ المسار النسبي أو مسار ملف المشروع للصورة بدلًا من مسار الملف الكامل للصورة. حيث يشير المسار النسبي إلى موقع الملف بالنسبة إلى دليل العمل الحالي، بينما يشير المسار الكامل إلى موقع الملف بالنسبة إلى الدليل الجذر. ورغم أن كلا المسارين سيعمل في هذه الحالة، ولكن لن يعمل سوى المسار النسبي إذا قررنا نشر موقعنا على الإنترنت. نظرًا لأن هدفنا النهائي هو إنشاء موقع ويب قابل للنشر فإننا سنستخدم المسارات النسبية لإضافة عناصر <img> إلى الأمثلة. الخطوة الأخيرة هي حفظ ملف index.html وإعادة تحميه في المتصفح. وستظهر الصفحة التالية: تقنيًا يمكنك استخدام روابط للصور المستضافة على الإنترنت كمسار للملفات. ولفهم كيفية عمل ذلك، استبدل موقع الصورة في المثال السابق برابط صورة Sammy the Shark كما يلي: <img src="https://html.sammy-codes.com/images/small-profile.jpeg"> احفظ الملف بعد إضافة التعديلات السابقة وأعد تحميله في المتصفح. وستلاحظ أنك حصلت على نفس النتيجة ولكن في هذه المرة حصلت على الصورة من موقعها على الإنترنت بدلًا من دليل المشروع الحالي. يمكنك تجربة إضافة صور أخرى من الإنترنت باستخدام روابط الموقع كقيمة للسمة scr في الوسم <img>. ولكن عند إنشاء موقع ويب من الأفضل عدم استخدام صور من الإنترنت لضمان استدامة الموقع. لأنه إذا أزيلت الصور من قبل مضيفها أو تغير عنوانها فلن تعرض مرة أخرى على موقعك. إضافة نص بديل لتسهيل الوصول إلى الصورة عند إضافة صورة إلى صفحة الويب يجب تضمين نص بديل يصف محتواها باستخدام السمة alt. لا يعض هذا النص عادةً على صفحة الويب ولكنه يستخدم بواسطة برامج قراءة الشاشة لتوصيل المحتوى إلى زوار الموقع من ذوي المشاكل البصرية. مثال: <img src="https://html.sammy-codes.com/images/small-profile.jpeg" alt="Digital Ocean’s mascot, a blue smiling shark." > عند إضافة نص بديل، ضع في حسبانك ما يلي: بالنسبة للصور التي تحتوي على معلومات يجب أن يصف النص البديل موضوع الصورة بطريقة واضحة ودقيقة، وبدون الرجوع إلى الصورة نفسها. مثلًا لا تكتب "صورة قرش في المحيط" وإنما "قرش في المحيط". بالنسبة لصور الزخرفة يجب استخدام السمة alt ولكن بدون إضافة أي قيمة. أي بالطريقة التالية: <img src="images/decorative_image.jpeg" alt=""> وهذا يؤدي إلى تحسين تجربة قارئ الشاشة. خاتمة وضحنا في هذا المقال الفرق بين عناصر HTML وكيفية عمل كل منها، ثم شرحنا كيفية استخدام السمة style لتعديل النص، وكيفية إضافة الصور إلى صفحات الويب. وتعد هذه الأفكار ضرورية لإنشاء أي صفحة ويب. في المقال التالي سنبدأ بإعداد ملف المشروع وإنشاء الصفحة الرئيسية لموقعنا التجريبي. ترجمة -وبتصرّف- للأجزاء من الثالث وحتى السادس من سلسلة المقالات How To Build a Website with HTML. اقرأ أيضًا أساسيات لغة HTML مكونات الويب: عناصر HTML المخصصة وقوالبها الدلالات المضمنة لعناصر صفحة الويب ودورها في تعزيز سهولة الوصول هيكلة النصوص باستخدام لغة HTML
    1 نقطة
  43. تلعب البيانات أهمية كبيرة في أعمال وشركات اليوم بل إنه يستحيل أن نجد شركة قوية ومنافسة في السوق وليس لديها قاعدة بيانات قوية، هذه هي قواعد اللعبة في عصرنا الحالي، هل تريد المنافسة والسيطرة على السوق؟ إذا جهز نفسك لبناء قاعدة بيانات قوية ومتكاملة، ولفهم أهمية قواعد البيانات لا بدّ لنا في البداية من تبسيط المفاهيم والتعرف بدقة على ماهيّة قواعد البيانات والتي ببساطة هي مجموعة من المعلومات المنظمة في شكل مهيكل (مثل جداول) أو غير مهيكل (مثل المستندات)، ويمكن الوصول إليها وإدارتها وتحديثها بسهولة من خلال أنظمة إدارة قواعد البيانات مثل MySQL و MongoDB. تكمن أهمية قواعد البيانات في أنها تخزن المعلومات المتعلقة بتفاصيل المنتج البرمجي مثلًا إذا كانت المنتج متجر إلكتروني فستكون المعلومات مثلًا عدد المبيعات ومخزون المنتجات وملفات العملاء وأنشطة التسويق …إلخ، وتساعد قواعد البيانات في جعل عملك أقوى مما يزيد من أرباح شركتك آنذاك. لنتخيل أنه ليس لديك مكان مركزي لتخزين كل هذه المعلومات التي تصدرها الشركة في هذه الحالة لن يكون لديك أدنى فكرة عما يحدث بالفعل في شركتك، وعندها ستبدأ في وضع الافتراضات لما يحدث داخل شركتك، وتتخذ القرارات بناء على تكهنات بدلًا أن يكون بناء على الحقائق. لاحظ كيف يمكن توظيف قواعد البيانات في فهم ما يحدث بالضبط في مثال المتجر السابق من خلال قراءة المعلومات وتحليلها، في الحقيقة مع اكتشاف الشركات لأهمية قواعد البيانات ازداد الاعتماد عليها، وبدأت شركات البرمجيات بتطوير قواعد البيانات وأنظمتها وجعلها تواكب متطلبات البيانات الحديثة فظهرت لدينا قواعد بيانات كثيرة بعضها للشركات الصغيرة وبعضها للكبير بعضها مغلقة المصدر وبعضها مفتوح المصدر، ومع هذا التنوع وكثرة الخيارات تزداد الحيرة والقلق من اختيار نوع خاطئ يؤدي لكوارث لاحقة للشركة، فما هو نوع قواعد البيانات المناسبة للشركات الناشئة؟ وكيف نختار ما يناسبنا في ظل هذا التنوع الكبير بين قواعد البيانات وأنظمة إدارتها؟ سنحاول في المقال تسليط الضوء على اثنين من أشهر أنظمة إدارة قواعد البيانات وهما MySQL و MongoDB والذين يديران قواعد البيانات العلائقية Relational Database وقواعد بيانات غير العلائقية Non-Relational Database على التتالي، وسنقارن بينهما ونكتشف كيف فرضا نجاحهما وجدارتهما في سوق العمل الحديث، ولنتمكن لاحقًا من استخدامهما في المشاريع التي تناسبهما، وسنسعى لتجنب التحيز بين أنظمة إدارة قواعد البيانات ولكن بالتأكيد هناك بعض المشاريع التي تناسب إحدى الأنظمة أكثر من الآخرى وهذا أمر طبيعي. نبذة موجزة عن MySQL و MongoDB تُعرف لغة SQL بأنها لغة استعلام مهيكلة تستخدم لتخزين ومعالجة واسترجاع البيانات الموجودة في قاعدة بيانات علائقية Relational Database وهذه الأخيرة وهي مجموعة من عناصر البيانات التي تترابط مع بعضها بعلاقات محددة على شكل مجموعة من الجداول ذات الأعمدة والأسطر، ويعد التعامل مع هذه اللغة واضحًا لأن قواعد البيانات مهيكلة ومنظمة حتى مع المشاريع الكبيرة. أما لغة NoSQL فهي لغة استعلام غير مهيكلة تستخدم لتخزين ومعالجة واسترجاع البيانات من قاعدة بيانات غير علائقية Non-Relational Database وهذا النوع من قواعد البيانات لا يستخدمُ المخططات Schema لبناء قواعد بيانات وإنما يستخدم نماذج مرن مثل أزواج الاسم والقيمة للمتطلبات Name-Value أو المستندات وهذا ما يمنح قاعدة البيانات المرونة العالية في التكيف مع البيانات المتغيرة للمشاريع الحديثة، ويعد التعامل مع هذه اللغة صعبًا نسبيًا في المشاريع الكبيرة. تعد أنظمة إدارة قواعد البيانات DBMS -وهي اختصارا Database Management Systems- أنظمة برمجية تُستخدم لتخزين واسترجاع وتنفيذ الاستعلامات على البيانات المخزنة في قاعدة البيانات، وتعمل هذه الأنظمة كواجهة بين المستخدم النهائي وقاعدة البيانات، مما يسمح للمستخدمين بإنشاء وقراءة وتحديث وحذف البيانات في قاعدة البيانات. قبل أن ندخل في تفاصيل الحديث عن هذين النظامين لا بدّ أن نوضح بأنه يمكن النظر إلى هذه المقارنة على أنها مقارنة بين نوعي قواعد البيانات SQL و NoSQL ولكن بطريقة غير مباشرة، كما أنه من الجدير بالذكر أن هنالك العديد من الأنظمة التي تدير قواعد البيانات من نوع SQL نذكر منها MySQL و PostgreSQL و Microsoft SQL Server وغيرها، وأيضًا هنالك أنظمة إدارة لقواعد البيانات NoSQL مثل MongoDB و BigTable و Redis و RavenDB و Cassandra و HBase و Neo4j و CouchDB وغيرها. ما هي MySQL؟ تعريف قواعد بيانات MySQL هو نظام إدارة قواعد بيانات علائقية RDBMS -وهو اختصارا Relational Database Management System- يستخدم لتحديث وإدارة وإنشاء قواعد البيانات العلائقية، صدر عام 1995 وسرعان ما بنى تاريخًا قويًا وسمعة عالية وموثوقية كبيرة بفضل مميزاته من السهولة والأمان ومع إتاحته كنظام مفتوح المصدر الأمر الذي الذي عزز شعبيته ومكّن المبرمجين من التعديل على الشيفرة البرمجية. أما قاعدة البيانات العلائقية Relational Database: فهي مجموعة من عناصر البيانات مرتبطة بعلاقات محددة مسبقًا فيما بينها، وتنظم هذه العناصر كمجموعة من الجداول ذات الأعمدة والصفوف، ويمكن تمييز كل صف في الجدول بمعرف فريد يسمى مفتاح أساسي، ويمكن جعل الصفوف الموجودة بين جداول متعددة مرتبطة باستخدام مفاتيح خارجية. يتوافق نظام إدارة MySQL مع العديد من الخوادم عبر جميع اللغات والبرامج الوسيطة، كما أن تصميمه متعدد الطبقات مع وحدات مستقلة الأمر الذي يوفر الحماية المطلوبة وهو يدعم الخيوط دعمًا كاملًا من خلال خيوط النواة Kernel Threads، كما يقدم أدوات مدمجة لتحليل الاستعلام وتحليل المساحة، ويمكنه التعامل مع كميات كبيرة من البيانات تصل حتى 50 مليون صف أو أكثر، ويعمل مع العديد من توزيعات يونكس UNIX ولينكس Linux. ما هو MongoDB؟ تعريف MongoDB هو نظام لإدارة قواعد البيانات غير العلائقية Non-Relational Databases مثل NoSQL و Cassandra، ويمكننا هذا النظام من إدارة المعلومات في قواعد البيانات سواء إضافة أو حذف أو تعديل أو استرداد، كما أن هذا النظام مفتوح المصدر وله أيضًا إصدارات تجارية أيضًا. ظهرت الشركة في البداية في عام 2007 عندما واجه المبرمجون الثلاثة وايت ميريمان وإليوت هورويتز وكيفين رايان مشكلة أثناء عمليات التطوير وقابلية التوسع لتطبيق الويب المشهور DoubleClick إذ كان يتطلب الموقع عرض 400,000 إعلان في الثانية، ولكن الاعتماد على مناهج قواعد البيانات العلائقية التقليدية أدى لبطئ كبير الأمر الذي حفزهم لتأسيس شركة 10Gen ولتطور الشركة بعدئذٍ ويغير اسمها لاحقًا إلى MongoDB Inc في عام 2013 ولتطرح اسهمها للاكتتاب العام في عام 2017. يدعم النظام أشكالًا مختلفة من البيانات وهذا لأن قواعد البيانات التي من نوع NoSQL بحد ذاتها تدعم هذه الأنواع ولا تتطلب قواعد البيانات أي مخططات مسبقة Database Schema مما يسمح بمرونة عالية في تطوير قواعد البيانات. في الواقع يمكن أن تكون المستندات في نفس المجموعة ومع ذلك لها هياكل مختلفة تمامًا فيما بينها. يعتمد نظام MongoDB أسلوبًا مختلفًا لتخزين البيانات إذ يمثل المعلومات كسلسلة من المستندات المشابهة لصيغة JSON الموجودة في لغة جافاسكربت (للتوسع في فهم صيغة JSON يمكنك الاطلاع على مقال ما هي JSON؟)، وتسمى الصياغة التي يخزن بها Binary JSON أو BSON. وتعرف BSON بأنها شكل ثنائي لتمثيل هياكل البيانات البسيطة أو المعقدة بما في ذلك المصفوفات الترابطية Associative Arrays (المعروفة أيضًا باسم أزواج الاسم والقيمة Name-Value)، والمصفوفات المفهرسة بالأرقام الصحيحة، ومجموعة من الأنواع العددية الأساسية. تتشابه الحقول الموجودة في هذه المستندات مع الأعمدة الموجودة في قاعدة البيانات العلائقية. وعادة ما يستخدم المتغير BSON لتبادل البيانات، يذكر أن شركة MongoDB طورت هذا المتغير عام 2009. مقارنة بين MySQL vs MongoDB يتشابه هذان النظامان في شكليهما إذ كلاهما نظام إدارة قواعد بيانات DBMS، وكلاهما يمكن الشركات من نشر وتوزيع تطبيقاتها السحابية أو تعديلها أو نشرها. علاوة على ذلك أنشأ مطورو كلا النظامين هذه القواعد في الأصل كقواعد بيانات مفتوحة المصدر لتكون الشيفرة البرمجية مجانية لأي شخص لاستخدامها وتوزيعها. هذه أبرز أوجه التشابه أما الاختلافات سنناقشها بالتفصيل. المجتمع والتطوير لننظر في المجتمع لتقييم تطوير هذه الأنظمة يشير المجتمع الأكبر إلى أن تطوير هذه الأطر مستمر على قدم وساق. كما أن كثرة استخدام المبرمجين لنظام قاعدة بيانات معين يجعل من السهولة الحصول على الدعم والمساعدة في المجتمعات التقنية. table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } وجه المقارنة قواعد بيانات MySQL قواعد بيانات MongoDB الموقع الرسمي MongoDB MySQL تاريخ أول إصدار 1995 2009 رقم الاصدار الحالي (الذي كان وقت كتابة المقال) 8.0.28 5.0.5 بحسب الاستبيان السنوي لموقع Stackoverflow جاء فيه سيطرة واضحة لنظام إدارة قواعد بيانات MySQL وهذا أمر منطقي نظرًا لقدمها وفعاليتها في معظم المشاريع آنذاك، ولكن سنجد أيضًا صعود قوي وسريع لنظام إدارة قواعد بيانات MongoDB على مر السنوات الماضية وذلك لأن تقنيات الويب تغيرت جدًا وأصبح كل شيء يتفاعل معه المستخدم في الموقع يولد بيانات وهذا الكم الكبير من البيانات تصعبُ إدارته من خلال MySQL، ولذلك ومع أن MySQL ستفوز في سباق الشعبية إلا أن MongoDB ستحجز لنفسها مكانًا في أوائل الأنظمة تطوير قواعد بيانات في المستقبل، وبحسب الاستبيان أيضًا نجد توافق بين جميع المستجيبين والمطورين المحترفين لقواعد بيانات الأكثر شيوعًا، والاختلاف الوحيد الذي نجده هو أن المطورين المحترفين يميلون أكثر قليلًا إلى استخدام Microsoft SQL Server على MongoDB. قابلية التوسع غالبًا ما يواجه المهندسون والمطورون تحديًا عندما يحتاج المشروع للتوسعة أو عند الزيادة الكبيرة لعدد المستخدمين والطلبات، ويكون ضمان توفر موارد موقع (سواء من قواعد بيانات أو الصور ..,إلخ) من أصعب التحديات، وهذا الأمر يحتاج للدراسة والتخطيط للتعامل مع عدد الزوار الكبير في أوقات ذروة الطلبات. في هكذا مواقف أول ما يخطر ببال المهندسين أننا سنحتاج لتوسيع قوة معالجة الخادم وسعة التخزين ومستويات التوفر للخادم …إلخ، ولكن هل تطوير الخادم هو الخيار الوحيد الذي لدينا؟ أم أن لدينا خيارات أخرى؟ وما هو التوسع بقواعد البيانات أفقيًا وعموديًا؟ ظهر مفهومي التوسع أفقيًا أو التوسع عموديًا في قواعد البيانات عند الزيادة الكبيرة في الاعتماد عليها وكمية البيانات الضخمة وعدد الزوار الكبير لمواقع وتطبيقات الويب الذين يطلبون البيانات ويمكن أن يختلط الأمر على المبتدئين بين لأن كليهما يشتملان على إضافة موارد إلى البنية التحتية التي نضع عليها قواعد البيانات، ولكن هناك فروقات واضحة بين الاثنين من حيث التنفيذ والأداء. يشير التوسع العمودي Vertical Scaling إلى التوسعة من خلال زيادة إمكانيات المكونات المادية للمخدم مثل زيادة قدرة وحدة المعالجة المركزية أو ذاكرة الوصول العشوائي …إلخ، بينما يشير التوسع الأفقي Horizontal Scaling إلى التوسع من خلال إضافة المزيد من الخوادم وتوزيع الحمولة عليها. أحد الاختلافات الأساسية بين الاثنين هو أن القياس الأفقي يتطلب تغيير منطق قاعدة البيانات وجعلها في أجزاء صغيرة من أجل وضعها بالتوازي عبر أجهزة متعددة وتوزيع الحمولة بينها، وغالبًا ما يكون التوسع الرأسي أسهل لأن المنطق لا يحتاج إلى التغيير وإنما فقط توسعة عدد المعالجات والأجهزة. يمكن لقواعد البيانات MySQL التوسع عموديًا وهذا الأمر يجعلها غير محبذة للمشاريع الضخمة أو التي تتغير بنيتها باستمرار، بينما نجد بأن قواعد MongoDB يمكنها التوسع أفقيًا وعموديًا ولذلك نجدها في المشاريع الكبيرة، ومن الجدير بالذكر أن هنالك عدة فروقات أخرى بين التوسع الأفقي والرأسي لن نناقشها في هذا المقال لكي لا يطول ونخرج عن الموضوع ويمكنك البحث عنها. بالرغم من ذلك هنالك بعض المبرمجين يحاولون المواربة عن مشكلة عدم إتاحة نظام قاعدة بيانات MySQL توزيع البيانات على مجموعة من المخدمات للقراءة فقط ولكن هذه الترقيعات لا يمكن مقارنتها مع الدعم الأصيل الموجود في MongoDB، ونشير أيضًا إلى أن التوسع العمودي في قواعد البيانات له حد أعظمي سواء من قدرة المعالج أو سعة الذاكرة العشوائية …إلخ. مخطط البيانات وتنوع البيانات في نظام قواعد البيانات MongoDB تعرض البيانات في أزواج مثل مستندات JSON، مما يتيح لقاعدة البيانات قيودًا أقل ومرونة أكبر بالمقارنة مع الطرق الأساسية بالتصميم والتي تعتمد على المخطط وأنواع البيانات والقيود والروابط، ولكن الأمر يتغير بالنسبة لنظام قواعد البيانات MySQL، فبالرغم من إمكانية تغيير المخطط مع مرور الزمن، إلا أن التعديلات ليست مرنة وديناميكية كما هو الحال في قواعد بيانات القائمة على المستندات مثل NoSQL. كما تتطلب MySQL إنشاءً مسبقًا لمخطط قواعد وتنظيم الجداول والأعمدة قبل تخزين أي بيانات، بالإضافة إلى ذلك يتطلب تعديل مخطط البيانات إعادة التفكير بعناية بكيفية تنفيذ التعديل من خلال لغة تعريف البيانات DDL (وهي اختصار Data Definition Language) أو لغة معالجة البيانات DML (وهي اختصار Data Manipulation Language) لأن نظام التعديل الذي تفرضه قواعد بيانات SQL صارم لذلك عندما يتغير مخطط قاعدة البيانات خصوصًا إن كانت التغييرات كبيرة، فنعيد بناء قاعدة البيانات ثم ننقل البيانات عليها من جديد، وفي الواقع هذا الاتساق هو من أكثر نقاط القوة في MySQL لأنه يحافظ على البيانات منظمة ومتسقة. وأما بالنسبة لتنوع البيانات فإن قاعدة بيانات MongoDB تسمح بتخزين المستندات والتي تختلف في المحتوى والحجم، أما MySQL نظرًا لأن مخطط البيانات أكثر تقييدًا وصرامة، فإن كل صف داخل الجدول يتطلب نفس الأعمدة (أي مثلًا يجب لعمود الاسم في جدول بيانات MySQL أن يأخذ نفس نوع البيانات ونفس الحجم وفي حالتنا كون Varchar(50) أي بحجم 50 محرف فقط‎) والتي يمكن أن تكون صعبة، ولذلك تتفوق قاعدة بيانات MongoDB على قاعدة بيانات MySQL عند التعامل مع كميات متنوعة وكبيرة من البيانات المعقدة. الأداء والسرعة تحتل سرعة وأداء قواعد البيانات مكانة كبيرة في سباق المقارنة وفي الحقيقة لا تتطلب كل المشاريع البرمجية سرعة كبيرة لنتخيل مثلًا نشاطًا تجاريًا يعمل بكميات صغيرة من البيانات ذات تنوع بسيط سنُلاحظ بأن السرعة ليست بالضرورة أمرًا مهمًا نظرًا لأن الميزات الأخرى (مثل الموثوقية واتساق البيانات)، ولذلك فإن الخيار الأفضل في هذه الحالة هو قواعد البيانات. تقبل MongoDB كميات أكبر من البيانات المهيكلة أو غير المهيكلة كما أنها أسرع من MySQL. ومع ذلك لا ينظر المهندسون إلى السرعة كعنصر محوري بقدر ما أنها ميزة إضافية لمميزات إحدى قواعد البيانات، في الحقيقة إن المقارنة بين السرعة ستكون منطقية في حال المقارنة بين نوعين من قواعد البيانات المهيكلة ولن نستطيع تطبيق ذلك لأن هذا سيُعد ظلمًا لقواعد البيانات MongoDB بإهمال أفضل ميزة بها وهي قواعد البيانات غير المهيكلة، وعمومًا تتمتع MySQL بسرعة جيدة في قواعد البيانات المهيكلة وتتحسن سرعتها من خلال الاستخدام الصحيح للفهارس، كما تتمتع MongoDB بأداء مرِن وسرعة كبيرة للبيانات غير المهيكلة، ولكن إنشاء فهارس على سمات بيانات متنوعة يصبح أمرًا صعبًا، الأمر الذي يجعل MongoDB تتطلب تحسينًا متكررًا لمخطط البيانات، ولذلك يكون هناك مخاطرة بمشاكل تتعلق باتساق البيانات. الحماية تستخدم نظام قواعد البيانات MySQL نموذج أمان قائم على الامتيازات Privileges، والذي يتطلب مصادقة المستخدم أي أن النظام يتطلب عمليات أمان وهي المصادقة Authentication والتفويض Authorization والتحقق Verification، بالإضافة إلى ذلك تستخدم قواعد البيانات MySQL اتصالات مشفرة بين العملاء والخادم وذلك من خلال طبقة مآخذ التوصيل الآمنة SSL بروتوكول أمان. تتشابه طريقة الحماية التي يوفرها نظام قواعد البيانات MongoDB إذ هو الآخر يعتمد على الامتيازات. بالإضافة إلى ذلك إذا كان التشفير مطلوبًا فيمكن تطبيق بروتوكول طبقة التوصيل الآمنة SSL أو تعطيله إن لزم الأمر، في الحقيقة يوفر نظامي MongoDB و MySQL نماذج أمان قوية والفارق غالبًا ما يكون في طريقة تطبيق المطورين والمهندسين للمارسات الأمنية الشائعة أما قواعد البيانات وأنظمتها فهي ذات أمان قوي. خصائص ACID تعد خصائص ACID وهي اختصار للكلمات التالية: الذرية Atomicity والاتساق Consistency والعزل Isolation والمتانة Durability من الخصائص المهمة جدًا عند التعامل مع قواعد البيانات، ويعد توافر هذه الشروط أساسيًا للوثوق بتعاملات قاعدة البيانات يذكر أن أول من طرح هذه الشروط هو العالم جيم جراي Jim Gray وذلك في أواخر الستينات القرن العشرين. تتكون تعاملات قواعد البيانات Database Transaction من مجموعة من العمليات المفردة. فمثلًا عند تحويل مبلغ من حساب بنكي إلى آخر، يخصم المبلغ من حساب المصدر ويضاف في الحساب المستقبل. فيكون لدينا عمليتان لكنهما معا تشكلات تعاملًا واحدًا، وعمومًا لنشرح بالضبط أهمية كل خاصية من هذه الخواص: الذرية Atomicity: وتعني أن تعاملات قاعدة البيانات إما أن تنفذ جميع عملياتها بصورة كاملة أو لا تُنفذ أيًا منها، بمعنى أنه لا يوجد حل وسط، ففي مثال التحويل البنكي إما أن تنفذ عمليتي الخصم والإيداع أو لا تُنفذ أية واحدة منها لأن تنفيذ أحدهما وفشل الآخر سينتجُ عنه خلل في صحة البيانات. الاتساق Consistency: وتعني أن تظل قاعدة الباينات ملتزمة بقوانين تكامل البيانات كما حددها مصمم قاعدة البيانات بعد تنفيذ التعامل، فمثلًا إذا حُدد الحد الأدنى للرصيد بمبلغ معين يجب أن ترفض قاعدة البيانات أي تعامل ينتج عنه في النهاية إخلال بهذا القانون. العزل Isolation: وتعني أن تنفذ التعاملات المختلفة بمعزل عن بعضها بعضًا، ويختص هذا الشرط بقواعد البيانات التي تنفذ عدة تعليمات متزامنة، فمثلًا إذا أراد العميل الكشف عن رصيده أثناء أجراء تعامل التحويل مالي يجب أن تمنحه قاعدة البيانات إما البيانات التي سبقت التحويل أو التي نتجت عنه (بفرض أنها نفذت بنجاح). المتانة Durability: وهي إذا ظهر للمستخدم نتيجة مفادها أن التعامل نُفذّ بنجاح، فإن ذلك يعني أن التعامل لن يُتراجع عنه مهما حدث، حتى في حالة حدوث أي أعطال لاحقة في قاعدة البيانات. يوفر كلا النظامين خصائص ACID وبالرغم من أن MongoDB تأخرت سنة كاملة لإضافتها ولكنها الآن متاحة، كما أن نظام قواعد البيانات جعل MongoDB هذه الخصائص غير مفعلة بصورة افتراضية إلا أنه يمكننا تفعيلها، ولكن تنفيذ هكذا خصائص سيتطلب التضحية بالسرعة والتوافر العالي. طريقة كتابة الاستعلام يعد الفرق بين البيانات المهيكلة وغير المهيكلة نقطة انطلاق مفيدة لأن البيانات المنظمة تتبع نموذجًا أو مخططًا محددًا جيدًا. بينما نجد بأن البيانات غير المهيكلة ليست منظمة وفقًا لأي نموذج محدد مسبقًا. ولذلك من المنطقي أن نجد نظام قواعد البيانات MySQL يستخدم لغة الاستعلام المهيكلة SQL عند طلب معلومات من جدول قاعدة بيانات، كما أنه لإنشاء جداول في قاعدة البيانات يتطلب معرفة بلغة تعريف البيانات DDL، ولتعديل البيانات يجب تعلم لغة معالجة البيانات DML وبذلك نستطيع التحكم الكامل بقواعد البيانات. أما بالنسبة لنظام قواعد البيانات MongoDB فهي تعتمد على لغة استعلام غير مهيكلة وهي MongoDB Query Language، والتي تعتمد بدورها على جافاسكربت وتحديدًا طريقة تبادل البيانات JSON الأمر الذي يجعل MongoDB تدعم لغات متعددة (مثل بايثون وجافا و C#‎ و Perl و PHP وروبي وجافاسكربت) ويمكن كتابة استعلام مركب ومحدد لمختلف الحقول داخل مستندات المجموعة باستخدام عوامل تشغيل الاستعلام. لنستعرض المثال التالي لفهم كيفية الاختلافات التي تحدث بين الاستعلامات لنفترض أن لدينا قاعدة بيانات تحتوي على جدول به الأعمدة التالية: الاسم العنوان رقم حساب متوسط كمية الطلب السعر عدد مخزون المنتجات من قراءة سريعة للتسميات يمكننا معرفة أو توقع المدخلات في كل عمود وبالتالي يمكننا الاستعلام عن البيانات وتحليلها بسهولة لأن تدفق البيانات محدد جيدًا. أما بالنسبة للقواعد البيانات غير المهيكلة فإن البيانات بها لا تتناسب بدقة مع الأعمدة. فمثلًا يمكن أن يتضمن جدول بيانات غير مهيكلة ما يلي: مقاطع فيديو نشاط الجهاز المحمول استخدام وسائل التواصل الاجتماعي مستندات نصية صور هل هنالك طريقة لمعرفة ما هو مقطع الفيديو أو الأغنية الشائعة التي أدخلها المستخدم؟ غالبًا لا يمكننا معرفة أو توقع ذلك، ولهذا السبب لا يمكننا استخدام الأدوات التقليدية للاستعلام عنه لأن تغير البيانات ينتج عنه تغير طريقة التعامل معها، وعمومًا الجدول التالي سيمنحنا المعرفة مبدئية للفوارق بين طريقة طريقة الاستعلام في MySQL و MongoDB. وهذه نظرة سريعة لبعض التعليمات في كل من نظام إدارة قواعد البيانات MySQL و MongoDB. الاستعلام عن جميع الموظفين: من خلال MySQL تكون التعليمة: select * from Employee;‎ من خلال MongoDB تكون التعليمة: db.Employee.find()‎ الاستعلام في بنية قواعد البيانات المعقدة: من خلال MySQL تكون التعليمة: SELECT E.* from Employee E inner join Dept D on E.EMPID=D.EMPID Where D.City=’Irving’ من خلال MongoDB تكون التعليمة: db.Employee.find( { "Address.City" : "Irving" }).pretty()‎ ادخال مجموعة من البيانات: من خلال MySQL تكون التعليمة: Insert into Employee values (‘Brian Lockwood’,45, ‘A’),(‘Charles’,35,’A’) من خلال MongoDB تكون التعليمة: document = [ { "Name" : "Brian Lockwood","Age" : "45", status:"A"}, { "Name" : "Charles","Age" : "35", status:"A"}] طريقة استخدام distinct لتصفية النتائج المكررة من استعلام معين: من خلال MySQL تكون التعليمة: Select distinct status from Employee;‎ من خلال MongoDB تكون التعليمة: db.Employee.distinct( "status");‎ طريقة الاستعلام مشروط: في MySQL تكون التعليمة: Select * from Employee where Age>30 في MongoDB تكون التعليمة: db.Employee.find ( { Age: {$gt : "30"} });‎ يمكننا في MySQL تطبيق تعليمات الدمج لاسترداد البيانات من جدولين أو أكثر من جداول قاعدة البيانات كما أن تعليمة الدمج JOIN توفر العديد من أنواع الدمج مثل الدمج الداخلي أو الخارجي أو اليساري أو اليمني أو المتقاطع، بينما لا تقدم MongoDB عمليات دمج لنتائج الاستعلام وليس لديها تعليمات تعادل هذه الوظيفة بالإضافة إلى ذلك لا توفر MongoDB القوادح Triggers والتي هي وحدات منطقية مقادة بالأحداث مزروعة في قاعدة البيانات، وتُنفذُ قاعدة البيانات أوامر القوادح أوتوماتيكيًا وتكون هذه التعليمات خاصة بالتعامل مع بيانات موجودة في جداول محددة بينما MySQL توفرها. سهولة التعلم للمبتدئين يعد نظام قواعد بيانات MySQL سهل نسبيًا وذلك بسبب أنه متسق ومنظم وهيكليته واضحة ولذلك من الطبيعي أن يكون تعلمه سهل وبسيط رغم طول منحنى تعلمه لكثرة المفاهيم فيه (وأحيانًا تعقيدها) بينما في المقابل نجد بأن البنية غير المهيكلة والمرونة العالية يمكن أن تجعل عملية التعلم أصعب نظرًا لكثرة التفاصيل والسيناريوهات رغم أن تعلم بدء استعمالها وتنفيذها سهل وسريع ويكون غالبًا مدمجًا مع اللغة البرمجية نفسها (أي تكتب الاستعلامات بلغة جافاسكربت بدلًا من لغة SQL) لما تخفي عن المستخدم التعقيد الداخلي. أيهما أفضل MySQL vs MongoDB؟ يعد كل من نظامي MySQL و MongoDB من الأنظمة القوية لإدارة قواعد البيانات، وتعمل كل واحدة منها بصورة مختلفة عن الأخرى نظرًا للاختلاف في نوع قواعد البيانات التي يتعاملان معها، ومن الصعوبة تحديد قاعدة البيانات الأفضل إذ يعتمد الأمر كله على السياق بعض الشركات تعتمد على كلا النظامين للتعامل مع مهام مختلفة وهذا أمر جيد والبعض الآخر يفضل التعامل فقط مع MongoDB لزيادة التركيز وتخفيف التشتت. متى نستخدم MySQL و MongoDB؟ بالرغم من المزايا العديدة التي يتمتع بها نظام MongoDB إلا أن MySQL تفوقت عليها في الموثوقية واتساق البيانات. وإذا كان الأمان يمثل أيضًا أولوية فإن MySQL معترف به على نطاق واسع كواحد من أكثر نظم إدارة قواعد البيانات أمانًا. تعد قواعد البيانات العلائقية الخيار الأنسب للتطبيقات متعددة المستخدمين وكل مستخدم له صلاحيات مختلفة وتتطلب أمان عال وموثوقية، مثل أنظمة المحاسبة والمصارف والبنوك لأن MySQL تركز على الوفاء بخصائص ACID وسلامة المعاملات، بينما تركز MongoDB على السماح بمعدل معاملات مرتفع ولذلك نجدها لا تدعم خصائص ACID في الوضع الافتراضي، وعمومًا يوصى باستخدام نظام MySQL للشركات أو المؤسسات أو المشاريع ذات مخطط البيانات الثابت والتي لا تنوي توسيع نطاق تنوع البيانات، مما يتطلب صيانة سهلة ومنخفضة مع ضمان سلامة البيانات وموثوقيتها، وهي مناسبة أيضًا لمشاريع التجارة الإلكترونية والمواقع التي تتطلب بروتوكولات أمان وموثوقية عالية مثل المشاريع الحكومية. أما نظام إدارة قواعد البيانات MongoDB فهو الخيار الأنسب للشركات الحديثة أو المشاريع التقنية المتطورة ذات المخطط غير مستقر لأن طبيعة البيانات غير العلائقية تسمح باستخدام قواعد البيانات بحرية وبدون بنية محددة مسبقًا الأمر الذي يسهل التحديث البنية أو تطويرها، وتستخدم غالبًا في المشاريع التي تتطلب إدارة المحتوى المتنوع، ومشاريع إنترنت الأشياء Internet of Things، ومواقع التحليلات والإحصائيات في الزمن الحقيقي Real-Time، والمواقع والتطبيقات عالية الاستخدام إجمالًا. يعد موقع Shutterfly مثلًا مميزًا لكيفية الانتقال إلى قواعد البيانات MongoDB، وهو واحدٌ من أشهر مواقع مشاركة للصور عبر الإنترنت، واعتمد في البداية على استخدام قواعد البيانات العلائقية المقدمة من شركة أوراكل لكن قواعد البيانات العلائقية غير مرنة لطبيعة عمل الموقع ومكلفة عند التوسع، كما تسببت في بعض الأحيان باختناقات خصيصًا عند التعامل مع عدد كبير من البيانات، لأن الشركة لديها أكثر من 6 مليارات صورة بالإضافة إلى معدل عمليات يصل إلى 10000 عملية في الثانية، وسرعان ما أدركت الشركة بأن الانتقال إلى قاعدة بيانات غير علائقية تعتمد على المستندات سيُساعدها على زيادة قابلية تطوير الموقع وتحسين أدائه وزيادة إنتاجية وقت البرمجة. يتيح نموذج مستند MongoDB للمطورين تخزين البيانات بالطريقة التي هي عليها بدلًا من محاولة تحويلها لتناسب نوع قواعد بيانات معين، من خلال عملية Normalization وهي عملية تنظيم البيانات في قاعدة البيانات (لمزيد من المعلومات يمكنك الاطلاع على مقال فهم عملية التوحيد Normalization المستخدمة عند تصميم قاعدة البيانات)، قارنت الشركة بين العديد من أنظمة قواعد البيانات البديلة الأخرى مثل BerkeleyDB أو CouchDB أو Cassandra لتستقر في النهاية على MongoDB لإدارة وتخزين بيناتها وأكدت الشركة أنها مسرورة بقرارها الانتقال من Oracle إلى MongoDB واستطاعت توفير 20% من النفقات المتعلقة بقواعد البيانات بعد هذا الانتقال بحسب تصريح أحد مهندسيها. إذا أردت الاطلاع على مقارنة شاملة وسريعة حول كل من MongoDB و MySQL، فيمكنك مشاهدة الفيديو الآتي: الخاتمة تعرفنا في هذا المقال على أهمية قواعد البيانات في الشركات وأخذنا نظرة سريعة إلى سرعة تطورها مع كثرة الاعتماد عليها وبعدها اطلعنا على نظامي إدارة قواعد البيانات MySQL و MongoDB وتعمقنا في فهم الاختلافات والتشابه بينهما من خلال الاطلاع على المجتمع والشعبية وقابلية التوسع ومن ثم فهمنا بين مخطط البيانات وتنوعها بين كِلا النظامين كما تعرفنا على تشابه سرعة وأداء النظامين ولنتعرف بعدها على طريقة حماية قواعد البيانات وإيفاء كل نظام بخصائص ACID ولندخل بعدها بالعمق أكثر من خلال معرفة كيفية كتابة الاستعلامات بينها ومن ثم سهولة تعلم المبتدئين لهذين النظامين وأجبنا بعدها على السؤال المكرر في الأوساط التقنية وهو أيهما أفضل MySQL vs MongoDB؟ كما اختتمنا المقال من خلال معرفة متى نستخدم كل منهما. وختامًا يعتمد القرار النهائي على متطلبات المشروع ونوعية بياناته الذي نعكف على تطويره لذلك يجب أن تكون متطلبات المشروع واضحة، وعمومًا ستقدم كلتا قاعدتي البيانات أداءً مُرضيًا للغاية إذا طبقت في سياق يناسبها. المصادر مقال ?What is MongoDB لصاحبه Jack Vaughan. مقال ?THE WORLD HAS CHANGED – WHY HAVEN’T DATABASE DESIGNS لكاتبه Avishai Ish-Shalom. مقال MongoDB vs MySQL: The Differences Explained لكاتبه Mauro Chojrin. مقال ?What are the main differences between MongoDB and MySQL لمحرري الموقع. مقال How to work with data using MongoDB Query Language لصاحبه Prashanth Jayaram. مقال MongoDB Query Language لمحرري الموقع. اقرأ أيضًا كتاب تصميم قواعد البيانات كتاب الدليل العملي إلى قواعد بيانات PostgreSQL توثيق SQL
    1 نقطة
  44. يشهد عالم البرمجة في عصرنا تطورًا هائلاً لا حدود له، إذ يُركز المطورين والمبرمجين على تحسين أداء الأعمال البرمجية من أنظمة، وبرامج، ومواقع وغيرها، وراحة المستخدم في التعامل معها، ومن أهم وأبرز عناصر وأركان هذا التطور سرعة استجابتها وأدائها. لاحظ الفرق في الصورة السابقة بين الحالتين، إذ تجد إحداها أسرع في العرض عند طلبها من الأخرى، والسبب في ذلك تطبيق تقنية prefetching فيها. تكمن تقنية prefetching (الجلب أو الاحضار المسبق) في تجهيز وتحميل الملف أو مجموعة الملفات قبل البدء بفتحها واستخدامها، وهي معروفة في كثير من مجالات البرمجة، حيث تستخدم في المعالجات لتسريع جلب البيانات والتعليمات قبل الحاجة لها، وفي ذاكرة DDR SDRAM، وفي أنظمة تشغيل الحاسوب، وفي المواقع الإلكترونية وهي من أبرز تطبيقاتها. سيكون الحديث هنا مقيدًا في مجال المواقع. المقصود من prefetching في مجال المواقع: تنقل أسرع بين صفحات الموقع من خلال تحميل الصفحات أو جزء منها قبل الشروع باستخدامها، أي بكل بساطة نخبر المتصفح بجلب الموارد قبل فتحها، وعند طلب المستخدم فتح الصفحة فإنها تُعرض مباشرةً كونها جاهزة للعرض كما ظهر في الصورة السابقة. كيفية إضافة هذه تقنية والاستفادة منها يستفاد من هذه تقنية في تسريع عرض صفحات الموقع أو جزءٍ منها كملفات JavaScript أو ملفات CSS (من أبرزها الخطوط حيث يتم عرض الخطوط من دون انتظار تحميل DOM و CSSOM)، أو الوسائط (صور ومقاطع مرئية وصوتية)، أو المستندات. يمكن إضافتها بعدة طرق، الأكثر شيوعًا باستخدام الوسم link في لغة HTML، وذلك بإدراجه في الصفحة السابقة للمراد تطبيق تقنية فيها، وفيه rel من نوع prefetching كما يلي: <link rel="prefetch" href="URL"> يوضع مكان URL رابط الملف المراد تحميله سابقًا وتجهيزه للعرض مباشرةً عند طلب المستخدم فتحه. نظرة أعمق لآلية عمل prefetching عند اكتمال تحميل الصفحة التي تحوي الوسم link من النوع prefetching (للمراد تطبيق تقنية الجلب المسبق فيها)، يرسل طلب تحميل الملف (المطبق عليه تقنية) بواسطة ترويسة HTTP التالية: Link: </js/chat-widget.js>; rel=prefetch بعدئذٍ يتم تحميل الملف وتخزينه في ذاكرة المتصفح المؤقتة، ومن المهم معرفته أنها تأخذ أقل أولوية بالتحميل (priority:lowest)، ويتم حفظها مدة لا تتجاوز الخمسة دقائق، خلال هذه المدة تكون جاهزة للعرض وما إن يقوم المستخدم بطلب فتح الصفحة تظهر مباشرةً، وتنتقل إلى إعدادات وقواعد cache-control الافتراضية لأي صفحة عادية، وإن لم يفعل وانتهت المدة يتم حذفها وتفقد هذه تقنية. تحديد الصفحة الأنسب والأولى بالتحميل المسبق تضاف هذه التقنية إلى الصفحات التي تملك الاحتمال الأكبر من انتقال المستخدم إليها، على سبيل المثال عند فتح موقع في صفحته الرئيسية يمكن للمستخدم أن ينتقل إلى 20 صفحة ثانوية، ولكن إحدى هذه الصفحات هي الأهم وأغلب المستخدمين ينتقلون إليها مباشرة عند فتح الموقع. ويتم إضافة تقنية إلى الصفحة التي من المؤكد انتقال المستخدم إليها كخطوة تالية، على سبيل المثال عند دخول إلى موقع تظهر في البداية صفحة إدخال بيانات شخصية وعند إتمام ذلك يتم الانتقال إلى الصفحة الرئيسية. وهذا يتطلب معرفة جيدة لوظيفة الموقع وطريقة استخدامه من قبل الزائرين، ومعرفة الصفحات الأكثر زيارة، ومما يساعد على ذلك الأداة Next Page Predictor فهي أداة تقترح الصفحة التالية التي تناسب تطبيق التقنية عليها. ولكن عند التعمق والتشعب أكثر في الموقع تصبح عملية اختيار الصفحة المناسبة لذلك أكثر صعوبة، ولكن من الممكن باستخدام بيانات إضافية التنبؤ بالصفحة الأنسب لإضافة التقنية، فعند فتح أي رابط URL من الموقع تحديد الصفحة التالية الأنسب لذلك وإضافة لها الوسم <link rel="prefetch" href="URL"‎>، مما يضفي لمسة تقنية أفضل أداءً للموقع كامل، ويمكن التعديل على الاختيارات يدويًا، وهذا ما تقدمه مكتبة Guess المعدة من قبل فريق تابع لجوجل، والتي تستند في نتائجها على استخدام الموقع (عدد الدخولات على الصفحات، وتحليلات جوجل) وعلى التعلم الآلي (Machine Learning) والتنبؤ بالصفحات التالية ذات الصلة بالحالية، وتقوم أيضًا بتجميع مصادر JavaScript المتوفرة بالصفحة الحالية والتي تلزم ببناء الصفحة التالية. توخي الحذر عند استخدام prefetching قد لا يتم الاستفادة من البيانات المحملة مسبقًا، بسبب عدم استخدامها وفتحها أو لانتهاء مدة تخزينها المؤقت أو غيرها من الأسباب، مما يتسبب بسحب وتبديد لبيانات الإنترنت من دون فائدة، وهذا قد يؤثر تأثير كبير على بعض المستخدمين الذين يملكون بيانات محدودة وشحيحة متاحة للسحب من الانترنت. يمكن التخفيف من هذه المشكلة بمعرفة نوع الشبكة بواسطة لغة JavaScript مع navigator.connection.effectiveType، حيث يقوم بإعطاء نوع الشبكة، فمثلا إن كانت الشبكة 4G على الأقل يتم تطبيق التقنية. ومن المشاكل التي قد ترتبط بهذه التقنية، طلب المستخدم فتح الصفحة قبل اكتمال الجلب المسبق لها، فذلك يؤدي إلى حذفها وإعادة تحميلها من جديد، لذا يفضل أن يحرص المبرمج على عرض جزء منها للمستخدم قبل حذفها. وعلى المبرمج أن يتنبه إلى أن التخزين المؤقت للملفات المالكة لهذه التقنية محدود، لذا يفضل عدم إدراج التقنية إلى ملفات كبيرة الحجم، بل إنه قد يعطي الخطأ: Failed to load resource: net::ERR_CACHE_WRITE_FAILURE وذلك لأن حجم الملف المطلوب جلبه مسبقًا كبير بشكل لا يمكن تخزينه في ذاكرة المتصفح المؤقتة. أمثلة عملية الموقع الياباني Nikkei: عندما وثقوا بانتقال المستخدمين إلى صفحات معينة، لم يتركوا المستخدم ينتظر تحميل الصفحة عند طلبها، بل قاموا بإدراج تقنية prefetching إلى تلك الصفحات مما أدى إلى تخفيض الوقت الكلي لعملية الانتقال إلى الصفحات من 880 ملي ثانية إلى 37، أي تخفيضها بنسبة 96% وهو فرق شاسع. شركة Netflix إذ قامت باستثمار هذه التقنية بتسهيل التنقلات إلى الصفحات. موقع Craigslist استفاد من هذه التقنية في تسهيل الوصول إلى صفحات نتائج البحث. موقع IndieGogo استفاد من هذه التقنية في تسهيل التعامل مع صفحات بطاقات الائتمان قبل الدخول إليها. المتصفحات التي تدعم هذه التقنية في ما يلي شكلٌ توضيحي من CanIUse للإصدارات التي تتيح تطبيق تقنية prefetching (الإصدار المظلل باللون الأخضر يدعم تقنية prefetching، والإصدار المظلل باللون الأحمر لا يدعمها): مراجع Speed up next-page navigations with prefetching Prefetching wikipedia Speeding up your website using Prefetching techniques Faster Page-Loads by Prefetching Links During Idle Time Prefetching, preloading, prebrowsing Prefetch W3C ‎<link rel="prefetch/preload"> in webpack Can I use prefetch‎?‎ Nikkei achieves a new level of quality and performance with their multi-page PWA Guess.js announcement
    1 نقطة
  45. كانت البرمجيات المكتبية تتفوق على تطبيقات الويب بإمكانية تخزين المعلومات محليًا تخزينًا دائمًا؛ حيث يوفِّر نظام التشغيل عادةً طبقةً وسيطةً لتخزين وقراءة بيانات خاصة بالتطبيق مثل الإعدادات وحالة التشغيل، وقد تُخزَّن هذه القيم في سجل النظام (registry) أو ملفات ini أو ملفات XML أو في مكانٍ آخر وفقًا للتقاليد المُتبَعة في نظام التشغيل؛ أما لو احتاج التطبيق المكتبي إلى تخزينٍ محليٍ أكثر تعقيدًا من مجرد تخزين البيانات على شكل "المفتاح/القيمة"، فيمكنك أن تُضمِّن قاعدة البيانات الخاصة بتطبيقك، أو أن تبتكر صيغة ملفات للتخزين، أو غيره ذلك من الحلول. لكن على مرِّ التاريخ، لم تملك تطبيقات الويب هذا الامتياز، وعلى الرغم من ابتكار الكعكات (Cookies) في بدايات الويب لكن كان الغرض منها هو التخزين المحلي لكميةٍ قليلةٍ من البيانات، إلا أنَّ هنالك ثلاثة أسباب تمنعنا من استخدامها لهذا الغرض: ستُضمَّن الكعكات في كل طلبية HTTP، مما يؤدي إلى حدوث بطء في تطبيق الويب بسبب نقل نفس البيانات مرارًا وتكرارًا دون داعٍ ستُضمَّن الكعكات في كل طلبية HTTP، وهذا يعني إرسال البيانات دون تشفير عبر الإنترنت (إلا إذا كان يُخدَّم تطبيق الويب عندك عبر طبقة SSL) المساحة التخزينية للكعكات محدودة إلى حوالي 4 كيلوبايت من البيانات، وهي كافية لإبطاء تطبيقك (انظر أعلاه)، لكنها ليست كافية لتخزين شيءٍ مفيدٍ ما نحتاج له حقًا هو: مساحة تخزينية كبيرة موجودة على جهاز العميل يمكن أن تبقى حتى بعد تحديث الصفحة لن تُنقَل طوال الوقت إلى الخادوم جميع المحاولات -قبل HTML5- لتحقيق ما سبق كانت غير مرضية لمختلف الأسباب. لمحة تاريخية عن محاولات تخزين البيانات محليا قبل HTML5 لم يكن هنالك سوى متصفح Internet Explorer في بدايات الويب، أو على الأقل هذا ما حاولت مايكروسوفت إيهام العالم به، ولتحقيق هذه الغاية، وكجزءٍ من الحرب الكبرى الأولى للمتصفحات، ابتكرت مايكروسوفت ميزاتٍ كثيرة ووضعتها في متصفحها -Internet Explorer- الذي أنهى تلك الحرب. واحدة من تلك الميزات تُسمى "DHTML Behaviors" وكان أحد خصائصها يُدعى userData. تسمح ميزة userData لصفحات الويب أن تُخزِّن 64 كيلوبايت كحد أقصى لكل نطاق (domain)، وذلك عبر هيكلية تعتمد على XML (أما النطاقات الموثوقة، مثل مواقع إنترانت [intranet]، فتستطيع تخزين 10 أضعاف الكمية؛ وكانت 640 كيلوبايت في ذاك الوقت أكثر من كافية). لم يوفِّر IE أي مربع حوار لأخذ إذن المستخدم، ولم تكن هنالك إمكانية لزيادة كمية البيانات التي يمكن تخزينها محليًا. في عام 2002، أضافت شركة Adobe ميزةً في Flash 6 التي اكتسبت الاسم "Flash cookies"، لكن هذه الميزة كانت معروفةً ضمن بيئة Flash بالاسم Local Shared Objects؛ باختصار، تسمح هذه الميزة لكائنات Flash أن تُخزِّن 100 كيلوبايت من البيانات كحد أقصى لكل نطاق. طوَّر Brad Neuberg نموذجًا أوليًا لجسرٍ يربط تقنية Flash بلغة JavaScript أسماه AMASS (اختصار للعبارة AJAX Massive Storage System)، لكنه كان محدودًا بسبب بعض المشكلات في تصميم صيغة Flash. لكن في 2006، ومع مجيء ExternalInterface في Flash 8، أصبح من الممكن بسهولة وسرعة الوصول إلى الكائنات المشتركة المخزنة محليًا (Local Shred Objects أو اختصارًا LSOs) من JavaScript؛ ولهذا السبب أعاد Brad كتابة AMASS ودمجها مع Dojo Toolkit تحت الاسم dojox.storage. وبهذا مَنَحَ Flash كل نطاق 100 كيلوبايت من التخزين المحلي "مجانًا"، وستُطلَب موافقة المستخدم عند كل زيادة في تخزين البيانات (1 ميغابايت، 10 ميغابايت، وهكذا). في عام 2007، أصدرت Google إضافة Gears، التي هي إضافة مفتوحة المصدر للمتصفحات غرضها هو توفير إمكانيات إضافية إليها (تحدثنا سابقًا عن Gears في سياق /توفير واجهة برمجية لتحديد الموقع الجغرافي لمتصفح IE/). توفِّر Gears واجهة برمجية (API) للوصول إلى قاعدة بيانات SQL مدمجة فيها مبنيةٌ على محرك قواعد البيانات SQLite. يمكن لإضافة Gears تخزين كمية غير محدودة من البيانات لكل نطاق في جداول قاعدة بيانات SQL بعد أخذ إذن المستخدم. في تلك الأثناء، أكمل Brad Neuberg وآخرون مشوارهم في تطوير dojox.storage لتوفير واجهة موحَّدة لمختلف الإضافات، وبحلول 2009 أصبح بمقدور dojox.storage أن تكتشف دعم (وتوفر واجهة موحدة) لبرمجية Adobe Flash و Gears و Adobe AIR والنموذج الأولي من التخزين المحلي في HTML5 الذي كان مُطبَّقًا في الإصدارات القديمة من Firefox فقط. عندما تنظر إلى تلك الحلول، فستكتشف أنَّ جميعها كان خاصًا بمتصفح معيّن أو كان يتبع لإضافة خارجية. وعلى الرغم من الجهود البطولية لتوحيد تلك الاختلافات (dojox.storage) إلا أنَّ تلك الحلول تملك واجهات برمجية مختلفة جذريًا عن بعضها، ولكلٍ منها حدود قصوى لمقدار المساحة التخزينية المتوفرة، ولكلٍ منها تجربة مستخدم مختلفة. هذه هي المشكلة التي أتت HTML5 لحلها: توفير واجهة برمجية معيارية، ومطبَّقة في جميع المتصفحات، دون الحاجة إلى استخدام إضافات خارجية. مدخل إلى التخزين المحلي في HTML5 ما أشير إليه على أنَّه "التخزين المحلي في HTML5"‏ (HTML5 Storage) هو مواصفة باسم "Web Storage" التي كانت جزءًا من معيار HTML5، لكنها انقسمت وأصبحت معيارًا مستقلًا لأسباب ليست مهمة. بعض الشركات المسؤولة عن المتصفحات تطلِق عليها الاسم "التخزين المحلي" (Local Storage) أو "تخزين DOM" ‏(DOM Storage). ازداد تعقيد موضوع التسميات خصوصًا بعد ظهور عدد من المعايير الجديدة التي سأناقشها في نهاية هذا الدرس. إذًا، ما هو التخزين المحلي في HTML؟ بشكل مبسّط: هو طريقة تتمكن صفحات الويب من خلالها أن تُخزِّن البيانات على شكل "المفتاح/القيمة" محليًا داخل متصفح الويب في حاسوب العميل. ومثل الكعكات، ستبقى البيانات موجودةً حتى بعد إغلاقك للسان الصفحة في المتصفح، أو إغلاق المتصفح. لكن على عكس الكعكات، لن تُرسَل البيانات تلقائيًا إلى خادوم الويب البعيد؛ وعلى النقيض من كل المحاولات السابقة لتوفير ميزة التخزين المحلي، هذه الميزة موجودة داخليًا في متصفحات الويب، لذلك ستكون متاحة للاستخدام حتى لو لم تتوفر إضافاتٌ خارجيةٌ للمتصفح. ما هي المتصفحات التي تدعمها؟ حسنًا، التخزين المحلي في HTML5 مدعومٌ من أغلبية المتصفحات، وحتى القديمة منها. IE Firefox Safari Chrome Opera iPhone Android 8.0+ 3.5+ 4.0+ 4.0+ 10.5+ 2.0+ 2.0+ تستطيع الوصول إلى التخزين المحلي في HTML5 في شيفرات JavaScript عبر الكائن localStorage الموجود في الكائن العام window؛ لكن قبل أن تستخدمها، عليك أن تكتشف دعم المتصفح لها. function supports_html5_storage() { try { return 'localStorage' in window && window['localStorage'] !== null; } catch (e) { return false; } } لكن بدلًا من كتابة الدالة السابقة يدويًا، يمكنك استخدام Modernizr لاكتشاف دعم التخزين المحلي في HTML5. if (Modernizr.localstorage) { // window.localStorage متوفرة! } else { // لا يوجد دعم للتخزين المحلي :( // ربما تجرب dojox.storage أو مكتبة أخرى } استخدام التخزين المحلي في HTML5 يعتمد التخزين المحلي في أساسه على تخزين البيانات على شكل "مفتاح/قيمة". أي أنَّك تُخزِّن البيانات في مفتاح له اسم مُميِّز، ثم تستطيع الحصول على تلك البيانات مرةً أخرى باستخدام نفس المفتاح. ذاك المفتاح هو سلسلة نصية، ويمكن أن تكون البيانات المُخزَّنة من أي نوع تدعمه لغة JavaScript بما في ذلك السلاسل النصية والقيم المنطقية (true و false) أو الأعداد الصحيحة أو الأعداد العشرية؛ لكن في الواقع، ستُخزَّن البيانات كسلسلة نصية، وهذا يعني أنَّه لو لم تكن القيمة المُخزَّنة نصيةً فستحتاج إلى استعمال دوال مثل parseInt()‎ أو parseFloat()‎ لكي تحوِّل البيانات التي حصلت عليها إلى نوع البيانات الذي تريده. interface Storage { getter any getItem(in DOMString key); setter creator void setItem(in DOMString key, in any data); }; سيؤدي استدعاء الدالة setItem()‎ مع تمرير مفتاح موجود مسبقًا إلى إعادة الكتابة فوق القيمة السابقة دون إشعار. وسيؤدي استدعاء الدالة getItem()‎ مع تمرير مفتاح غير موجود إلى إعادة null بدلًا من رمي استثناء (throw an exception). وكما هو الحال مع بقية الكائنات في JavaScript، يمكنك أن تُعامِل الكائن localStorage على أنَّه مصفوفة ترابطية (associative array). فبدلًا من استخدام الدالتين getItem()‎ و setItem()‎، تستطيع بكل بساطة أن تستعمل الأقواس المربعة (التي تستعملها للوصول إلى عناصر المصفوفات). يمكن على سبيل المثال أن نُعيد كتابة هذه الشيفرة: var foo = localStorage.getItem("bar"); localStorage.setItem("bar", foo); var foo = localStorage["bar"]; localStorage["bar"] = foo; هنالك دوالٌ أخرى لحذف قيمة مرتبطة بمفتاح معيّن، ولحذف كل ما هو مُخزَّنٌ محليًا (وهذا يعني حذف كل المفاتيح والقيم معًا). interface Storage { deleter void removeItem(in DOMString key); void clear(); }; لن يؤدي استدعاء الدالة removeItem()‎ مع تمرير مفتاح غير موجود إلى فعل أي شيء. وأخيرًا، هنالك خاصية للحصول على العدد الكلي للقيم المُخزَّنة محليًا، ودالة للحصول على اسم كل مفتاح عبر تمرير فهرسه المكاني*. interface Storage { readonly attribute unsigned long length; getter DOMString key(in unsigned long index); }; لو استدعيتَ الدالة key()‎ مع فهرس لا يقع بين 0 - 1 فستُعيد الدالة null. تتبّع التغييرات في مساحة التخزين المحلي إذا أردت أن تتبَّع التغييرات في مساحة التخزين (storage area) برمجيًا، فعليك أن تستعمل الحَدَث storage، الذي يُفعَّل (fired) في الكائن العام window في كل مرة تُستدعى فيها الدالة setItem()‎ أو removeItem()‎ أو clear()‎ وتجري تلك الدالة تغييرًا ما. فعلى سبيل المثال، لو أعدتَ ضبط قيمة موجودة مسبقًا وكانت القيمة الجديدة مساوية للقيمة القديمة، أو استدعيت الدالة clear()‎‎ لكن لم تكن هنالك أيّة قيم في مساحة التخزين، فلن يُفعَّل الحدث storage، لعدم تغيّر شيء في مساحة التخزين. الحدث storage مدعوم في كل متصفح يدعم الكائن localStorage، وهذا يتضمن Internet Explorer 8، لكن IE 8 لا يدعم الدالة المعيارية من W3C لمراقبة الأحداث addEventListener (لكنها أُضيفت في نهاية المطاف في IE 9)؛ ولهذا، إذا أردت مراقبة تفعيل الحدث storage فعليك أن تكتشف ما هي آلية الأحداث التي يدعمها المتصفح أولًا (إذا فعلتَ هذا من قبل مع الأحداث الأخرى، فيمكنك تخطي هذه الفقرة والانتقال إلى آخر القسم. مراقبة الحدث storage مماثلة تمامًا لعملية مراقبة الأحداث الأخرى التي سبقَ وأن راقبتَها؛ وإذا كنتَ تُفضِّل استخدام jQuery أو مكتبة JavaScript أخرى لتسجيل دوال مراقبة الأحداث، فتستطيع فعل ذلك مع الحدث storage أيضًا). if (window.addEventListener) { window.addEventListener("storage", handle_storage, false); } else { window.attachEvent("onstorage", handle_storage); }; ستُستدعى الدالة handle_storage مع تمرير كائن من نوع StorageEvent، عدا في متصفح Internet Explorer حيث يُخزَّن الكائن في window.event. function handle_storage(e) { if (!e) { e = window.event; } } سيكون المتغير e -عند هذه النقطة- كائنًا من نوع StorageEvent، الذي لديه الخاصيات المبيّنة في الجدول الآتي: الخاصية النوع الشرح key سلسلة نصية مفتاح القيمة التي أُضيفَت أو حُذِفَت أو عدِّلَت oldValue أي نوع القيمة (التي كُتِبَ فوقها)، أو null إذا أُضيف عنصرٌ جديد newValue أي نوع القيمة الجديدة، أو null إن حُذِفَ عنصرٌ ما url* سلسلة نصية الصفحة التي تحتوي على الدالة التي أجرت هذا التغيير ملاحظة: كان اسم الخاصية url الأصلي هو uri، وذلك لأنَّ بعض المتصفحات امتلكت هذه الخاصية قبل تغيير مواصفة التخزين المحلي. لأكبر قدر من التوافقية، عليك أن تتحقق من وجود الخاصية url، فإن لم تكن موجودًا فتحقق من قيمة الخاصية uri. لا يمكن إلغاء الأحداث في الحدث storage. فلا توجد طريقة من داخل الدالة handle_storage تستطيع إيقاف تغيير ما من الحدوث. بكل بساطة، هذه طريقة لكي يخبرك المتصفح: "هذا ما حصل لتوِّه، لا يمكنك فعل أي شيء تجاهه؛ كل ما أستطيع فعله هو إخبارك ما الذي حدث". المحدوديات في المتصفحات الحالية في حديثي عن اللمحة التاريخية عن محاولات تخزين البيانات محليًا باستخدام إضافات خارجية، حرصتُ على ذكر محدوديات كل تقنية من تلك التقنيات، مثل محدودية المساحة التخزينية. لكنني لم أذكر شيئًا عن محدوديات التخزين المحلي في HTML5 المعياري. سأعطيك الأجوبة أولًا ثم سأشرحها. الأجوبة هي -بترتيبها حسب الأهمية-: "5 ميغابايت"، و"QUOTA_EXCEEDED_ERR" و "لا". "5 ميغابايت" هي المساحة التي يُسمَح لكل موقع بالحصول عليها افتراضيًا، وهذه القيمة متساوية -على غير العادة- بين المتصفحات، على الرغم من أنَّها مذكورة في مواصفة التخزين المحلي في HTML5 على أنَّها "اقتراح". ابقِ في ذهنك أنَّك تُخزِّن سلاسل نصية، ولا تخزِّن البيانات بصيغتها الأصلية، فلو كنت تُخزِّن الكثير من الأعداد الصحيحة (integers) أو العشرية (floats)، فسيكون الفرق في طريقة تمثيل البيانات مؤثرًا، إذ يُخزَّن كل رقم من عدد عشري كمحرف (character)، وليس بالتمثيل التقليدي لعدد عشري. "QUOTA_EXCEEDED_ERR" هو الاستثناء (exception) الذي سيُرمى (thrown) عندما تتجاوز حد 5 ميغابايت. أما "لا" فهو الجواب على السؤال البدهي الذي سيخطر ببالك: "هل يمكنني طلب المزيد من المساحة التخزينية من المستخدم؟" إلى حد الساعة، لا تدعم أيّة متصفحات أي آلية يتمكن خلالها مطورو الويب من طلب المزيد من المساحة التخزينية. لكن بعض المتصفحات (مثل Opera أو Firefox) تسمح للمستخدم أن يتحكم بالحدّ الأقصى للتخزين المحلي، لكن هذا منوطٌ بالمستخدم تمامًا، ولا يمكنك -كمطوِّر ويب- الاعتماد على ذلك لبناء تطبيقك. مثال عملي عن استخدام التخزين المحلي لنأخذ مثالًا عمليًا عن التخزين المحلي في HTML. هل تتذكر لعبة الضامة التي بنيناها في الدرس الذي يتحدث عن canvas؟ هنالك مشكلة صغيرة مع هذه اللعبة: ستخسر تقدّمك في اللعبة عندما تُغلِق نافذة المتصفح. لكن باستخدام التخزين في HTML5، سنستطيع حفظ التقدّم محليًا داخل المتصفح. هذا مثالٌ حيّ للعبة بعد التعديل. حرِّك بعض القطع، ثم أغلق لسان الصفحة (أو المتصفح)، ثم أعد فتح الصفحة. فإذا كان يدعم متصفحك التخزين المحلي، فيجب أن تتذكر الصفحة السابقة خطواتك التي أجريتها في اللعبة، بما في ذلك عدد الخطوات التي تحركت بها، ومكان كل قطعة على رقعة اللعب، وحتى آخر قطعة قمتَ بتحديدها. ما هي الآلية التي اتبعناها لفعل ذلك؟ سنستدعي الدالة الآتية في كل مرّة يطرأ فيها تغيير داخل اللعبة: function saveGameState() { if (!supportsLocalStorage()) { return false; } localStorage["halma.game.in.progress"] = gGameInProgress; for (var i = 0; i < kNumPieces; i++) { localStorage["halma.piece." + i + ".row"] = gPieces[i].row; localStorage["halma.piece." + i + ".column"] = gPieces[i].column; } localStorage["halma.selectedpiece"] = gSelectedPieceIndex; localStorage["halma.selectedpiecehasmoved"] = gSelectedPieceHasMoved; localStorage["halma.movecount"] = gMoveCount; return true; } كما لاحظت، تستعمل الدالة السابقة الكائن localStorage لتخزين أنَّ المستخدم قد بدأ اللعب (المفتاح gGameInProgress، الذي هو قيمة منطقية [Boolean]). ثم ستدور حلقة for على جميع القطع (المتغير gPieces، الذي هو مصفوفة في لغة JavaScript) ثم يحفظ رقم السطر والعمود لكل قطعة؛ ثم تحفظ الدالة بعض المعلومات الإضافية عن اللعبة، بما في ذلك القطعة التي تم تحديدها (القيمة gSelectedPieceIndex، التي هي رقمٌ صحيح [integer])، وفيما إذا كانت القطعة في منتصف سلسلة من القفزات (القيمة gSelectedPieceHasMoved، التي هي قيمة منطقية)، والعدد الكلي للحركات التي قام بها اللاعب (القيمة gMoveCount، التي هي عدد صحيح). وعند تحميل الصفحة، وبدلًا من الاستدعاء التلقائي للدالة newGame()‎ التي ستُعيد ضبط جميع المتغيرات إلى قيم مُحدَّدة مسبقًا، فسنستدعي الدالة resumeGame()‎. التي تتحقق -باستخدام التخزين المحلي في HTML5- فيما إذا كانت هنالك نسخة محفوظة من اللعبة مُخزَّنةٌ محليًا؛ فإن وُجِدَت، فستُستعاد تلك القيم باستخدام الكائن localStorage. function resumeGame() { if (!supportsLocalStorage()) { return false; } gGameInProgress = (localStorage["halma.game.in.progress"] == "true"); if (!gGameInProgress) { return false; } gPieces = new Array(kNumPieces); for (var i = 0; i < kNumPieces; i++) { var row = parseInt(localStorage["halma.piece." + i + ".row"]); var column = parseInt(localStorage["halma.piece." + i + ".column"]); gPieces[i] = new Cell(row, column); } gNumPieces = kNumPieces; gSelectedPieceIndex = parseInt(localStorage["halma.selectedpiece"]); gSelectedPieceHasMoved = localStorage["halma.selectedpiecehasmoved"] == "true"; gMoveCount = parseInt(localStorage["halma.movecount"]); drawBoard(); return true; } أهم فكرة في هذه الدالة هي تطبيق التحذير الذي ذكرته لك سابقًا في هذا الدرس، وسأكرره هنا: "ستُخزَّن البيانات كسلسلة نصية، وهذا يعني أنَّه لو لم تكن القيمة المُخزَّنة نصيةً فستحتاج إلى تحويل البيانات التي حصلت عليها إلى نوع البيانات الذي تريده". فعلى سبيل المثال، القيمة التي تُحدِّد فيما إذا كانت هنالك لعبة قيد اللعب (gGameInProgress) هي قيمة منطقية، وفي الدالة saveGameState()‎ خزَّنا القيمة دون أن نلقي بالًا لنوعها: localStorage["halma.game.in.progress"] = gGameInProgress; لكن في دالة resumeGame()‎ علينا أن نُعامِل القيمة التي أخذناها من التخزين المحلي كسلسلةٍ نصيةٍ كالآتي: gGameInProgress = (localStorage["halma.game.in.progress"] == "true"); وبشكلٍ مشابه، يُخزَّن عدد الخطوات في gMoveCount كعددٍ صحيحٍ؛ فلقد خزَّناها ببساطة في الدالة saveGameState()‎: localStorage["halma.movecount"] = gMoveCount; لكن في دالة resumeGame()‎ علينا أن نحوِّل القيمة إلى عدد صحيح باستخدام الدالة parseInt()‎ الموجودة في JavaScript: gMoveCount = parseInt(localStorage["halma.movecount"]); مستقبل التخزين المحلي في تطبيقات الويب على الرغم من أنَّ الماضي كان مليئًا بالطرق الالتفافية، لكن الوضع الراهن للتخزين المحلي في HTML5 مشرقٌ، فهنالك واجهة برمجية (API) جديدة قد وُضِعَ لها معيارٌ وطبِّق هذا المعيار في جميع المتصفحات الرئيسية على مختلف المنصات والأجهزة. فهذا أمرٌ لا تراه كل يوم كمطوِّر ويب، أليس كذلك؟ لكن ألا تتطلع إلى أكثر من "5 ميغابايت من الثنائيات على شكل "مفتاح/قيمة"؟ حسنًا، هنالك عدد من الرؤى التنافسية لمستقبل التخزين المحلي. إحدى تلك الرؤى هي اختصارٌ تعرفه بالتأكيد: SQL. أطلقَت Google في عام 2007 إضافة Gears المفتوحة المصدر التي تعمل على مختلف المتصفحات والتي احتوت على قاعدة بيانات مُضمَّنة فيها مبنية على SQLite. أثَّر هذا النموذج الأولي لاحقًا على إنشاء مواصفة Web SQL Database، والتي كانت تعرف رسميًا باسم "WebDB" التي توفر طبقةً للوصول إلى قاعدة بيانات SQL، سامحةً لك بالقيام بأشياء شبيهة بما يلي عبر JavaScript (لاحظ أنَّ الشيفرة الآتية حقيقية وتعمل على أربعة متصفحات): openDatabase('documents', '1.0', 'Local document storage', 5*1024*1024, function (db) { db.changeVersion('', '1.0', function (t) { t.executeSql('CREATE TABLE docids (id, name)'); }, error); }); كما لاحظت، ما يهم في الشيفرة السابقة هو السلسلة النصية التي مررتها إلى الدالة executeSql، ويمكن أن تحتوي تلك السلسلة النصية على أيّة تعليمات SQL مدعومة، بما في ذلك SELECT و UPDATE و INSERT و DELETE. الأمر هنا شبيهٌ ببرمجة قواعد البيانات بلغةٍ مثل PHP، إلا أنَّك تقوم بذلك عبر JavaScript! طُبِّقت مواصفات Web SQL Database من أربعة متصفحات ومنصات. IE Firefox Safari Chrome Opera iPhone Android . . 4.0+ 4.0+ 10.5+ 3.0+ 2.0+ وبكل تأكيد، لو سبق وأن استخدمت أكثر من مُحرِّك لقواعد البيانات في حياتك، فأنت تعلم أنَّ "SQL" هي مصطلح تسويقي أكثر من كونها معيارًا متكاملًا (قد يقول البعض أنَّ HTML5 كذلك، لكن لا تأبه بقولهم). حسنًا، هنالك معيار للغة SQL (يسمى SQL-92) لكن لا يوجد خادوم قواعد بيانات في العالم يتوافق تمامًا مع ذاك المعيار. فهنالك نسخة SQL لقواعد بيانات Oracle، ونسخة أخرى لقواعد MSSQL، ونسخة أخرى لقواعد بيانات MySQL، وأخرى لقواعد بيانات PostgreSQL، ولا ننسَ نسخة SQL لقواعد بيانات SQLite. وحتى كل منتج من تلك المنتجات يُضيف ميزات SQL جديدة على مرّ الزمن، وبهذا يكون قولنا "نسخة SQL لقواعد بيانات SQLite" ليس كافيًا لتحديد ما نتحدث عنه بدقّة. فعليك أن تقول "نسخة SQL التي تأتي مع قواعد بيانات SQLite ذات الإصدار X.Y.Z". كل ما سبق أدى إلى الإعلان الآتي، التي يقبع الآن في أعلى صفحة مواصفة Web SQL Database: وعلى ضوء هذا، سأعرِّفك على رؤية تنافسية أخرى لتخزينٍ محليٍ متقدم وثابت لتطبيقات الويب: Indexed Database API المعروفة رسميًا باسم "WebSimpleDB" التي اشتهرت باسم "IndexedDB". تحتوي IndexedDB على ما يُسمى "مخزن الكائنات" (object store)، الذي يتشارك مع قاعدة بيانات SQL في الكثير من المفاهيم؛ فهنالك "قواعد بيانات" (databases) فيها "سجلات" (records)، ويملك كل سجل عددًا من "الحقول" (fields)، وكل حقل له نوع بيانات معيّن، الذي يُعرَّف عند إنشاء قاعدة البيانات. تستطيع أيضًا تحديد مجموعة فرعية من السجلات، ثم تعرضها عبر "مؤشر" (cursor)، ويتم التعامل مع التغييرات على مخزن الكائنات عبر "التحويلات" (transactions). إذا سبق وأن برمجتَ قليلًا بأي نوع من أنواع قواعد بيانات SQL ، فمن المرجح أن تبدو المصطلحات السابقة مألوفةً لديك. الفرق الرئيسي هو أنَّ "مخزن الكائنات" ليس لديه "لغة استعلام بنيوية"، لا تستطيع كتابة عبارات مثل "SELECT * from USERS where ACTIVE = 'Y'‎" لكنك تستطيع استخدام الدوال التي يوفرها مخزن الكائنات لفتح "مؤشر" (cursor) في قاعدة البيانات "USERS"، ثم تمر عبر السجلات، وتستبعد سجلات المستخدمين غير النشيطين، ثم تستخدم دوالًا للوصول إلى قيم كل حقل في السجلات المتبقية. دعم IndexedDB موجودٌ في Firefox منذ الإصدار 4.0 (صرَّحَت Mozilla أنَّها لن تدعم Web SQL Database في متصفحها)، وChrome منذ الإصدار 11، وحتى Internet Explorer أصبح يدعم IndexedDB منذ الإصدار 10. ترجمة -وبتصرّف- لفصل "Local Storage" من كتاب Dive Into HTML5 لمؤلفه Mark Pilgrim. اقرأ أيضًا المقال التالي: تطبيقات الويب التي تعمل دون اتصال – الجزء الأول المقال السابق: تحديد الموقع الجغرافي (GeoLocation) في HTML5 النسخة العربية الكاملة من كتاب نحو فهم أعمق لتقنيات HTML5
    1 نقطة
  46. عادة ما يرتكب القادم الجديد إلى عالم HTML5 أخطاء عديدة ترجع إما لعدم فهمه للعناصر الجديدة أو الإفراط في استخدامها مكان العناصر القديمة. سنحاول في هذا المقال تسليط الضوء على أكثر الأخطاء شيوعا وكيفية تجنب الوقوع فيها. لا تستخدم <section> كأداة للتغليف بدل <div>أحد أكثر الأخطاء شيوعا هو الاستبدال المفرط لكل عناصر <div> بعناصر <section> في شفرات HTML5 وخاصة لما يتعلق الأمر بعناصر <div> المستخدمة لأغراض تنسيقية styling. سابقا لدى استخدامنا لـ XHTML و HTML4 كنا نكتب الشفرات على النحو التالي: <!-- HTML 4-style code --> <div id="wrapper"> <div id="header"> <h1>My super duper page</h1> <!-- Header content --> </div> <div id="main"> <!-- Page content --> </div> <div id="secondary"> <!-- Secondary content --> </div> <div id="footer"> <!-- Footer content --> </div> </div>بعض ظهور HTML5 أصبح العديد يكتبونها على النحو التالي: <!-- Don’t copy this code! It’s wrong! --> <section id="wrapper"> <header> <h1>My super duper page</h1> <!-- Header content --> </header> <section id="main"> <!-- Page content --> </section> <section id="secondary"> <!-- Secondary content --> </section> <footer> <!-- Footer content --> </footer> </section>وهو أمر خاطئ لأنه وبكل بساطة لا يعتبر عنصر <section> أداة تغليف wrapper، حيث أنه يتم استخدام هذا العنصر مع الأجزاء الدلالية للصفحة لبناء مخطط واضح المعالم لها، كما أنه من الواجب أن يحتوي على ترويسة heading. إن كان كل ما ترغب في القيام به هو إضافة نمط style لصفحتك فحاول أن تنفذه مباشرة على عنصر <body> ، أما لو احتجت عناصر إضافية للنمط الذي تود تنفيذه فعليك استخدام <div> في هذه الحالة وهو العنصر الأنسب لما يكون كل ما تحتاجه هو أداة لتنفيذ الأنماط. بناء على ما سبق ذكره فإن الطريقة الصحيحة لكتابة الشفرة السابقة باستخدام HTML5 وبعض وظائف ARIA (ملاحظة: قد تحتاج إلى عنصر <div> واحد فقط بناء على التصميم الذي ترغب فيه) هو على النحو التالي: <body> <header> <h1>My super duper page</h1> <!-- Header content --> </header> <div role="main"> <!-- Page content --> </div> <aside role="complementary"> <!-- Secondary content --> </aside> <footer> <!-- Footer content --> </footer> </body>إذا لم تكت تعلم ما هي العناصر التي يجب عليك استخدامها فيُمكنك الاستعانة بالصورة التالية التي ستسهل عليك الاختيار لا تستخدم عنصر header ما لم يكن هناك حاجة إليهملاحظة: في المقال الأصلي تم الحديث عن عنصري header و hgroup، وبما أنه تم التخلص من هذا الأخير من مواصفات HTML5 فلم أقم بتضمينه في الترجمة. لا توجد أية معنى لإضافة عناصر إضافية إلى صفحتك ما لم يكن هناك حاجة لها، لكن رغم ذلك عادة ما نلحظ استخدام عنصر <header> لما لا تكون هناك أية حاجة إلى استخدامه. يُمكنك معرفة كيفية استخدام هذا العنصر بقراءتك لهذا المقال والذي يُمكن تلخيصه في أن العنصر <header> يلعب دور عنصر مساعد أو مقدم لمحتوى الجزء الذي يحتويه. وبما أنه يُمكن استخدام عنصر <header> أكثر من مرة واحدة في نفس الصفحة فإنه عادة ما تتم إساءة استخدامه على النحو التالي: <!-- Don’t copy this code! No need for header here --> <article> <header> <h1>My best blog post</h1> </header> <!-- Article content --> </article>إن كان عنصر header الذي تستخدمه لا يحتوي سوى على عنصر رأسي heading element واحد فمن الأفضل تجنب استخدامه، حيث أن عنصر article سيضمن تضمين هذا العنصر الرأسي في مُخطط الصفحة document outline. وبما أنه سيحتوي عنصرا واحدا فقط (عكس ما تشير إليه مواصفات العنصر) فإنه من الأفضل كتابة الشفرة بشكل مبسط على النحو التالي: <article> <h1>My best blog post</h1> <!-- Article content --> </article>لا تُغلف كل قوائم الروابط باستخدام navلم يعد من السهل -مع كل العناصر الجديدة التي تمت إضافتها إلى HTML5- اختيار العنصر الأنسب لكثرة الاختيارات المتاحة، لكنه في المقابل لا يجب علينا أن نُفرط في استخدام العناصر الدلالية الجديدة وهو أمر عادة ما نلاحظه مع العنصر nav والذي تنص مواصفاته على التالي: يُمثل عنصر nav قسما من الصفحة تقوم بالربط إلى صفحات أخرى أو إلى أجزاء أخرى من نفس الصفحة. ملاحظة: لا يجب أن تكون كل مجموعات الروابط داخل عناصر <div>، يجب اقتصار استعمال هذا العنصر على كتل التصفح Navigation blocks الرئيسية فقط. فعلى سبيل المثال عادة ما يحتوي أسفل الصفحات footers على قوائم قصيرة لروابط لمختلف صفحات الموقع مثل قواعد استخدام المواقع، صفحة البداية وصفحة حقوق الملكية الفكرية. في مثل هذه الحالات يكفي استخدام عنصر footer لكنه يبقى استخدام عنصر nav ممكنا رغم أنه غير ضروري. WHATWG HTML spec الكلمة المفتاحية في هذه المواصفات هي "الرئيسية"، قد نختلف فيما تعنيه هذه الكلمة على وجه التحديد، لكنه عادة ما يُقصد بها: روابط تصفح الموقع الرئيسيةمحرك بحث الموقعروابط تصفح الموقع الثانويةروابط التنقل داخل الصفحة الواحدة (خاصة في الصفحات والمقالات الطويلة).بالرغم من أنه يصعب تمييز الصحيح من الخطأ في الكثير من الحالات إلا أنه يبدو بأنه من الأفضل تجنب استخدام nav في الحالات التالية: ترقيم الصفحاتالروابط الاجتماعية (قد يكون لهذا الأمر استثناءات خاصة إذا ما كانت هذه الروابط جزءا أساسيا في الصفحة مثلما هو الحال مع موقعي about me و flavours)الوسوم أو التصنيفات في التدويناتالروابط الثانويةأسفل الصفحات (footers)إن لم تعرف ما إذا كان بإمكانك استخدام عنصر nav اسأل نفسك، هل الروابط التي تنوي تغليفها داخل عنصر nav هي وسيلة أساسية للانتقال داخل الصفحة أو داخل الموقع؟ يمكنك الاستعانة بالنقطتين التاليتين للإجابة على هذا السؤال: لا تستخدم nav ما لم تعتقد بأنه يُمكن استبدال الأمر بعنصر <section> باستخدام عنصر hxهل كنت ستضيف عنصر "اذهب مباشرة إلى" للوصول إليها لتحسين قابلية وصول الموقع؟إن كانت إجابتك بالنفي فإنه من الأجدر بك عدم استخدام عنصر nav. أخطاء شائعة مع عنصر figureليس من السهل إتقان استخدام عنصر figure (وعنصر figcaption الذي يلازمه). إليكم بعض الأخطاء الشائعة التي يقع الكثيرون لدى استعمالهما. لا تستعمل figure مع جميع الصوركما سبق وأن أشرنا إليه ، لا توجد أية فائدة من كتابة شفرات إضافية ما لم يكن هناك داع لها، وهو نفس الأمر الذي يتكرر مع هذا العنصر أيضا. هناك من يقوم بتحويل جميع الصور إلى figure رغم أننا في غنى عن تغليف كل صورة في هذا العنصر، كلما تقوم به لدي قيامك بهذا الأمر هو إضافة شفرات إضافية لا تقدم أية إضافة للصفحة. تحدد مواصفات HTML5 عنصر figure على النحو التالي: بعبارة أخرى figure عبارة عن محتوى قائم بذاته يحتوي وصفا يتم إضافته إلى محتوى الصفحة رغم أنه ليس جزءا أساسيا فيها. وهنا يبرز جمال عنصر figure حيث أنه بالإمكان تغيير مكانه في الصفحة إلى القائمة الجانبية sidebar مثلا دون الإخلال بمحتوى الصفحة. إن كان ما تحاول وضعه داخل figure عبارة عن محتوى جمالي فقط لا يقدم أية إضافة للمحتوى، وإن لم يكن بالإمكان الإشارة إليه في محتوى صفحتك فإنه من المحتمل جدا أن لا يكون العنصر الواجب استخدامه هو figure. يُمكنك أيضا أن تسأل نفسك "هل هذه الصورة (أو غيرها) أساسية لفهم محتوى الصفحة" إن لم يكن جوابك بالإيجاب فقد لا يكون figure هو العنصر الأنسب لك (فكر في استخدام aside حينها). أما لو أجبت بالإيجاب فاسأل نفسك "هل يمكنني تغيير مكان هذه الصورة إلى ملف ملحق appendix ؟" إن كانت إجابتك بالنفي هنا أيضا فقد لا يكون عنصر figure هو الأنسب لك أيضا. لا تستخدم figure مع شعار موقعكلا يصح أيضا استخدام figure مع شعارات المواقع أيضا. عادة ما نشاهد مثل هذه الشفرات الخاطئة في بعض المواقع: <!—Don't copy this code! It's wrong! --> <header> <h1> <figure> <img src="/img/mylogo.png" alt="My company" /> </figure> My company name </h1> </header> <!—Don't copy this code! It's wrong! --> <header> <figure> <img src="/img/mylogo.png" alt="My company" /> </figure> </header>ليس لدينا ما نقوله هنا سوى أن استخدام figure للشعارات هو استخدام خاطئ. يجب عليك تجنب استخدام figure ما لم تتم الإشارة إلى المحتوى المراد تغليفه في هذا العنصر داخل الصفحة. وبما أنه من السهل أن نجزم بأنه لن تتم الإشارة إلى شعار موقعك في أي جزء من أجزاء صفحتك، فإن كل ما تحتاجه هو: <header> <h1>My company name</h1> <!-- More stuff in here --> </header>لا يقتصر استخدام figure على الصور فقطالاعتقاد السائد هو أن استخدام عنصر figure يقتصر على الصور فقط وهو اعتقاد خاطئ حيث أنه من المُمكن استخدام figure مع الفيديوهات، الملفات الصوتية، الرسوم البيانية (على هيأة SVG مثلا)، الاقتباسات، الجداول، الشفرات المصدرية وغيرها. يعني أي محتوى يساعد على فهم المحتوى الرئيسي للصفحة وإعطاء تفاصيل إضافية حوله يصلح أن يكون داخل عنصر figure. يُمكن معرفة المزيد حول عنصر figure بقراءتك لهذا المقال. استخدام خاصية type غير الضروريةاستخدام خاصية type شائعة جدا ما بين المبرمجين، رغم أنه ليس خطأ في حد ذاته، إلا أنه من الأفضل تجنبه. ليس من الضروري لدى استخدام HTML5 التصريح بنوع عنصري script و style. قد لا يكون من السهل التخلص من الأمر خاصة إن كان إضافة هذه الخاصية يتم بشكل آلي خاصة لدى استخدام أنظمة إدارة المحتوى إلا أنه لا توجد أية حاجة ماسة لاستخدامها لما تقوم بكتابة كامل شفرة تطبيقك بشكل يدوي لأنه وبكل بساطة تتوقع جميع المتصفحات أن تكون السكربتات التي تستخدمها من نوع javascript وكل الأنماط من نوع css، وعليه فإنك لن تحتاج إلى كتابة التالي: <!-- Don’t copy this code! It’s attribute overload! --> <link type="text/css" rel="stylesheet" href="css/styles.css" /> <script type="text/javascript" src="js/scripts.js"></script>بل كل ما تحتاجه هو <link rel="stylesheet" href="css/styles.css" /> <script src="js/scripts.js"></script>كما أننا لم نعد في حاجة إلى كتابة الكثير للإشارة إلى نوعية الترميز المستخدم في الصفحة character set إضافة إلى أمور أخرى لم يعد هناك حاجة إليها ستجدها مشروحة بشكل مفصل في هذا المقال. استخدامات خاطئة لبعض خصائص النماذجكما سبق وأن أشرنا إليه، يوفر HTML5 خصائص عديدة للنماذج، ويرافق استخدام هذه الخصائص أخطاء يجب تجنبها: الخصائص المنطقيةالعديد من الخصائص الجديدة في نماذج HTML5 هي خصائص منطقية، ونعني بذلك بأنه تتم إضافة سلوك معين للنموذج أو لعنصر ما بمجرد إضافة هذا العنصر إليه، ومن بين هذه الخصائص المنطقية نجد كلا من autofocus، autocomplete و required. قد لا يكون هذه المشكل كثير الشيوع، إلا أن هناك من يستخدم هذه الخصائص المنطقية (عنصر required مثلا) على النحو التالي: <!-- Don’t copy this code! It’s wrong! --> <input type="email" name="email" required="true" /> <!-- Another bad example --> <input type="email" name="email" required="1" />لكن ماذا لو أردت "العبث" بالشفرة السابقة قليلا وأعطيت قيمة false لخاصية required، ما الذي تتوقع أن يقوم به المتصفح في هذه الحالة؟ <!-- Don’t copy this code! It’s wrong! --> <input type="email" name="email" required="false" />على غير ما تتوقع فإن المتصفح وبمجرد أن يلاحظ وجود خاصية required فإنه يقوم بجعل العنصر الذي تمت إضافته إليه ضروريا رغم أنك أعطيت الخاصية قيمة false. هناك 3 صيغ لاستخدام الخصائص المنطقية مع HTML5 (يتم استخدام الصيغتين الثانية والثالثة مع XHTML): required required="" required="required"وأفضل طريقة لكتابة الشفرة السابقة هي على النحو التالي: <input type="email" name="email" required />خلاصةاستعرضنا في هذا المقال بعضا من الأخطاء الأكثر شيوعا مع HTML5. بطبيعة الحال فإنه يستحيل حصر كل هذه الأخطاء، وبالتالي إن كانت هناك أخطاء أخرى سبق وأن شاهدتها أكثر من مرة فلا تتردد في مشاركتها معنا في التعليقات. ترجمة -وبتصرف- للمقال Avoiding common HTML5 mistakes لصاحبه Richard Clark
    1 نقطة
×
×
  • أضف...