VOL73: Payment Fees: An Engineering Breakdown
أهلًا وسهلا بكم في العدد الثالث والسبعين من النشرة الأسبوعية لاقرأ-تِك 🚀
لا تنسوا أهلنا من صالح الدعاء,اللهم إنّا استودعناك اياهم، اللهم كُن عوناً لهم، اللهم انصرهم واحفظهم. 🇵🇸
أهلًا وسهلا بكم في العدد الثالث والسبعين من النشرة الأسبوعية لاقرأ-تِك 🚀
سواء كنت مهندس برمجيات مبتدئ أو محترف، فنشرتنا هدفها انها تثري المحتوى التقني العربي سعيا للتطوير من جودة المحتوى باللغة العربية، من خلال تقديم أحدث المستجدات والتطورات في عالم البرمجيات، بالإضافة إلى أفضل الممارسات والنصائح القيمة، ونشر أحدث المقالات وترشيحات الكتب ومحتوى ورقة وقلم اللي بينزلوا بشكل مستمر في موقع اقرأ-تِك.
في الإصدار ده الفهرس هيكون كالآتي:
Payment Fees
How Canva Built Scalable and Reliable Content Usage Counting Service
React Props Best Practices for Handling Large Objects
gRPC
الإصدار الأول من مدونات فطين في تصميم النظم
Payment Fees
في حاله دفع ١٠٠ ريال في موقع الكتروني او نقاط البيع (POS)، كم يصل للتجار فعليا؟
عملية الدفع عملية معقدة بتمر بأكثر من جهة لكي تكتمل. كل جهة بيكون لها رسوم بيتم استقطاعها من مبلغ العملية قبل وصوله للتاجر.
الرسوم التي يتم خصمها تكون موزعة كالآتي:
1- الـ Interchange Fees - عمولة البنك مُصدِر البطاقة (Issuer)
البنك مُصدِر البطاقة يخصم العمولة الاكبر. وبيتم فرضها على التاجر مقابل إتاحة البطاقة وخدمة العميل.
نسبة العمولة تختلف حسب:
طبيعة نشاط التاجر (MCC: Merchant Category Code) (لو في مجال التعليم مثلا العمولة بتكون أقل من مجال آخر مثل السفر)
نوع البطاقة: بطاقة Debit رسومها اقل من ال Credit، وايضا ال card tier الأعلى مثلا (Signature / Infinite) رسومها أعلي لأنها تمول امتيازات البطاقة.
هل الدفع تم من خلال نقاط البيع POS؟ هنا بتكون العملية نوعها (Card Present) ومخاطرها ورسومها اقل، بعكس الدفع اونلاين بيكون (Card Not Present) بمستوي مخاطر ورسوم أعلي.
هل التاجر في نفس الدولة Local ام دولة اخري International. العمليات ال International او تسمي (Cross-Border) رسومها أعلى.
متوسط النسبة بيكون مثلا: 1.5٪ – 2٪
2- الـ Assessment or Network Fees: عموله شبكة البطاقة (Visa/Mastercard/Mada)
الشبكة تخصم Network Fee وهي نسبة صغيرة مقابل تمرير المعاملة عبر الشبكة وادارة عمليات الدفع.
في حالة ان العملية عبر دولة مختلفة (Cross-Border) بتزيد العمولة أو لو عملة مختلفة فبتطلب تحويل للعملات (Currency Conversion) بتزيد العمولة.
متوسط النسبة بيكون مثلا: 0.1٪ – 0.3٪
3- الـ Acquirer Markup: عمولة بنك التاجر (Acquirer Bank)
بيتم خصم رسوم مقابل إدارة حساب التاجر وتحمله جزء من مخاطر عمليات الدفع.
بنك التاجر (Acquirer) يضيف نسبة أو مبلغ ثابت فوق الرسوم الأساسية (Interchange + Network Fees)، ويقدّمها للتاجر في صورة عمولة واحدة.
ايضا النسبة تعتمد علي طبيعة نشاط التاجر (MCC: Merchant Category Code)، وكمان عدد عمليات التاجر.
قد تزيد النسبة بناء علي معدل عمليات الاعتراض علي الدفع (Chargeback) الخاص بالتاجر.
متوسط النسبة بيكون مثلا: 0.5٪ – 1.5٪
4- الـ Gateway Fees: عمولة بوابة الدفع
عمولة بيتم خصمها مقابل توفير الواجهة البرمجية للربط. بالإضافة لتأمين بيانات الدفع (PCI DSS Compliance).
ابضا تعتمد علي المميزات المقدمة من بوابه الدفع: فعلي سبيل المثال بعض بوابات الدفع تفرض رسوم اضافية علي ال Auth/Cap (امكانية حجز المبلغ لمدة وخصمه بعد فترة من الدفع) عن ال Purchase (الدفع المباشر).
How Canva Built Scalable and Reliable Content Usage Counting Service
مهمة Canva ورؤيتهم إنهم يمكنوا أي شخص في العالم من تصميم أي حاجة ونشرها في أي مكان. وجزء مهم من تحقيق الهدف ده هو برنامج Canva Creators.
من ساعة إطلاق البرنامج من 3 سنين تقريبًا، واستخدام المحتوى اللي بيقدموه الـ creators تضاعف في خلال 18 شهر. وحاليًا هم بيحسبوا ويدفعوا بناءً على مليارات الاستخدامات للمحتوى ده كل شهر للـ creators.
وطبعًا البيانات دي مش بتشمل templates بس، لكنها كمان بتضم الصور، والفيديوهات، وغيرهم من المحتوى اللي بيتم استعماله.
فبناء وصيانة خدمة لتتبع البيانات دي علشان الدفع يكون مظبوط وموثوق للـ creators كان فيه تحديات كتير زي:
الدقة (Accuracy): عدد الاستخدامات لازم يكون مظبوط 100% لأن الدخل المالي وثقة الـ creators معتمدين عليه.
القابلية للتوسع (Scalability): تخزين ومعالجة البيانات اللي بيتم استخدامها بشكل مهول وكبير جدًا بالإضافة لإنها في تزايد مستمر.
سهولة التشغيل (Operability): مع زيادة حجم بيانات الاستخدام، بيزيد التعقيد في الصيانة، والتعامل مع المشاكل اللي ممن تحصل، وأيضًا استرجاع البيانات في حالة أي مشاكل حصلت.
رحلة التطوير والبداية مع MySQL
في الأول كانوا بيستعملوا MySQL لأنهم كانوا متعودين عليه. وبالتالي بنوا الأجزاء الكبيرة من الـ Architecture بشكل منفصل باستخدام Worker Services، وكان عندهم طبقات متعددة من النتائج الوسيطة أو الـ Intermediary Output.
فبكل بساطة كان عندهم Raw Usage من الـ Events اللي بتحصل وفيه Worker Service بيقوم بعمل الـ Deduplication على الـ raw usage events وبعدين يحطهم في قاعدة بيانات مستقلة للـ deduplicated usage events وفيه عندنا Aggregation Workers هم اللي بيقرأوا من قاعدة البيانات دي ويبدأوا يعملوا الحسابات وزيادة الـ usage counters ويعملوا update في الـ Aggregated Usages ودي برضو قاعدة بيانات منفصة.
بس للأسف ظهر عندهم 3 مشاكل:
1- قابلية التوسع في معالجة البيانات (Processing Scalability)
كل record عشان يحصله processing أو معالجة كان بيتطلب round-trip رايح جاي من الـ Database، وده كان غير عملي مع زيادة الحجم الضخم للـ events.
2- التعامل مع الـ Incidents
أي مشكلة كانت بتحصل كانت معقدة وبتاخد وقت كبير للتعامل معاها. وده لإن المهندسين كانوا مضطرين يبصوا في الـ Database ويشوفوا المشكلة فين ويصلحوا الـ data اللي فيها مشكلة. وقدروا إنهم يعملوا categorization لأنواع المشاكل اللي بتحصل وكانت كالآتي:
مشكلة الـ Overcounting: الزيادة بتحصل لما الـ (Event Source) يضيف نوع جديد من الـ event المفروض إنه ما يتمش حسابه، والـ (Consumers) مايعرفوش ده. النتيجة إنه النوع الجديد ده بيتحسب بالغلط في مراحل الـ Deduplication والـ Aggregation.
وطبعًا عشان يعالجوا النوع ده من المشاكل:
أول حاجة بيحددوا الـ events اللي اتحسبت بالغلط ويقفوا الـ Pipeline بتاع الـ Deduplication والـ Aggregation.
بعد كده بيحسبوا عدد الـ events اللي اتعالجت بالغلط ويشيلوها من جدول الـ Deduplication ويصححوا البيانات في جدول الـ Aggregation.
العملية دي بتاخد وقت ومجهود كبير من فريق المهندسين.
مشكلة الـ Undercounting: أحيانًا بيتم إضافة نوع جديد من الـ events اللي المفروض يتحسب في عملية الدفع، ولكن الـ (Event Source) فشل بطريقة ما إنه يـ integrate مع الـ (Usage Services)، وبالتالي الـ events دي ما بتتجمعش.
بيحددو ا الفترة الزمنية اللي فيها البيانات المفقودة (Missing Data Window).
بعد كده بيبجيبوا البيانات دي من (Backup Data Source)، ودي أكتر خطوة بتاخد وقت ومجهود.
بعد ما يتم جمع البيانات من الـ Backup، بيرجعوها للـ Service مرة تانية المسئولة ويبدأوا يعيدوا معالجتها.
طبعًا لو حجم البيانات كبير، العملية دي ممكن تاخد أيام، وده ممكن يأخر الدفع بسبب مشاكل الأداء اللي اتكلمنا عنها قبل كده.
مشكلة الـ Misclassification: الخطأ ده بيحصل أثناء مرحلة الـ Deduplication، لما event معين (Usage Event) المفروض يتصنف على إنه نوع "A" ويتم تصنيفه بالغلط على إنه نوع "B". المشكلة هنا إنهم بيدفعوا أسعار مختلفة على حسب النوع.
أول حاجة بيحددوا سبب المشكلة، وغالبًا ده بيكون Bug في الكود.
بيصلحوا الـ Bug وطبعًا يوقفوا الـ Pipeline.
بعد كده بيصححوا البيانات في جدول الـ Deduplication وجداول المراحل اللي بعد كده عن طريق إعادة حساب البيانات مرة تانية.
العملية دي مرهقة جدًا وبتاخد أيام، وبتحتاج أكتر من مهندس علشان يتأكدوا من صحة البيانات بعد التصليح.
مشكلة الـ Processing Delay: دي مشكلة Performance بسبب إن المعالجة كانت بتعتمد على عملية Sequential بتتم من خلال الـ (Single-threaded Sequential Scan) ومع عدد كبير من الـ round-trips بين الـ Service وقاعدة البيانات.
3- استهلاك التخزين
مساحة التخزين في MySQL RDS كانت بتتستهلك بسرعة جدًا، والمشكلة إن MySQL مش بتعمل Horizontal Scaling من خلال الـ Partitioning بشكل تلقائي على سبيل المثال. فكان الحل مضاعفة حجم الـ RDS Instance كل 8-10 شهور.
قسموا قواعد البيانات (Database Split) علشان يوزعوا الحمل.
عملوا أدوات زي الـ (Sweepers) بتنضف البيانات القديمة من فترة للتانية.
بس مع زيادة عدد الـ events بشكل كبير، كان واضح إن الحل ده مش هيكمل على المدى الطويل.
Migration to DynamoDB
مبدئيًا عشان يحلوا مشكلة الـ Scalability اللي كانت ظاهرة بشكل مستمر ، أول حاجة عملوها هي إنهم نقلوا الـ Raw Usage Events اللي كانت في مرحلة الـ Collection لـ DynamoDB وده ساعد في تقليل الضغط على مساحة التخزين اللي كانت بتتزايد بشكل مستمر.
Simplify using OLAP and ELT
في النهاية قرروا إنهم يغيروا من طريقة تفكيرهم ويقوموا بعمل دمج للمرحلتين الـ Deduplication والـ Aggregation من خلال Service تعمل end-to-end calculation باستعمال الـ raw usage events اللي هي المصدر الأساسي للبيانات.
React Props Best Practices for Handling Large Objects
عند استخدام React ، تعد إدارة البيانات بين الـ Components أمرًا أساسيًا. واحدة من التحديات الشائعة التي يواجهها المطورون هي كيفية التعامل مع الـ props عند الحاجة إلى تمرير objects كبيرة تحتوي على بيانات متعددة.
في هذا المقال، نستعرض أفضل الممارسات للتعامل مع هذا السيناريو مع تسليط الضوء على مزايا وعيوب كل أسلوب.
تمرير الـ object بالكامل
في هذه الطريقة، يتم تمرير الـ
object
بالكامل كـprop
. داخل الـUserProfile Component
، يمكن الوصول إلى الحقول المطلوبة (مثلuser.name
أوuser.avatar
) حسب الحاجة.
<UserProfile user={user}/>;
المزايا
سهولة وسرعة التنفيذ: تمرير الـ object بالكامل بسيط ولا يتطلب تعديلات إضافية على الكود.
مرونة مستقبلية: إذا احتاج الـ component إلى المزيد من الحقول لاحقًا، فإنها تكون متاحة بالفعل.
العيوب
أداء أقل: تمرير object كبير قد يؤدي إلى حدوث (re-rendering) بشكل غير ضروري إذا تغير أي جزء من الـ object، حتى وإن لم يكن مرتبطًا بالـ component.
زيادة البيانات المرسلة: قد يتم تمرير بيانات غير ضرورية للـ component، مما يستهلك ذاكرة إضافية.
ترابط قوي بين ال components: يصبح الـ Component معتمدًا بشكل مباشر على بنية الـ object، مما يجعل إعادة الهيكلة أكثر تعقيدًا.
تمرير الحقول المطلوبة فقط
في هذه الطريقة، يتم استخلاص الحقول المطلوبة فقط من الـ object وتمريرها كـ props منفصلة.
<UserProfile name={user.name} avatar={user.avatar} />;
المزايا
أداء أفضل: يقلل من احتمالية حدوث (re-rendering) غير الضرورية لأن React تقوم بمقارنة الحقول الفردية بكفاءة أعلى من مقارنة الـ objects.
تقليل حجم البيانات: يتم تمرير البيانات المطلوبة فقط، مما يحسن من استخدام الموارد.
تقليل الترابط: يصبح الـ Component أكثر استقلالية عن بنية الـ object، مما يسهل إعادة هيكلة الكود لاحقًا.
العيوب
مزيد من العمل اليدوي: إذا كان هناك عدد كبير من الحقول، فقد يكون من المرهق تمرير كل حقل يدويًا.
تعديلات مستقبلية: إذا احتاج الـ Component إلى حقول جديدة، يجب تحديث الكود في الـ Parent Component لتمريرها.
gRPC
الـ gRPC هي اختصار لـ Google Remote Procedure Call وهي تكنولوجيا بتخلي الـ Service تقدر تنادي الـ function اللي موجودة في Service تانية كأنها بتناديها عادي كـ Function Call، حتى لو الـ Service التانية دي مكتوبة بلغة برمجة مختلفة ومش موجودة على نفس الـ Machine!
بشكل أبسط يعني لو عندنا Service مكتوبة بـ Java و Service تانية مكتوبة بـ Python، نقدر نخلي الـ Python ينادي Function في الـ Java بسهولة.
في الـ Microservices لو كل Service بدأت تعمل Generate لـ Client Library عشان الـ Services التانية تستخدمها ، هنضطر نعمل Client Library بلغات برمجة مختلفة على حسب الـ Services التانية ، وده مش حاجة منطقية! وهنا بتيجي ميزة الـ gRPC في انها بتوفر Unified Framework وكمان Language Agnostic ، فاحنا بنقول ده الـ proto اللي عاوزها والـ Client بيستعمل الـ gRPC Framework في انه يبعتلنا الـ Proto ويستقبل الـ Proto كـ Response وخلاص.
الـ gRPC بيبدأ من الـ Schema ، بـ Define الـ APIs بتاعتي وبقول دول الـ Functions اللي عندي أو الـ Contracts بتاعتي ، وبحدد الـ Request/Response كـ proto واللي هي اختصار للـ Protocol Buffer.
الـ gRPC شغال إزاي؟
الـ gRPC بيعتمد على حاجة اسمها Protocol Buffers (Protobuf). دي زي JSON كده، بس أخف وأسرع، بتستخدمها علشان توصف شكل البيانات اللي رايحة واللي جاية.
فبدل ما نبعت JSON كبير ومليان تفاصيل، بنكتب ملف .proto
نعرف فيه الـ Message والـ Functions اللي عاوزين نتبادلها بين الـ Client والـ Server.
فانا بقول عندي service x بتشمل الـ functions الآتية وكل function بتستقبل proto request وبترجع proto response وخلاص كده ، فمش محتاج باه احدد الـ params دي هتيجي من الـ query , url , body والـ complexity بتاعة الـ REST
خصم 50% على جميع خطط الاشتراك السنوية لفترة محدودة، تقدروا دلوقتي تشتركوا في اقرأ-تِك وتستمتعوا بكافة المقالات في كل ما يخص هندسة البرمجيات باللغة العربية والمحتوى المميز من ورقة وقلم ومدونات فطين اللي بيتميزوا بتصاميم ذات جودة عالية وكل ده بحرية كاملة وكمان مفاجآت اقرأ-تِك الجاية 🚀
وبرضو متاح الاشتراك من خلال InstaPay و VodafoneCash 🎁
مدونات فطين في تصميم النظم - الإصدار الأول 🚀
كتابة هذا الكتاب لم تكن قرارًا مخططًا... بل كانت نتيجة لتراكمات من الحيرة، الإحباط، والدهشة اللي بيواجهوا أغلب الشباب حاليًا خصوصًا في رحلة البحث عن تعلم مهارات تصميم النظم واللي أصبحت من المهارات الأساسية في الانترفيوهات بالإضافة لكونها مهمة فعلًا على جميع المستويات.
على مدار سنوات من العمل داخل شركات تكنولوجية متعددة، وجدت نفسي مرارًا أواجه بعض الأسئلة زي:
لماذا صُمّم هذا النظام بهذه الطريقة؟
لماذا لم نرَ المشكلة إلا بعد فوات الأوان؟
هل كان يمكن أن نصمم الأمر بشكل أبسط؟
الإجابات كانت دائمًا معقدة، وتعود لأبعاد تقنية وتنظيمية ونفسية أيضًا.
هذا الكتاب ليس دليلًا أكاديميًا، بل هو مجموعة من التجارب والخبرات العملية كتبتها بعين المهندس الذي يراقب، يسأل، ويُخطئ ثم يتعلّم. المجموعة دي لم يتم ترجمتها للعربية من مدونات الشركات العالمية .. بل تم اعادة شرحها وتبسيطها باللغة العربية بأسلوب مختلف حتى تتسم بالبساطة بالإضافة لتميزها بالرسوم التوضيحية الجذابة.
اخترت اسم "فَطين" لأنه الشخصية التي تمنيت لو كانت موجودة معي منذ البداية— يسأل الأسئلة الصحيحة، ويفكّر بصوت عالٍ، ويحكي لك الدروس المستفادة.
إن كنت مهندسًا في بداية الطريق، أو تعمل منذ سنين ولديك خبرة متوسطة أو متقدمة في تصميم وبناء النظم فهذا الكتاب كتبته لك ليكون مرجعًا عمليًا لك يساعدك في تطوير مهاراتك التحليلية والفكرية في بناء وتطوير النظم الضخمة.
يتناول الكتاب ما يعادل من 15 تجربة عملية مميزة من داخل الشركات العالمية في تصميم النظم الضخمة بأكتر من 160 صفحة ويضم الآتي :
Introduction Into System Design
How Uber Serves Over 40 Million Reads Per Second
How Discord Stores Trillions of Messages
Dropbox's Chrono: Scalable, Consistent and Metadata Caching Solution
Unlocking Notion's Power - The Data Model Explained
How Shopify Mitigates Deadlocks in High Concurrency Environments
How LinkedIn Improves Microservices Performance With Protobuf
How Figma Secures Internal Web Applications
How GitHub Improves Reliability of Code Push Processing
How Meta Leverages AI For Efficient Incident Response
How Stripe Architected Massive Scale Observability Solution on AWS
Change Data Capture at Pinterest
How Canva Built Scalable and Reliable Content Usage Counting Service
How Netflix Migrates Critical Traffic at Scale With No Downtime
How Slack Handles Billions of Tasks in Milliseconds
How YouTube Supports Billions of Users With MySQL
System Design Comprehensive Guide
تقدروا تشوفوا النسخة كاملة من هنا كـ E-Book ، وحاولنا نخليها بسعر رمزي يناسب الجميع 👇
وكمان وفرناه على Kindle عشان الناس اللي بتحب تجربة القراءة على الـ Kindle منحرمهاش من التجربة الممتعة دي 🎉
بفضل الله أصبح متاح حاليا دعمنا من خلال الرعاة والشراكات وفعلنا الـ Sponsorship واحنا بنرحب بجميع الشراكات مع المؤسسات والشركات وأصحاب الأعمال لبناء مجتمع عربي يشجع على القراءة والتعلم ومشاركة التجارب والخبرات العملية في هندسة البرمجيات.
دورك كشريك أو راعي هيكون محوري في دعم المحتوى وتوسيع نطاق تأثيره. فانضم لرحلتنا وكن جزءًا من صناعة مستقبل التكنولوجيا في المنطقة 🚀
تقدروا تشوفوا التفاصيل كاملة من هنا والـ Analytics بتاعتنا من خلال اقرأ-تِك والنشرة الأسبوعية 👇
رؤيتنا هي إثراء المحتوى التقني العربي وجعل التعلم من خلال القراءة أمتع، وذلك من خلال إثراء المحتوى التقني باللغة العربية وتشجيع المبرمجين على القراءة بلغتهم الأم والتفكير أيضًا بها.
لذلك اتحنا الفرصة أمام الجميع للمساهمة ومساعدتنا في نشر واثراء المحتوى التقني باللغة العربية, من خلال كتابة المقالات التقنية في مختلف مجالات هندسة البرمجيات.
وجب التنويه أنه لن يتم نشر كافة الأعمال التي تصل إلينا، وإنما سيتم الانتقاء منها ما يحقق هدفنا بإثراء المحتوى التقني العربي، ولذلك قد تُطلب بعض التعديلات من الكاتب قبل النشر.
لمعرفة المزيد بخصوص :
💬 المعايير العامة لكتابة ونشر المقالات
⚡️ كيفية الإرسال
🔥 التزامات اقرأ-تِك تجاه الكتاب
يمكنكم قراءة كافة التفاصيل من هنا 👇