VOL68: Online Payments 101 for Developers
أهلًا وسهلا بكم في العدد الثامن والستين من النشرة الأسبوعية لاقرأ-تِك 🚀
لا تنسوا أهلنا من صالح الدعاء,اللهم إنّا استودعناك اياهم، اللهم كُن عوناً لهم، اللهم انصرهم واحفظهم. 🇵🇸
أهلًا وسهلا بكم في العدد الثامن والستين من النشرة الأسبوعية لاقرأ-تِك 🚀
سواء كنت مهندس برمجيات مبتدئ أو محترف، فنشرتنا هدفها انها تثري المحتوى التقني العربي سعيا للتطوير من جودة المحتوى باللغة العربية، من خلال تقديم أحدث المستجدات والتطورات في عالم البرمجيات، بالإضافة إلى أفضل الممارسات والنصائح القيمة، ونشر أحدث المقالات وترشيحات الكتب ومحتوى ورقة وقلم اللي بينزلوا بشكل مستمر في موقع اقرأ-تِك.
في الإصدار ده الفهرس هيكون كالآتي:
Online Payments 101 for Developers
Dropbox's Chrono: Scalable, Consistent and Metadata Caching Solution
Concurrency Building Blocks (Process)
How to Avoid Double Payment
الإصدار الأول من مدونات فطين في تصميم النظم
Online Payments 101 for Developers
واحدة من أكثر المجالات صعودًا في السنين الأخيرة في عالم التقنية هي ال Fintech بل وأصبحت لا غني عنها وجزء من حياتنا اليومية, وأي Business حاليًا لازم يتعامل معها بطريقة أو بأخرى, فورقة وقلم مًبرمجنا الفاضل وتعالى نفهم أساس النظام دا من وجهة نظر العميل ووجهة النظر التقنية لأن سواء احتجت تطبق Payment Solution أو بس ت Integrate مع حل جاهز, فهمك للنظام دا هيسهل عليك كتير..
القصة القصيرة بالنسبة للعميل:
العميل بيدفع للتاجر باستخدام بطاقة البنك الخاصة بيه سواء في المحل مع جهاز الـ Terminal أو ما يعرف ب Point of sale POS) أو بيدخل بيانات الكارت في ال Checkout علي الموقع, وقتها احنا بنعمل Authorisation Request للبنك المٌصدر للكارت عشان نتأكد من وجود رصيد كافي للمعاملة ال Authorisation request دا بنعمل فيه أكثر من عملية أهمهم:
التأكد من بيانات الكارت و من إن المعاملة مش Fraud
التأكد من وجود رصيد كافي
لو في رصيد كافي فالبنك بيقوم بخصم قيمة المعاملة من حساب المشتري وإرسالها لحساب التاجر
خلص ال Authorisation request بنجاح عميلنا كدا دفع بنجاح وخد مشترياته ومشي.
خد بالك عزيزي المبرمج العميل هنا مهتم بـ حاجتين ملهمش ثالث:
Reliability of Service أمان المعاملة (ادفع ويتخصم مني فقط القيمة المٌتفق عليها من غير مشاكل تقنية وتفضل بياناتي وبيانات حسابي في أمان)
Ease of Service سلاسة ووقت المعاملة (عملية الدفع تتم بأسهل وأسرع طريقة)
فمهما قصة ال Payments تطول معاك في تفاصيلها أولويتك الأولى والأخيرة إنك بتوفر له الحاجتين دول.
القصة الطويلة بالنسبة للمبرمج
قبل ما نعرض الخطوات هنناقش نقطتين مهمين:
المصطلحات المٌستخدمة في أنظمة الدفع
خلونا نستعرض بعض المصطلحات لتسهيلها, الجميل إن المصطلحات دي 90٪ من الوقت ثابتة حول العالم ففي مصر مثل السعودية مثل أمريكا هو نظام واحد بيختلف مٌقدمين الخدمات وأسمائهم.
Issuer (البنك المُصدِر): هو البنك أو الجهة التي أصدرت بطاقة العميل ويتحقق من صلاحيتها ويوافق أو يرفض العملية.
Acquirer (البنك المُكتسِب): هو البنك أو المؤسسة المالية التي تمثل التاجر وتستقبل المدفوعات نيابة عنه من شبكات البطاقات.
Card Network (شبكة البطاقات): هي الجهة الوسيطة التي تربط بين البنك المُكتسِب (Acquirer) والبنك المُصدِر (Issuer)، وتُعالج الطلبات وتُطبق قواعد المدفوعات بين الطرفين.
Payment Gateway (بوابة الدفع): هي الواجهة الإلكترونية التي تجمع بيانات الدفع من العميل وتربطها آمنًا بمعالج الدفع لتنفيذ المعاملة.
Payment Processor (معالج الدفع): هو النظام أو الشركة التي تنفذ عملية الدفع تقنيًا من خلال التحقق من البيانات والتواصل مع الشبكات والبنوك.
عملية الدفع ليست خطوة واحدة
لما بندفع Cash, عميلة الدفع أغلب الوقا هي نفسها عملية الاستلام. بينما في عمليات الدفع الالكتروني عملية دفع العميل لا تعني استلام التاجر للفلوس, طيب إزاي🤷♀️
عملية تحقق Authorisation : وفيها البنك المٌصدر بيقوم بحجز الفلوس في حساب العميل بل وبيوضح للعميل إنه اتخصم منه بشكل فوري(حسابك كرقم بيقل) لكن الفلوس في الواقع متحركتش من البنك.
عملية تسوية Settlement : وفيها يتم نقل الفلوس بالفعل لحساب التاجر في البنك. عملية التسوية بتحصل عادة خلال يوم أو اثنين ولكن في حلول حاليًا بتقدم تسوية للتاجر في نفس اليوم.
لو تابعنا في الرسم التوضيحي هنلاحظ إن ال Payment gateway بيبدأ بجمع المعلومات من كارت العميل سواء في ال Checkout أو من خلال ال Terminal وتشفيرها وإرسالها ك Authorisation request لل Payment Processor وكذلك يقوم باستقبال ال Response وعرضه للعميل.
Dropbox's Chrono: Scalable, Consistent and Metadata Caching Solution
عملية تخزين الـ Metadata واسترجعاها كان من فترة طويلة محور أساسي ومهم لفرق الـ Metadata في Dropbox ومؤخرًا فريق المهندسين عمل تحسينات ملحوظة في البنية التحتية.
التحسينات دي كان من ضمنها إنهم يبنوا الـ Scalable Key-Value Storage الخاص بيهم تدريجيًا ، وبالشكل ده قدروا إنهم يتجنبوا احتياجهم الأساسي لمضاعفة الـ Hardware.
ولكن مع تطورهم ومع وجود Scale كبير ، ده برضو كان قصاده تحديات مستمرة مقدروش إنهم يتجنبوها بسهولة.
Context
الـ Internal Clients اللي بيستعملوا Dropbox Metadata فضلوا لمدة طويلة بيعتمدوا على فرضية إن البيانات اللي هيتم استرجاعها لازم توفر ضمان الـ read-after-write فعلى سبيل المثال :
لما نيجي نعمل عملية Write لـ Key معين وبعدين علطول نعمل عمليات قراءة متتابعة للـ Key ده ، المفترض اني اقدر اشوف اللي عملتله Write بمعنى أدق لازم دايمًا أشوف الـ Recent Value اللي حصلت من عملية الـ Write ولا مجال لوجود Stale Values.
ولو كان فريق الـ Metadata كبر دماغه وقال إن الضمان ده مش مهم ، خصوصًا في أغلب التطبيقات الحالية اللي بتعتمد على الـ Eventual Consistency ، كان هتبقى مشكلة كبيرة من ناحية الـ Auditing وإنهم يغيروا كل الـ Client Code الخاص بالفرق التانية ، وده كان هيضطرهم لمجهود كبير جدًا ومضاعفات من ناحية الـ Client Side وكان هيقلل من سرعة فرق التطوير والـ Product Teams كذلك.
فعشان يحلوا مشكلة الـ High-Volume Read QPS واللي بتعرف برضو بالـ "Queries Per Second" المهولة اللي بتحصل عندهم وفي نفس الوقت يظلوا محافظين على توقعات الـ Client بتوعهم من ناحية الـ Read Consistency وعدم وجود Stale Reads ، فالحلول التقليدية من الـ Caching ما كنتش هتنفع.
فكان لا بد من وجود Scalable Consistent Caching Solution عشان يحل المشكلة دي.
Chrono
ومن هنا جه Chrono وهو عبارة عن Scalable و Consistent Caching System مبني فوق Key-Value Storage System بيستعملوه وهو Panda. وقادر إنه يعيش ويـ Survive مع الكميات المهولة من عمليات القراءة والـ High-Volume Read QPS.
Consistent Caching Challenges
استخدام الـ Caching بشكله البسيط والتقليدي في الـ Database Layer مش بيدينا ضمانات القراءة بعد الكتابة "Read-After-Write" اللي عاوزين نحققها. فمثلًا، لو كتبنا في قاعدة البيانات وبعدها كتبنا في الـ Caching، ممكن يحصل إن الـ Server يتعطل بين العمليتين، وده يخلي البيانات اللي في الـ Caching قديمة.
وحتى الطرق البسيطة لتحديث الـ Caching مش بتكون مضمونة. فخلونا نتخيل السيناريو ده: لو عندنا القيمة القديمة للـ Key = K في الـ Storage هي v1، وفي الـ Cache هي كمان v1:
الـ Writer لو حاول يكتب K=v2 فاحنا في البداية محتاجين نمسح القيمة القديمة من الـ Cache للـ Key = K.
الـ Reader 1 وهو بيقرأ من الـ Cache مش هيلاقي حاجة وده لإننا مسحناها، فهيروح يقرأ من الـ Storage Layer نفسها وهيلاقي إن النتيجة هي v1.
الـ Writer بعد كده بيكمل الكتابة عادي جدًا في الـ Storage ويخزن v2.
الـ Reader 2 وهو بيقرأ من الـ Cache مش هيلاقي حاجة، فهيروح يقرأ من الـ Storage Layer وهيلاقي v2 ووقتها هيخزنها في الـ Cache إن الـ K = v2.
الـ Reader 1 في الأول حصله Cache Miss وبالتالي قرأ من الـ Storage Layer إن الـ K = v1 فهو دلوقتي هيروح يكتب v1 في الـ Cache بعد ما عمل Cache Invalidation.
فهنلاقي إن النتيجة إن الـ Cache دلوقتي بيحتوي على بيانات قديمة بالنسبة للـ Storage Layer. نتيجة إن فيه Concurrent Read حصلت وبينهم حصل Concurrent Cache Miss واثناء ما كل Reader بيحاول يـ Invalidate الـ Cache بالقيمة الجديدة فيه واحد عمل Write على التاني بالقيمة القديمة.
Consistent Caching at Scale
فـ Chrono زي ماوضحنا هو مبني فوق Panda، وPanda عبارة عن الـ Multi-Version Concurrency Control واللي هي الـ (MVCC) للـ Key-Value Storage System الخاص بـ Dropbox.
Panda APIs
طبعًا Panda بيوفر APIs لكتابة وقراءة البيانات باستخدام الـ Timestamps دي و Chrono بيستخدم الـ APIs المتوفرة من خلال Panda لتحقيق الـ Consistent Caching.
الـ (Write API): بيتم استخدامه لكتابة البيانات في Panda، ولو الـ Timestamp اللي اختاره Panda للكتابة أكبر من الـ Timestamp اللي العميل حددّه، عملية الكتابة بتفشل.
الـ (Snapshot Read API): بيسمح للعميل يقرأ البيانات من لحظة معينة في الزمن باستخدام Timestamp محدد.
الـ (GetLatest API): بيرجع أحدث البيانات المتاحة للقراءة مع الـ Timestamp.
وبالشكل ده Chrono يقدر يخزن الـ Timestamp لأحدث محاولة كتابة لكل Key، وده بيساعد إننا نتأكد إن الـ Caching ما فيهوش بيانات قديمة أو إن فيه Stale Data.
How Chrono Works
باختصار Chrono هو خدمة بتقولك الـ Timestamp لأحدث محاولة كتابة لأي بيان في الـ Storage System.
مصدر الصورة : Dropbox Engineering Blog
Concurrency Building Blocks (Process)
الـ Concurrent Programming مبنية على فكرة إن يكون عندي الـ Application متكسر لـ Independent Tasks يعني مهام مستقلة أو Units اقدر اشتعل عليهم بشكل Concurrently.
وطبعًا الـ Abstraction Layer واللي بتسهلنا أغلب الشغل ده ألا وهو الـ OS قادر إنه يدير الـ Tasks دي ويعملهم Handling بشكل كويس من خلال إنه يوفر الـ Resources اللازمة بشكل كفء.
فنقدر نعتبر الـ Concurrent Programming هي مجموعة من الـ Abstractions اللي بتسمح للمطورين إنهم ينظموا التطبيق بتاعهم على شكل مهام صغيرة ومستقلة وينقلوها بعد كده للـ Runtime System واللي في الحالة دي هو الـ OS عشان يعملهم Handling بكفاءة.
وطبعا الـ Runtime System هيكون المسئول عن تنفيذهم وعملية الـ Orchestration اللي هتتم بينهم عشان يختار انهي Task اللي هيتم تنفيذها ويستغل الـ Resources بأفضل شكل ممكن.
وخلاصة الـ Abstractions اللي عمالين نتكلم عليها دي هي إن احنا عندنا بكل بساطة نوعين من الـ Abstractions كمطورين عشان نتعامل مع الـ Concurrent Programming والنوعين دول هم الـ Building Blocks اللي ممكن نعتمد عليهم عامة في تطبيق الـ Concurrency ألا وهم الـ Process والـ Threads.
الـ Process
التعريف اللي أغلبنا سمع عنه للـ Process هي إنها عبارة عن Running Program ، فأي تطبيق أو برنامج شغال ده بنسميه Process واللي أغلبنا يقدر يشوفه من خلال الـ Management Tools على أي OS طبعًا ويشوف الـ Processes اللي موجودة.
فأي برنامج في الأساس هو عبارة عن حاجة ملهاش قيمة ، مرمية على الـ Disk ، بتتكون من مجموعة أوامر مستنية إنها تتنفذ ، والـ OS الله يمسيه بالخير بياخد الأوامر أو الـ Instructions دي وينفذهم على الـ Hardware بتاعنا فيبدأ البرنامج يبقى ليه قيمة فعلية لما يشتغل ويتنفذ.
مثال من الواقع على الـ Process
طبعًا أمثلة ده كتير في الواقع بتاعنا ، وعشان نبسط الكلام بمثال: فالعربية هي عبارة عن مجموعة من الأجزاء الميكانيكية اللي طبعا ملهاش أي قيمة وهي مبتتحركش ، ولكن بمجرد ما بندور العربية ونشغلها والمحرك بتاعها يبدأ يشتغل والعربية تتحرك بتتحول لحاجة قيمة ومفيدة بتساعدك في حياتك انك تتنقل بيها.
فنقدر نعتبر الـ Source Code بتاعنا كـ Developers هو العربية دي بس بدل مهو عبارة عن Mechanical Parts أو أجزاء ميكانيكية ، فهو عبارة عن مجموعة من الأوامر اللي مستنية يبقى ليها قيمة فعلية ، وبيشتغل على Abstractions وده اللي بتيحه لغات البرمجة.
فأنت فعليا كـ Developer معندكش Memory تخزن فيها بيانات أو ملفات تقرأ وتكتب منها وعليها أو بعض الأجهزة اللي بتبعتلها Signals فعلية عشان تقوم بدور معين ، ولكن احنا كـ Developers بنستعمل Models مبنية على Abstractions بفضل لغات البرمجة اللي شغالين بيها والـ Runtime Environment اللي بتنفذ الكلام ده على الـ Hardware الفعلي بتاعنا.
فالـ Abstraction اللي بيوفره الـ OS للـ Running Program بتاعنا هو الـ Process وطبعا مفيش حاجة اسمها Process على Scope الـ Machine Instructions فهو مجرد Abstraction ليه دور مهم في عزل الـ Tasks أو المهام اللي مفروض تتنفذ ويكون ليها Hardware Resources عشان تتنفذ.
How to Avoid Double Payment
أحد أكبر المشاكل اللي ممكن نواجهها في تصميم الأنظمة الخاصة بالدفع , والمعاملات المالية هي أنك تدفع العميل أكتر من مرة, وعشان كده واحنا بنصمم Payment System محتاجين ناخد في الاعتبار ان عملية الدفع لازم نضمن انها هتتم مرة واحدة فقط لا غير.
وطبعًا عشان نحقق الضمان ده واللي بنسميه Exactly-Once Delivery بيقابلنا تحديات مش سهلة خصوصًا لو بنتعامل كمان مع Distributed Systems.
المعادلة الرياضية
لو جينا نبص للمشكلة اللي بنواجهها دي رياضيًا فالمفترض عشان نقول أن فيه حاجة تتم مرة واحدة بس فده معناه انها بتطبق الشروط دي:
اتنفذت على الأقل مرة
اتنفذت كحد أقصى مرة
يعني ايه الكلام الغريب ده باه ؟
بكل بساطة عشان نعالج مشكلة الـ Double Payment واننا منخليش الـ Customer يتحاسب مرتين أو أكتر, احنا عاوزين طريقة نضمن بيها , ان عملية الدفع على الأقل حصلت مرة .. وفي نفس الوقت نضمن أنها متحصلش أكتر من مرة عشان ميتحاسبش مرتين أو أكتر.
وعشان نحقق ده هنستعمل:
الـ Retryer عشان نضمن أول شرط ان عملية الدفع على الأقل حصلت مرة.
الـ Idempotency Key عشان نضمن تاني شرط وهو أن عملية الدفع ما تحصلش أكتر من مرة.
خصم 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 بتاعتنا من خلال اقرأ-تِك والنشرة الأسبوعية 👇
رؤيتنا هي إثراء المحتوى التقني العربي وجعل التعلم من خلال القراءة أمتع، وذلك من خلال إثراء المحتوى التقني باللغة العربية وتشجيع المبرمجين على القراءة بلغتهم الأم والتفكير أيضًا بها.
لذلك اتحنا الفرصة أمام الجميع للمساهمة ومساعدتنا في نشر واثراء المحتوى التقني باللغة العربية, من خلال كتابة المقالات التقنية في مختلف مجالات هندسة البرمجيات.
وجب التنويه أنه لن يتم نشر كافة الأعمال التي تصل إلينا، وإنما سيتم الانتقاء منها ما يحقق هدفنا بإثراء المحتوى التقني العربي، ولذلك قد تُطلب بعض التعديلات من الكاتب قبل النشر.
لمعرفة المزيد بخصوص :
💬 المعايير العامة لكتابة ونشر المقالات
⚡️ كيفية الإرسال
🔥 التزامات اقرأ-تِك تجاه الكتاب
يمكنكم قراءة كافة التفاصيل من هنا 👇