اسکلت (برنامه‌نویسی رایانه‌ای)

برنامه‌نویسی اسکلت‌وار (Skeleton programming) یک سبک از برنامه‌نویسی رایانه‌ای است که بر پایه‌ی ساختارهای ساده و سطح‌بالای برنامه و آنچه "کد ساختگی" (Dummy code) نامیده می‌شود، بنا شده است. اسکلت برنامه‌ها شباهت زیادی به شبه‌کد دارند، اما امکان تجزیه (Parsing)، ترجمه (Compilation) و آزمایش (Testing) کد را نیز فراهم می‌کنند.

"این مقاله در حال ترجمه از ویکی انگلیسی است لطفا حذف نشود." 

کد ساختگی در اسکلت برنامه قرار داده می‌شود تا فرآیند پردازش را شبیه‌سازی کرده و از نمایش پیام‌های خطای ترجمه جلوگیری کند. این کد ممکن است شامل اعلان توابع خالی باشد یا توابعی که فقط در یک حالت آزمایشی ساده که پاسخ مورد انتظار آن از پیش مشخص است، نتیجه‌ی درستی بازمی‌گردانند.

برنامه‌نویسی اسکلت‌وار، طراحی به سبک بالا به پایین را تسهیل می‌کند؛ به این معنا که یک سیستم نیمه‌عملیاتی با ساختارهای سطح‌بالای کامل طراحی و پیاده‌سازی می‌شود و سپس به‌تدریج گسترش یافته و نیازهای پروژه را برآورده می‌سازد. اسکلت برنامه‌ها گاهی برای توصیف‌های سطح‌بالای الگوریتم‌ها نیز به‌کار می‌روند. همچنین اسکلت یک برنامه می‌تواند به عنوان الگویی (template) مورد استفاده قرار گیرد که نحو (syntax) و ساختارهای رایج در یک دسته گسترده از مسائل را منعکس می‌کند.

اسکلت برنامه‌ها در الگوی طراحی روش قالبی (template method) در برنامه‌نویسی شی‌گرا مورد استفاده قرار می‌گیرند. در برنامه‌نویسی شی‌گرا، کد ساختگی (Dummy code) معادل روش (متد) انتزاعی، پیکره‌ی اولیه‌ی یک متد (method stub) یا شیء شبیه‌سازی‌شده (mock object) است. در اصطلاحات Java RMI (فراخوانی روش از راه دور در جاوا)، یک stub در سمت کلاینت با یک skeleton در سمت سرور ارتباط برقرار می‌کند.

اسکلت کلاس (Class Skeleton) در مهندسی نرم‌افزار، چارچوبی کلی از یک کلاس است که شامل توصیفی از نقش‌های کلاس و هدف متغیرها و متدها می‌باشد، اما این متدها و متغیرها هنوز پیاده‌سازی نشده‌اند. کلاس در مراحل بعدی از روی این اسکلت پیاده‌سازی می‌شود. این اسکلت می‌تواند در زبان‌هایی که از الگوی چندریختی (polymorphism) پیروی می‌کنند، به‌صورت رابط (interface) یا کلاس انتزاعی (abstract class) نیز شناخته شود.

 پیشینه 
نرم‌افزارهای مدرن اغلب به دلایل مختلف پیچیده هستند. این پیچیدگی می‌تواند به این معنا باشد که توسعه‌ی نرم‌افزار تنها توسط یک برنامه‌نویس ممکن نیست، یا اینکه بخش‌ها و ماژول‌های دیگر باید به صورت جداگانه وارد (import) شوند. برخی برنامه‌ها به‌تنهایی نیز ممکن است بسیار پیچیده باشند؛ مانند برنامه‌هایی که چندین تابع به‌طور هم‌زمان به یک متغیر دسترسی دارند یا حتی پیکسل‌هایی را برای نمایشگر تولید می‌کنند.

کد اسکلت‌وار برای کمک به برنامه‌نویسان در جهت توسعه‌ی کدهایشان با کم‌ترین خطا در زمان ترجمه (کامپایل) استفاده می‌شود.

کد اسکلت‌وار بیشتر در برنامه‌نویسی موازی (parallel programming) یافت می‌شود، اما در موقعیت‌های دیگر مانند مستندسازی در زبان‌های برنامه‌نویسی نیز کاربرد دارد. این روش به ساده‌سازی عملکرد اصلی یک متد که ممکن است گیج‌کننده باشد، کمک می‌کند. همچنین ممکن است برای اجرای موقت یک تابع کوچک در درون یک برنامه‌ی بزرگ، بدون نیاز به عملکرد کامل، استفاده شود.

این روش برنامه‌نویسی از نوشتن یک تابع کامل آسان‌تر است، چرا که توابع اسکلت‌وار لازم نیست تمام عملکردهای اصلی را داشته باشند و می‌توانند در مرحله‌ی توسعه، به‌صورت ثابت (hardcoded) تعریف شوند. این کدها معمولاً شامل کدی با نحو (syntax) درست هستند که متد را معرفی می‌کند، و همچنین توضیحاتی (کامنت) برای بیان عملکرد بخش‌های مختلف برنامه دارند. البته همیشه لازم نیست که به هر متن یا قطعه کدی، عنوان "کد اسکلت‌وار" داده شود.

 ارتباط آن با شبه‌کد 
شبه‌کد (Pseudocode) بیشتر زمانی استفاده می‌شود که ساختار یک نرم‌افزار جدید در حال طراحی است. این روش، توصیفی ساده و به زبان انگلیسی از عملکرد خاصی در یک سیستم بزرگ‌تر است، یا حتی ممکن است نماینده‌ای از کل برنامه باشد. شبه‌کد شباهت‌هایی با برنامه‌نویسی اسکلت‌وار دارد، اما تفاوت اصلی آن‌ها در این است که شبه‌کد روشی غیررسمی برای برنامه‌نویسی محسوب می‌شود.

کد ساختگی (Dummy code) نیز شباهت زیادی به این دو دارد؛ زیرا در آن، کد به‌عنوان جای‌نگهدار استفاده می‌شود یا وجود یک متد در یک کلاس یا رابط (interface) را فقط به‌صورت نمادین نشان می‌دهد.

برنامه‌نویسان به شدت به شبه‌کد وابسته‌اند، به‌طوری‌که این موضوع تأثیر روانی قابل‌سنجشی بر آن‌ها دارد. یک برنامه‌نویس معمولی آن‌قدر با نوشتن کدهای ساده‌شده – چه از طریق شبه‌کد، چه اسکلت کد، یا حتی فقط رسم یک دیاگرام – خو گرفته که این روند روی کیفیت پیاده‌سازی نهایی آن‌ها تأثیر مستقیم دارد. این موضوع در پروژه‌های مختلف، زبان‌های برنامه‌نویسی متنوع و با پارادایم‌های گوناگون بررسی و اثبات شده است.

طراحی به روش شبه‌کد معمولاً روی کاغذ و خودکار انجام می‌شود؛ یعنی در مرحله‌ای دور از پیاده‌سازی واقعی قرار دارد. اما برنامه‌نویسی اسکلت‌وار برخلاف آن، معمولاً در محیط توسعه (IDE) یا ویرایشگرهای متنی نوشته می‌شود، و همین موضوع امکان توسعه آسان‌تر برنامه را پس از مرحله طراحی فراهم می‌سازد. همچنین، برنامه‌های اسکلت‌وار این قابلیت را دارند که توابع ساده‌ای را حتی در همین مرحله اولیه اجرا کنند.

 پیاده‌سازی 
برنامه‌نویسی اسکلت‌وار (Skeleton programming) را می‌توان در طیف گسترده‌ای از کاربردهای مختلف برنامه‌نویسی پیاده‌سازی کرد.

 مستندسازی زبان‌های برنامه‌نویسی 
تقریباً تمامی زبان‌های برنامه‌نویسی — اگر نگوییم همه — از کدهای اسکلت‌وار برای کمک به تعریف توابع و متدهای داخلی استفاده می‌کنند. این کار، راهی ساده برای برنامه‌نویسان تازه‌کار فراهم می‌کند تا با نحو (syntax) و نحوه‌ی پیاده‌سازی مورد انتظار توابع نوشته‌شده آشنا شوند.

جاوا، به‌عنوان یک زبان شی‌گرا، تمرکز زیادی بر روی مستندسازی ساخت‌یافته دارد. در صفحات مستندات جاوا، متدهای مربوط به هر شیء که بخشی از پکیج‌های جاوا هستند، به‌صورت کاملاً جداگانه و منظم تعریف شده‌اند. زبان‌های شی‌گرا مانند جاوا به‌جای پیروی از رویکرد ساده‌ی بالا به پایین، بر ساختار سلسله‌مراتبی (hierarchical) تکیه دارند. در این زبان‌ها، «اشیاء (objects)» داده‌ها و متغیرها را در خود نگه می‌دارند و این امکان را فراهم می‌سازند تا برنامه‌هایی کارآمدتر نوشته شوند. این اشیاء دارای توابعی هستند که می‌توانند به متغیرهای داخلی دسترسی پیدا کنند، که به آن‌ها متد (method) گفته می‌شود. 

در مستندات جاوا، هر متد به شکلی مشخص تعریف می‌شود: نام متد و نحوی که باید در محیط توسعه (IDE) نوشته شود، در بالای هر بلوک قابل مشاهده است. با توجه به تأکید جاوا بر محدوده‌ی متغیر (scope)، انواع داده و وراثت (inheritance)، این نوع نحو بسیار مفید و آموزنده برای برنامه‌نویسان — چه تازه‌کار و چه حرفه‌ای — است. در ادامه‌ی هر تعریف، توضیحی دقیق از عملکرد متد و خطاهای احتمالی نیز ارائه می‌شود.

زبان پایتون نیز رویکردی مشابه برای مستندسازی متدهای درونی خود دارد، اما این رویکرد بازتابی از سادگی پایتون و عدم تمرکز آن بر روی محدوده‌ها و انواع داده است. مستندات پایتون شامل نحوی از هر متد، توضیحی کوتاه، و مثالی کاربردی برای استفاده معمول آن متد یا تابع است. کد اسکلت‌واری که در این مثال‌ها ارائه می‌شود، به برنامه‌نویسان این امکان را می‌دهد که در نگاه اول، درک خوبی از عملکرد آن تابع یا متد پیدا کنند.

 تعریف کلاس 
کلاس‌هایی که توسط توسعه‌دهندگان شخص ثالث (third-party) به‌عنوان بخشی از کتابخانه‌ها نوشته می‌شوند، معمولاً به شکل کد اسکلت‌وار ارائه می‌گردند. این کار به کاربران تازه‌وارد به کتابخانه کمک می‌کند تا درک بهتری از نحوه‌ی عملکرد توابع و متدهای موجود داشته باشند. به‌عنوان نمونه، کتابخانه‌ی P5.js از همین ساختار در مستندات خود استفاده می‌کند تا کاربرد موردنظر برخی توابع از پیش تعریف‌شده را نمایش دهد. این روش با مستندسازی زبان‌های برنامه‌نویسی متفاوت است، زیرا در این‌جا تمرکز روی نمایش پارامترهای ورودی هر تابع است، نه تمام کاربردهای ممکن آن متد.

واسط‌های زبان طبیعی بیشتر در مواردی دیده می‌شوند که برنامه‌نویسان می‌خواهند ورودی‌ای را از کاربر دریافت کنند — ورودی‌ای که اغلب به‌صورت محاوره‌ای (و بدون اصطلاحات خاص برنامه‌نویسی) بیان می‌شود — و بر اساس آن، یک برنامه یا تابع تولید کنند. در برخی پیاده‌سازی‌ها، یک مجموعه کوچک از کد اسکلت‌وار به‌کار می‌رود تا عملکردی را که در پس‌زمینه در حال اجراست، شبیه‌سازی یا نمایندگی کند.

دیگر شکل‌های واسط زبان طبیعی نیز از انواع مختلف ورودی استفاده می‌کنند: 

از ورودی‌های گفتاری در زبان‌های مختلف، گرفته تا حرکات فیزیکی (gesture-based input) — همه‌ی این‌ها در نهایت با هدف تولید یک نتیجه مشابه یعنی تولید کد هستند. از آنجا که اکثر زبان‌های برنامه‌نویسی مدرن به زبان انگلیسی طراحی شده‌اند، افرادی که به زبان‌های دیگر صحبت می‌کنند، ممکن است در یادگیری و توسعه نرم‌افزار با دشواری مواجه شوند. در برخی مطالعات، واسط‌های زبان طبیعی برای کمک به این دسته از افراد مورد استفاده قرار گرفته‌اند. یکی از این مطالعات نشان داد که چگونه کلاس‌هایی به زبان جاوا از طریق ورودی‌های زبان طبیعی ساخته شده‌اند. در این حالت، نیازی به یادگیری قواعد نحوی (syntax) زبان برنامه‌نویسی نبود، اما در عوض، کلاس‌ها بر پایه‌ی یک مجموعه‌ی ساده از کد اسکلت‌وار نوشته شدند.

 تعریف بر پایه‌ی چندریختی 
چندریختی (Polymorphism) یکی از مفاهیم اصلی در پارادایم برنامه‌نویسی شی‌گرا است. در این مفهوم، متدها می‌توانند بازنویسی (Override) یا بارگذاری مجدد (Overload) شوند؛ به این معنا که یک متد با همان نام در کلاس فرزند تعریف می‌شود و اولویت اجرا با متد کلاس فرزند خواهد بود، حتی اگر در کلاس والد متدی با همان نام وجود داشته باشد. تعریف این متدها بر پایه‌ی چهارچوب اسکلت‌واری است که توسط نحو (syntax) زبان برنامه‌نویسی تعیین می‌شود.

مشابه پیاده‌سازی کلاس‌ها، از کد اسکلت‌وار برای تعریف متدهایی که بخشی از یک رابط (interface) هستند نیز استفاده می‌شود.Interface در واقع نقشه‌ی اولیه‌ای برای یک کلاس است که در زبان‌های شی‌گرای سخت‌گیر مانند Java، امکان استفاده از کلاس‌هایی در پکیج‌های مختلف را فراهم می‌کند بدون نیاز به دانستن جزییات درونی عملکرد آن‌ها. رابط‌ها فقط نام و قالب متدهایی را تعریف می‌کنند که باید در کلاس پیاده‌سازی شوند، و این اجازه را می‌دهند تا برنامه‌نویسان دیگر، آن کلاس را متناسب با نیازهای خود گسترش دهند یا از متدهای تعریف‌شده استفاده کنند.

کلاس‌های انتزاعی بسیار شبیه کلاس‌های معمولی هستند، با این تفاوت که بسته به زبان، حداقل یک متد باید به‌صورت انتزاعی (abstract) تعریف شده باشد.این یعنی هر کلاسی که از این کلاس ارث‌بری کند (extends یا implements) باید متد مربوطه را پیاده‌سازی کند. کلاس‌های انتزاعی از لحاظ ساختاری شباهت زیادی به interface دارند، اما معمولاً با کلمه‌ی کلیدی abstract مشخص می‌شوند تا نشان دهند که آن متد باید در کلاس‌های فرزند پیاده‌سازی شود.

 برنامه‌نویسی موازی 
برنامه‌نویسی موازی به معنای اجرای هم‌زمان چندین تابع است که معمولاً برای افزایش بهره‌وری مورد استفاده قرار می‌گیرد. این نوع برنامه‌ها معمولاً از سخت‌ترین انواع نرم‌افزارها برای توسعه هستند، زیرا علاوه بر پیچیدگی ذاتی، ارتباط تنگاتنگی نیز با سخت‌افزار مورد استفاده دارند. بسیاری از توسعه‌دهندگان تلاش کرده‌اند برنامه‌هایی با این عملکرد اصلی بنویسند، اما نتایج به‌دست‌آمده متفاوت بوده است.

در برنامه‌نویسی موازی، از چهارچوب‌های اسکلت الگوریتمی استفاده می‌شود تا روش‌های موردنظر به‌صورت انتزاعی توصیف شوند و در مراحل بعدی توسعه یابند. این چهارچوب‌ها به یک نوع خاص محدود نمی‌شوند و هرکدام هدف متفاوتی برای افزایش بهره‌وری برنامه توسعه‌دهنده دارند. این چهارچوب‌ها را می‌توان به سه نوع اصلی دسته‌بندی کرد: داده‌موازی (data-parallel)، وظیفه‌موازی (task-parallel) و حل مسئله (resolution)

 داده‌موازی 
الگوریتم‌های اسکلت داده‌موازی برای توسعه‌ی برنامه‌هایی استفاده می‌شوند که با نرم‌افزارهای مبتنی بر داده‌های بزرگ کار می‌کنند و معمولاً برای شناسایی ارتباطات بین داده‌ها جهت استفاده در مراحل بعدی به کار می‌روند. الگوریتم‌های داده‌موازی شامل مفاهیمی مانند 'نقشه‌برداری' (maps)، 'انشعاب' (forks)، 'کاهش' (reduces) یا 'پویش' (scans) هستند.

 "نقشه‌برداری" رایج‌ترین نوع الگوریتم‌های داده‌موازی هستند. این الگوریتم‌ها معمولاً شامل انجام یک عملیات واحد بر روی یک مجموعه‌ی بزرگ از داده‌ها می‌شوند. برای افزایش بهره‌وری، این عملیات به‌طور هم‌زمان بر روی چندین مجموعه‌داده اعمال می‌شود و سپس داده‌ها در پایان دوباره با هم ترکیب می‌شوند.
 "انشعاب" مشابه maps هستند، با این تفاوت که از عملیات‌های متفاوت برای انواع مختلف داده‌ها استفاده می‌کنند. به این نوع الگوریتم‌ها چندداده‌موازی (multiple data parallelism) گفته می‌شود.
 "کاهش / پویش" برای افزودن پیشوند (prefix) به یک مجموعه داده قبل از اعمال یک عملیات اصلی استفاده می‌شوند. این الگوریتم‌ها با maps تفاوت دارند، زیرا در طول زمان اجرای متد، مجموعه‌ای از نتایج جزئی تولید می‌شود.

 وظیفه‌موازی 
همان‌طور که از نام آن پیداست، این نوع عملیات بر اساس وظایف (Tasks) انجام می‌شود. هر نوع الگوریتم در این دسته با دیگری متفاوت است، زیرا رفتار میان وظایف مختلف تغییر می‌کند. الگوریتم‌های وظیفه‌موازی شامل مواردی مانند: Sequential، Farms، Pipes، If، For و While هستند.

 "ترتیبی" برای پایان دادن به مجموعه‌های تودرتوی الگوریتم‌های اسکلت‌وار به‌کار می‌رود. متدها و برنامه‌هایی که بخشی از اسکلت هستند، پیش از بسته‌شدن برنامه، به‌عنوان بخش نهایی و خاتمه‌دهنده اجرا می‌شوند.
 "مزارع" به‌عنوان گروهی از وظایف، کارگر (worker) یا به‌صورت رابطه‌ی ارباب/برده (master/slave) با تابع دیگر شناخته می‌شود. در این الگوریتم، وظایف داده‌شده با تکرار آن‌ها در چندین نخ (thread) به‌طور هم‌زمان انجام می‌گیرد. این کار باعث تقسیم بار کاری بین نخ‌ها می‌شود و ساختاری مانند ارباب/برده میان آن‌ها ایجاد می‌کند.
 "لوله‌ها" فرم سنتی‌تری از الگوریتم‌ها هستند که در آن هر متد یا تابع به‌ترتیب اجرا می‌شود، دقیقاً همان‌گونه که برنامه‌نویس آن را نوشته است. این عملیات با اجرای وظایف متفاوت به‌صورت هم‌زمان روی مجموعه‌ای از داده‌ها (معمولاً ورودی) به حالت موازی در می‌آید تا سرعت و کارایی افزایش یابد. هر عملیات هم‌زمان در این ساختار یک مرحله (stage) نامیده می‌شود. Pipe می‌تواند تو در تو (Nested) باشد و مسئولیت‌ها را تقسیم کند تا سرعت و تعداد مراحل بیشتر شود.
 "if" باعث انشعاب شرطی در وظایف برنامه می‌شود. در این حالت، اسکلت کد به دو بخش اصلی تقسیم می‌شود و بر اساس یک عبارت شرطی، مسیر اجرای الگوریتم تعیین می‌شود.
 "For" وظیفه‌ای را برای تعداد دفعات مشخصی که توسط برنامه‌نویس تعیین شده اجرا می‌کند. تعداد تکرارها از پیش تعیین شده است و در زمان اجرا تغییر نمی‌کند. برنامه باید دقیقاً به همان تعداد، وظیفه را انجام دهد.
 "while" شباهت زیادی به for دارد، اما تفاوت آن در این است که تعداد تکرارها از پیش مشخص نیست. وظیفه تا زمانی که یک عبارت شرطی برقرار نباشد تکرار می‌شود، بنابراین هر بار اجرا ممکن است تعداد تکرارها متفاوت باشد.

 اسکلت‌های حل مسئله 
این نوع اسکلت‌ها با اسکلت‌های معمولی که پیش‌تر معرفی شدند تفاوت زیادی دارند. الگوریتم‌های «حل مسئله» (Resolution) از ترکیبی از روش‌ها برای حل یک مسئله‌ی مشخص استفاده می‌کنند. مسئله‌ی ارائه‌شده در این الگوریتم‌ها می‌تواند شامل "خانواده‌ای از مسائل" باشد. این اسکلت‌ها دو نوع اصلی دارند: «Divide and Conquer» (تقسیم و غلبه) و «Branch and Bound» (شاخه و کران).

 تقسیم و غلبه: در این روش، از اسکلت map به‌عنوان پایه استفاده می‌شود و با اسکلت while ترکیب می‌گردد تا مسئله حل شود. در الگوریتم‌های map، توابع بر روی داده‌ها به‌صورت هم‌زمان اعمال می‌شوند. در الگوریتم تقسیم و غلبه، مجموعه‌ای از داده‌ها گرفته می‌شود و با استفاده از اسکلت map، یک تابع روی آن اعمال می‌گردد، اما این فرآیند می‌تواند به‌صورت بازگشتی و با استفاده از اسکلت while انجام شود. اجرای while تنها زمانی متوقف می‌شود که کل مسئله حل شده باشد.
 شاخه و کران: این الگوریتم نیز از اسکلت map استفاده می‌کند، اما به‌جای استفاده از الگوریتم while برای اجرای هم‌زمان وظایف، وظایف به شاخه‌هایی تقسیم می‌شوند. هر شاخه دارای یک هدف مشخص یا "کران" (bound) است، و هنگامی که یک عبارت شرطی برقرار شود، آن شاخه متوقف می‌شود.

 منابع 

 Freeman, Eric; Freeman, Elisabeth; Kathy, Sierra; Bert, Bates (2004). Hendrickson, Mike; Loukides, Mike (eds.). Head First Design Patterns (paperback). Vol. 1. O'REILLY. p. 440. ISBN 978-0-596-00712-6. Retrieved August 28, 2012.
 Lowery, Jeff (November 2, 2019). "Why is Software Development Difficult?". Medium. Retrieved November 15, 2020.
 Bellamy, Rachel K. E. (June 1, 1994). "What Does Pseudo-Code Do? A Psychological Analysis of the use of Pseudo-Code by Experienced Programmers". Human–Computer Interaction. 9 (2): 225–246. doi:10.1207/s15327051hci0902_3. ISSN 0737-0024.
 "Object (Java Platform SE 8 )". docs.oracle.com. Retrieved October 2, 2020.
 "Built-in Functions — Python v3.0.1 documentation". docs.python.org. February 14, 2009. Retrieved October 3, 2020.
 "reference | p5.js". p5js.org. Retrieved November 15, 2020.
 Granger, Chris (November 18, 2020). "A first peek at something new we're working on". Twitter. Retrieved November 19, 2020.
 Özcan, E. (2004). "Generating Java Class Skeleton Using a Natural Language Interface". Proceedings of the 1st International Workshop on Natural Language Understanding and Cognitive Science. 1. SciTePress - Science and Technology Publications: 126–134. doi:10.5220/0002683301260134. ISBN 972-8865-05-8.
 Benaya, Tamar; Zur, Ela (2008), "Understanding Object Oriented Programming Concepts in an Advanced Programming Course", Informatics Education - Supporting Computational Thinking, Lecture Notes in Computer Science, vol. 5090, Berlin, Heidelberg: Springer Berlin Heidelberg,
 González-Vélez, Horacio; Leyton, Mario (November 1, 2010). "A survey of algorithmic skeleton frameworks: high-level structured parallel programming enablers". Software: Practice and Experience. 40 (12): 1135–1160. doi:10.1002/spe.1026. ISSN 0038-0644. S2CID 16211075.

رده:مقاله‌های ایجادشده توسط ایجادگر