اپلیکیشن چگونه کار می کند
اپلیکیشن برنامه ای است که روی خود دستگاه نصب می شود، رابط و منطقش داخل همان دستگاه اجرا می شود، و برای هر داده تازه ای با یک سرور حرف می زند. بیشتر آن چیزی که کاربر «کند بودن اپلیکیشن» می نامد در همین گفتگو با سرور می گذرد، نه در کدی که روی گوشی است.
- درس ۱ از ۸
- مقدماتی
- رایگان، بدون ثبت نام
پنج لایه یک اپلیکیشن، و مرزی که همه تصمیم ها روی آن گرفته می شود
- رابط کاربریتنها لایه ای که کاربر می بیند، و تنها لایه ای که وقتی خراب باشد کسی به شما می گوید.
- منطق برنامهتصمیم می گیرد هر لمس چه کاری بکند و داده لازم داخل دستگاه هست یا باید خواسته شود.
- قرارداد APIمرز اصلی. بالایش مال یک دستگاه است و پایینش بین همه کاربرها مشترک.
- برنامه پشتیجای منطقی که نباید روی گوشی کاربر باشد: قیمت، موجودی، دسترسی، پرداخت.
- پایگاه دادهچیزها را نگه می دارد. کاربر هیچ وقت مستقیم با آن حرف نمی زند و نباید بزند.
این لایه بندی یک ترتیب یادگیری است و نه یک استاندارد؛ اسم ها در تیم های مختلف فرق می کنند. دو لایه بالا روی گوشی اند و سه لایه پایین روی سرور.
آخرین بررسی: فکت ها و نام ابزارهای این درس در همین تاریخ با منابعشان بازبینی شده اند.
وقتی روی یک دکمه می زنید چه اتفاقی می افتد؟
یک ضربه انگشت چهار کار پشت سر هم راه می اندازد. اول کد رابط می فهمد کجای صفحه لمس شده و این لمس مال کدام دکمه بوده. بعد منطق برنامه تصمیم می گیرد برای این دکمه چه داده ای لازم است و آیا همان لحظه داخل دستگاه هست یا نه. اگر نبود، یک درخواست HTTPS به سرور می رود. آخر هم جوابی که برمی گردد به شکل صفحه در می آید.
سه کار از این چهار تا در چند هزارم ثانیه تمام می شوند. سومی نه. رفت و برگشت با سرور تقریبا همیشه از بقیه بلندتر است و اگر یک بار خودتان اندازه اش بگیرید دیگر فراموشش نمی کنید. این دستور یک درخواست به API خود همین سایت می زند و مرحله هایش را جدا جدا چاپ می کند:
curl -s -o /dev/null -w 'dns=%{time_namelookup} tls=%{time_appconnect} first_byte=%{time_starttransfer} bytes=%{size_download}\n' "https://rgb.ir/wp-json/wp/v2/posts?per_page=1&_fields=id,title,link,date"سه بار پشت سر هم اجرایش کردیم. پیدا کردن نشانی دامنه بین ۱.۴ تا ۴.۲ هزارم ثانیه طول کشید، دست دادن امن TLS تا ۳۱ تا ۴۹ هزارم ثانیه تمام شد، و اولین بایت پاسخ بین ۱۶۷ تا ۱۹۴ هزارم ثانیه رسید. کل چیزی که برگشت ۳۵۳ بایت بود. چند ساعت بعد همان دستور را دوباره گرفتیم و این بار اولین بایت بین ۱۸۰ تا ۲۵۱ هزارم ثانیه آمد، در حالی که حجم پاسخ دقیقا همان ۳۵۳ بایت ماند. عددی که باید به خاطر سپرد همان ۳۵۳ است و نه زمان ها.
به نسبت ها نگاه کنید. برقرار کردن ارتباط امن حدود یک چهارم زمان را برد و بقیه اش مدتی است که سرور طول کشید تا جواب را بسازد. در تمام این مدت اپلیکیشن هیچ کاری نکرده و فقط منتظر مانده. اینجا همان جایی است که کاربر می گوید برنامه کند است و برنامه نویس دنبال بهینه سازی رابط می گردد.

مسیر یک ضربه انگشت، و جایی که وقت آنجا می رود
-
۱
لمس صفحه
رابط می فهمد کجا لمس شده و این لمس مال کدام دکمه بوده.
-
۲
تصمیم منطق برنامه
داده لازم داخل دستگاه هست؟ اگر هست، کار همین جا تمام می شود.
-
۳
درخواست HTTPS
اینجا وقت واقعا خرج می شود. دست دادن امن هم بخشی از همین قدم است.
-
۴
سرور جواب را می سازد
پاسخ های API کش نمی شوند، پس هر ضربه یک اجرای کامل روی سرور است.
-
۵
صفحه دوباره رسم می شود
هر چه پاسخ سبک تر باشد این قدم کوتاه تر است، حتی روی گوشی ارزان.
قدم سوم روی همین سایت اولین بایتش بین ۱۶۷ تا ۱۹۴ هزارم ثانیه رسید. سه قدم دیگر روی هم به آن نمی رسند، ولی روی گوشی ضعیف قدم آخر هم دیده می شود.
اپلیکیشن از چه لایه هایی ساخته شده است؟
پنج لایه، و مرزی که بین دوتاشان می افتد مهم تر از خود لایه هاست. رابط کاربری چیزی است که دیده و لمس می شود: دکمه، فهرست، فرم. منطق برنامه تصمیم می گیرد که با هر لمس چه کاری انجام شود و چه چیزی نمایش داده شود. این دو روی خود گوشی اجرا می شوند.
لایه سوم API است، یعنی همان قراردادی که می گوید اپلیکیشن با چه نشانی و چه شکلی از سرور داده می خواهد و سرور با چه شکلی جواب می دهد. آن طرف قرارداد، برنامه پشتی روی سرور نشسته و منطقی را اجرا می کند که نباید روی گوشی کاربر باشد: قیمت، موجودی، دسترسی، پرداخت. زیر آن هم پایگاه داده است که چیزها را نگه می دارد.
مرز واقعی بین لایه دوم و سوم است. هر چیزی که بالای این مرز باشد فقط مال همین یک دستگاه است و هر چیزی که پایینش باشد بین همه کاربرها مشترک است. تمام سوال های سختی که سر یک پروژه اپلیکیشن پیش می آید در نهایت همین یک سوال اند: این کار باید بالای مرز انجام شود یا پایینش. اگر جواب را اشتباه بدهید، مشتری روی گوشی خودش قیمت را عوض می کند.
لایه بندی بالا یک ترتیب یادگیری است و نه یک استاندارد. اسم ها هم در تیم های مختلف فرق می کنند. چیزی که فرق نمی کند، همان مرز است.
نیتیو، وب و هیبرید سه چیز متفاوت اند
وقتی مشتری می گوید اپلیکیشن می خواهم، تقریبا همیشه منظورش یک آیکن روی صفحه گوشی است. سه فناوری کاملا متفاوت همان آیکن را به شما می دهند و تفاوتشان تازه وقتی معلوم می شود که اینترنت قطع شود یا بخواهید نسخه جدید را برسانید.
نیتیو یعنی برنامه ای که برای همان سیستم عامل کامپایل و به شکل یک بسته نصب می شود. سند خود اندروید این را دقیق می گوید: برنامه های اندروید با کاتلین و جاوا و سی پلاس پلاس نوشته می شوند و ابزارهای SDK کد و منابع را در یک APK یا یک App Bundle بسته بندی می کنند؛ APK همان فایلی است که دستگاه برای نصب استفاده می کند و App Bundle اصلا روی دستگاه نصب نمی شود، چون قالب انتشار است نه قالب نصب. همین یک جمله بعدا سر انتشار به کارتان می آید.
وب یعنی همان چیزی که در مرورگر باز می شود. چیزی نصب نمی شود، به روزرسانی همان لحظه به همه می رسد، و به سخت افزار گوشی دسترسی محدودی دارد. PWA نسخه ای از همین است که به تعریف MDN با فناوری های وب ساخته می شود ولی تجربه ای شبیه برنامه نصب شده می دهد: مثل سایت از یک کد پایه روی چند سکو اجرا می شود و مثل برنامه نصب شده روی دستگاه نصب می شود، آفلاین و در پس زمینه کار می کند و با خود دستگاه یکپارچه می شود.
هیبرید یعنی یک برنامه وب که داخل یک پوسته نیتیو بسته بندی شده. از بیرون نیتیو به نظر می رسد و از داخل وب است. برای فرم ها و محتوا خوب جواب می دهد و هر جا انیمیشن سنگین یا کار مداوم با دوربین و سنسور باشد سقفش را نشان می دهد.
موضع ما ساده است: انتخاب بین این سه، تصمیمی درباره فناوری نیست، تصمیمی درباره این است که کاربر شما در چه وضعیتی از برنامه استفاده می کند. کسی که در انبار بدون آنتن کار می کند و کسی که در دفتر پشت وای فای نشسته دو جواب متفاوت می گیرند.
چهار جایی که نیتیو و وب واقعا از هم جدا می شوند
-
نصب یا باز کردن
نیتیو یک بسته است که نصب می شود و آیکن می سازد. وب فقط با یک نشانی باز می شود و همین کمترین اصطکاک ورود را دارد.
-
بدون اینترنت چه می شود
نیتیو می تواند نسخه ای از داده را نگه دارد و چیزی نشان بدهد. وب ساده صفحه خطا می دهد، مگر آنکه PWA باشد و برای همین حالت ساخته شده باشد.
-
نسخه جدید از کجا می رسد
وب همان لحظه به همه می رسد. نیتیو باید از استور رد شود و همیشه کاربرهایی می مانند که نسخه قدیمی را نگه می دارند.
-
دسترسی به سخت افزار
نیتیو به دوربین و سنسور و کار در پس زمینه کامل دسترسی دارد. وب بخشی از اینها را دارد و مرزش را مرورگر تعیین می کند نه شما.
هیبرید عمدا در این چهار خانه جایی ندارد، چون در هر کدام یک طرف را انتخاب می کند: نصب می شود مثل نیتیو و داخلش وب است.
چه چیزی داخل گوشی می ماند و چه چیزی روی سرور؟
دو قاعده کار را تمام می کند. هر چیزی که دو نفر باید یک شکل ببینندش روی سرور می ماند: قیمت، موجودی، سفارش، پیام. هر چیزی که کاربر باید بدون اینترنت هم ببیندش باید یک نسخه روی دستگاه داشته باشد: تنظیمات، پیش نویس، آخرین فهرستی که دیده، و همان نشانه ورودی که نمی گذارد هر بار رمز بزند.
آن نشانه ورود، که به آن توکن می گویند، جای حساسی است. تا وقتی روی دستگاه است کاربر وارد مانده و همین راحتی است. اگر گوشی گم شود همان توکن هم گم شده، پس باید بتوان از سمت سرور باطلش کرد. این کاری است که فقط برنامه پشتی می تواند انجام دهد و هیچ کدی روی گوشی جایگزینش نمی شود.
درباره کار آفلاین یک حرف نامحبوب هم هست. بیشتر پروژه هایی که «حالت آفلاین» می خواهند در واقع می خواهند وقتی کاربر داخل آسانسور آنتن ندارد صفحه خطا نبیند. آن چیزی که لازم دارند یک کش خواندنی است و ارزان است. آفلاین واقعی یعنی کاربر بتواند بدون اینترنت هم چیزی را تغییر بدهد، و آن وقت باید تصمیم بگیرید اگر دو نفر همزمان یک چیز را عوض کردند کدام برنده است. این تصمیم گران است و اگر پروژه به آن نیاز ندارد نباید خریدش.
چرا اپلیکیشن شما دقیقا به اندازه API اش سریع است
یک صفحه فهرست معمولی ده ردیف نشان می دهد. از API خود همین سایت ده مقاله خواستیم، یک بار به شکل پیش فرض و یک بار با گفتن اینکه فقط چهار فیلد لازم داریم:
curl -s -o /dev/null -w '%{size_download}\n' "https://rgb.ir/wp-json/wp/v2/posts?per_page=10"
curl -s -o /dev/null -w '%{size_download}\n' "https://rgb.ir/wp-json/wp/v2/posts?per_page=10&_fields=id,title,link,date"جواب اولی ۴۰۳٬۱۵۲ بایت بود و جواب دومی ۳٬۷۸۰ بایت. برای یک مقاله همین نسبت ۳۷٬۳۴۱ بایت در برابر ۳۵۳ بایت است. پنج بار پشت سر هم گرفتیم و عددهای حجم دقیقا همان ماندند؛ زمان ها اما نه، و یکی از همان پنج بار روی این سرور زنده ۵.۳ ثانیه طول کشید. این تفاوت خودش درس دارد: حجم قابل پیش بینی است و زمان نیست.
هیچ چیز در سمت اپلیکیشن عوض نشده بود. صفحه فهرست صد برابر سبک تر شد چون درخواست گفت چه چیزی لازم دارد. بقیه آن ۴۰۳ کیلوبایت متن کامل رندر شده مقاله ها بود، که یک صفحه فهرست هرگز نشانش نمی دهد.
یک نکته دیگر هم در همین اندازه گیری بود. پاسخ های API هدر x-flying-press-cache: MISS و cf-cache-status: DYNAMIC داشتند، یعنی برخلاف صفحه های HTML این سایت، هیچ کدام از این جواب ها کش نمی شوند و هر ضربه انگشت یک اجرای کامل PHP است. سروری که برای بازدیدکننده وب راحت جواب می دهد، زیر بار اپلیکیشن کار متفاوتی انجام می دهد.
پس ترتیب درست کار این است: قبل از انتخاب فریمورک، به این نگاه کنید که API شما چه چیزی برمی گرداند. درس بعدی همین مسیر سراغ همان انتخاب می رود، یعنی نیتیو یا کراس پلتفرم، و از فهرست درس ها در صفحه مسیر طراحی اپلیکیشن در دسترس است. اگر می خواهید ببینید همین قرارداد از سمت وب چه شکلی است، درس ای پی آی چیست همان را از پایه باز می کند.
همان صفحه، قبل و بعد از اینکه درخواست بگوید چه می خواهد
- یک مقاله ۳۷٬۳۴۱ بایت۳۵۳ بایت
-
فهرست ده مقاله
۴۰۳٬۱۵۲ بایت۳٬۷۸۰ بایت
صفحه فهرست همان جایی است که فرق را می سازد، چون ده برابر داده می خواهد.
این عددها حجم اند و نه زمان. حجم در پنج بار اندازه گیری دقیقا ثابت ماند، ولی زمان یک بار به ۵.۳ ثانیه رسید؛ روی اینترنت همراه همین حجم است که خودش را نشان می دهد.
مسیر سریع با هوش مصنوعی
سریع ترین کاری که امروز می شود با مدل انجام داد، نوشتن کد نیست. این است که پیش از یک خط کد، قرارداد داده اپلیکیشن را بیرون بکشید: هر صفحه چه چیزی نشان می دهد، آن چیز از کدام نشانی می آید و دقیقا کدام فیلدها لازم اند. همان کاری که در بخش آخر این درس صفحه فهرست را صد برابر سبک کرد.
- صفحه های اپلیکیشن را با اسم بنویسید، همان طور که به یک آدم توضیح می دهید: ورود، فهرست سفارش ها، جزئیات سفارش، پروفایل. بدون فناوری، بدون فریمورک.
- برای هر صفحه فقط چیزی را بنویسید که کاربر روی آن صفحه واقعا می بیند. اگر در صفحه فهرست فقط عنوان و تاریخ دیده می شود، همان دو تا را بنویسید و نه بیشتر.
- این فهرست را با نسخه پایین به یک مدل قوی بدهید تا قرارداد API را بسازد. مدل کلاس قضاوت را انتخاب کنید، نه سریع ترین و ارزان ترین را، چون کار اینجا تصمیم گرفتن است و نه ترجمه کردن.
- قدم آخر همان است که بقیه انجام نمی دهند: از مدل بخواهید هر فیلدی را که هیچ صفحه ای مصرفش نمی کند حذف کند و بگوید کدام فیلد را حدس زده است. همین یک خط، فهرست را از چیزی که خوب به نظر می رسد به چیزی که سبک است تبدیل می کند.
نسخه آماده کپی
نقش: معمار API برای یک اپلیکیشن موبایل.
صفحه های اپلیکیشن و چیزی که هر کدام نشان می دهند:
{صفحه ۱}: {فیلدهایی که کاربر روی آن می بیند}
{صفحه ۲}: {فیلدهایی که کاربر روی آن می بیند}
{صفحه ۳}: {فیلدهایی که کاربر روی آن می بیند}
کاری که باید بکنی، به همین ترتیب:
۱. برای هر صفحه یک درخواست بنویس: متد، نشانی، پارامترها، و نمونه پاسخ JSON.
۲. در نمونه پاسخ فقط فیلدهایی را بگذار که همان صفحه نشانشان می دهد. هر فیلد اضافه را حذف کن.
۳. جدولی بده از فیلدهایی که حذف کردی و صفحه ای که اگر لازم شد باید آن را برگرداند.
۴. جدا بنویس کدام نام یا ساختار را حدس زده ای و از کجا باید تاییدش کنم.
۵. اگر داده ای بین دو صفحه مشترک است، بگو کدام صفحه باید آن را کش کند و چه مدت.
هیچ عددی درباره سرعت یا حجم ننویس. من خودم اندازه می گیرم.
قبل از اعتماد به خروجی: خروجی این نسخه یک پیشنهاد است و نه سند. مدل نام فیلدها و حتی نشانی ها را می سازد، پس هر خطی از آن باید با همان چیزی که برنامه پشتی واقعا برمی گرداند مقایسه شود؛ یک بار curl زدن به نشانی واقعی این کار را تمام می کند. و اگر پروژه هنوز برنامه پشتی ندارد، این قرارداد ورودی کار آن است و نه جایگزینش.
هوش مصنوعی در این کار
در این موضوع مدل ها دو کار را واقعا خوب انجام می دهند و یک کار را بد. خوب: خواندن سند طولانی یک سکو و بیرون کشیدن قرارداد داده از توضیح یک صفحه. بد: هر جمله ای که به عدد یا به سیاست فروشگاه ها ربط دارد. موضع ما این است که مدل را در سمت طراحی قرارداد بگذارید و از سمت ادعا کردن بیرون نگه دارید.
ابزارهایی که واقعا کمک می کنند
- Claude برای همان کاری که نسخه بالا می خواهد مناسب است: تبدیل توضیح صفحه ها به قرارداد داده، و مهم تر، حذف کردن چیزی که هیچ صفحه ای لازم ندارد. ایران در هیچ کدام از دو فهرست کشورهای پشتیبانی شده انتروپیک نیست؛ این را از صفحه خودشان خوانده ایم و نه از تست شبکه.
- Gemini برای خواندن سندهای بلند سکوها خوب جواب می دهد، و همین درس هم چند جمله اش را از سند رسمی اندروید گرفته است. صفحه خود گوگل می گوید اپ وب جمنای در بیش از دویست و سی کشور و منطقه کار می کند و ایران در آن فهرست نیست.
- NotebookLM وقتی سوال این است که سند یک SDK دقیقا چه گفته، این ابزار درست تر از یک گفتگوی معمولی است، چون فقط از منبعی که خودتان داده اید جواب می دهد. راهنمای خود گوگل می گوید در همان مناطقی کار می کند که اپ جمنای کار می کند و ایران در آن فهرست نیست.
- GitHub Copilot داخل ویرایشگر کار می کند و برای خواننده ایرانی نکته دسترسی اش از همه غیرمنتظره تر است: صفحه کنترل تجاری خود گیتهاب می گوید مجوز خزانه داری آمریکا خدمات ابری اش را برای توسعه دهندگان ساکن ایران، رایگان و پولی، پوشش می دهد. ما همین را نقل می کنیم و درباره پرداخت ادعایی نداریم.
کجا نتیجه معکوس می دهد
خطر اول این کار مخصوص اپلیکیشن است و به مدل ربط مستقیم دارد. اپلیکیشن به گوشی کاربر می رود، پس هر چیزی که داخل بسته باشد در دست کسی است که گوشی را دارد. مدل ها معمولا نمونه کدی می نویسند که کلید API را همان وسط کد گذاشته اند، چون فقط این طور نمونه اجرا می شود؛ و بعد همان نمونه کپی می شود و به استور می رود. فهرست OWASP Mobile Top 10 در نسخه ۲۰۲۴ خانه اول را به «استفاده نادرست از اطلاعات هویتی» و خانه هفتم را به «محافظت ناکافی از فایل نهایی» داده است. قاعده ای که از همین درس درمی آید ساده است: کلیدی که باید مخفی بماند بالای مرز جای ندارد و باید در برنامه پشتی بنشیند.
خطر دوم عادی تر است. مدلی که درباره SDK های موبایل یا قوانین فروشگاه ها می نویسد، با همان لحن مطمئن نام متد و شرط انتشار می سازد. هر جمله ای از این جنس باید با سند خود سازنده مقایسه شود. راه پرداخت از ایران برای این ابزارها در راهنمای خرید است.
منبع ها: OWASP Mobile Top 10 (2024) Anthropic: supported countries GitHub and Trade Controls Google: where the Gemini web app is available
حد این توصیه
این درس شکل رایج را توضیح می دهد: اپلیکیشنی که صفحه دارد و با یک API روی HTTP حرف می زند. بازی ها اینجا نیستند، و همین طور اپلیکیشن هایی که ارزششان روی خود دستگاه ساخته می شود، مثل پردازش تصویر دوربین یا مدلی که روی گوشی اجرا می شود؛ در آنها مرزی که این درس رویش ایستاده اصلا جای دیگری است. یک نکته درباره خود ما هم لازم است: عمق تجربه دست اول ما سمت سرور این مرز است، یعنی هاست و API، و همه عددهای این صفحه هم عددهای سرور اند و نه عددهای یک اپلیکیشن منتشرشده.
از تجربه خود ما
روی همین سرور یک افزونه کوچک اجباری داریم به اسم rgb-rest-raw.php که فقط برای یک چیز نوشته شده. افزونه امنیتی Really Simple SSL یک بافر خروجی باز می کند و در تمام بدنه پاسخ، هر «https://rgb.ir» را به «https://rgb.ir» تبدیل می کند. برای HTML این کار درست است. روی یک پاسخ JSON یک خرابکاری بی صداست: ابزار بررسی ریدایرکت ما وظیفه اش این است که نشان بدهد نشانی http به https ریدایرکت می شود، و آن بازنویسی باعث می شد اولین حلقه زنجیر «https به https» خوانده شود، یعنی دقیقا همان چیزی که ابزار برای پیدا کردنش ساخته شده بود نامرئی می شد. مقدار ذخیره شده در پایگاه داده درست بود و فقط بدنه خروجی دستکاری می شد. هیچ مرورگری این را نمی فهمید؛ برنامه ای که نشانی را بایت به بایت می خواند بله. نکته دوم از جنس دیگری است: API عمومی خود ما پشت کپچا است، و درخواست ساده به /wp-json/rgb/v1/domain امروز کد ۴۲۲ و پیامی برگرداند که می گفت منتظر کامل شدن تایید امنیتی بمانید. روی فرم یک سایت این درست است، و همین دلیل این است که یک اپلیکیشن نمی تواند API سایت را همان طور که هست مصرف کند و به مسیر احراز هویت خودش نیاز دارد.
سوال هایی که واقعا پرسیده می شوند
برای ساختن اپلیکیشن حتما به سرور نیاز دارم؟
نه، اگر همه چیز روی خود دستگاه بماند: ماشین حساب، یادداشت آفلاین، ابزار اندازه گیری. لحظه ای که دو دستگاه باید یک چیز را یک شکل ببینند، یا کاربر باید وارد حسابی شود، سرور لازم می شود و دیگر اختیاری نیست. مرزش را همان قاعده بخش چهارم مشخص می کند.
تفاوت اپلیکیشن با سایت موبایلی در چیست؟
چهار چیز: اپلیکیشن نصب می شود و آیکن می سازد، می تواند بدون اینترنت هم چیزی نشان بدهد، به دوربین و سنسور و کار در پس زمینه دسترسی کامل دارد، و نسخه جدیدش باید از یک فروشگاه رد شود. سایت هیچ کدام از اینها را ندارد و در عوض هیچ اصطکاکی برای ورود ندارد و به روزرسانی اش همان لحظه به همه می رسد.
چرا اپلیکیشن من روی وای فای سریع است و روی اینترنت همراه کند؟
چون تقریبا همیشه مشکل حجم است و نه کد. وای فای حجم زیاد را پنهان می کند و اینترنت همراه نمی کند. اندازه گیری بخش آخر همین را نشان می دهد: یک صفحه فهرست ده ردیفی از این سایت به شکل پیش فرض ۴۰۳٬۱۵۲ بایت بود و با گفتن چهار فیلد لازم ۳٬۷۸۰ بایت شد، بدون هیچ تغییری در سمت اپلیکیشن.