فهرست مطالب
- مقدمه
- گواهی لغو مسئولیت!
- پیش نیاز
- چرا زبانهای استاتیک؟
- سوال و جوابهای متداول
- با وجود تست ها، باز هم به تایپ نیاز داریم؟
- چطور یکی از پایدارترین سیستمهای نرمافزاری دنیا با ارلنگ که یک زبان داینامیک است نوشته شده؟
- پس چرا فیسبوک هنوز از PHP که یک زبان داینامیک است استفاده میکند؟
- پس چرا اینستاگرام هنوز از پایتون که یک زبان داینامیک است استفاده میکند؟
- من برایم سرعت مهم نیست؛ آیا باز هم به استاتیک تایپنگ نیاز دارم؟
- برنامهی من زیاد بزرگ نیست، آیا باز هم به استاتیک تایپنگ نیاز دارم؟
- سخن آخر
مقدمه
درباره انتشار این مطلب مردد بودم! به دو دلیل:
- مقایسه زبانهای استاتیک و داینامیک در گروه «جنگهای تاریخی» صنعت نرم افزار جا میگیرد (در کنار مقایسههایی مثل ویندوز یا لینوکس، ویم یا ایمکس، تب یا اسپیس!…). یعنی به محض انتشار چنین پستی، باید خودتان را آماده حرف شنیدن کنید!
- این بحث بعد از سالهای متمادی حالت کلیشهای پیدا کرده. اغلب برنامهنویسان که مدت طولانی وبلاگ مینویسند، به طور مستقیم یا غیر مستقیم مطلبی درباره این موضوع دارند.
اما چرا در نهایت تصمیم به انتشار این پست گرفتم:
- این مقایسه بر خلاف مقایسههای رایج دنیای کامپیوتر، جنبهی فنی و تخصصی دارد؛ یعنی نمی شود همینطور از روی «علاقه»ی شخصی راجع بهش حرف زد. تا جایی که توانستم سعی کردم فقط به مزایای زبانهای استاتیک بپردازم و از جبههی مقابل بد نگویم!
- راستش را بخواهید، مطلب مناسبی در وب فارسی در باب این موضوع پیدا نکردم!
گواهی لغو مسئولیت!
این پست، از طرف شخصی نوشته شده که بخش بزرگی از دوران برنامهنویسی خودش را در زبانهای کاملا داینامیک کد زده و هنوز هم میزند! (Python, PHP, JS, …). یعنی با چم و خم این زبانها دست و پنجه نرم کردهام. با تمام فواید و یا دردسرهایشان هم آشنایی دارم. این مطلب مبتنی بر تجربهی واقعی خواهد بود و همینطور روی هوا حرفی نخواهم زد. اما میدانم که تجربیات شما ممکن است با من متفاوت باشد.
پیش نیاز
برای مطالعهی این مطلب، پیشنهاد میکنم ابتدا مطالب زیر را که در همین وبلاگ موجود هستند مطالعه فرمایید:
اگر حوصلهی خواندن این مطالب را ندارید، پس حداقل به طور خلاصه این موارد را به یاد داشته باشید:
-
تایپ: خصوصیتی است که تعیین میکند یک «داده» میتواند شامل چه «محتوا» ای باشد و چه کارهایی میتوان با آن انجام داد. هر تایپ، مشخص کنندهی «مجموعه مقادیر یا حالاتی» است که یک داده میتواند به خود بگیرد.
-
زبان Static Type: به زبانی «استاتیک تایپ» میگوییم که در آن فرآیند چک کردن تایپها «قبل از اجرای برنامه» اتفاق بیفتد.
-
زبان Dynamic Type: به زبانی «داینامیک تایپ» میگوییم که در آن فرآیند چک کردن تایپها «در زمان اجرای برنامه» اتفاق بیفتد.
-
زبان Strong Type: جدای از این قضیه که زبان استاتیک تایپ باشد یا داینامیک تایپ، اگر زبانی سیستم تایپ را با جدیت کامل اعمال کند، میگوییم که آن زبان دارای تایپ مستحکم یا استرانگ تایپ است. مثلا زبان نباید اجازه دهد دادهی عددی 12 با دادهی رشتهای “hi” جمع و تفریق شود.
-
زبان Weak Type: جدای از این قضیه که زبان استاتیک تایپ باشد یا داینامیک تایپ، اگر زبانی سیستم تایپ را با جدیت کامل اعمال نکند، میگوییم که آن زبان دارای تایپ سُست یا ویک تایپ است. از نمونههای بارز چنین زبانهایی JS و PHP هستند. مثلا در این زبانها عدد 6 را میتوان با رشتهی “Hello” جمع بست؛ که از نظر منطقی بیمعنی است!
-
استاتیک بودن زبان، حتما به این معنی نیست که «اعلانهای تایپ» را در کدهایمان ذکر کنیم: مثلا int (هرچند که اکثر این زبانها چنین خصوصیتی دارند).
-
استاتیک بودن زبان، ربطی به کامپایلری بودن یا نبودن زبان ندارد. (هرچند که اکثر آنها کامپایلری میباشند). مثلا ارلنگ، الیکسیر، یا کلوژور همگی زبانهای کامپایلری هستند، ولی تمام آنها داینامیک تایپ میباشند!
با این توضیحات، مطلب را ادامه میدهیم.
چرا زبانهای استاتیک؟
تمام مزایای زبانهای استاتیک تایپ، به طور مستقیم یا غیر مستقیم به این موضوع برمیگردد که «کامپایلر» یا «تایپ چِکِر» میتواند به کمک تایپها، اطلاعات بیشتری نسبت به کدهای ما داشته باشد. و همین اطلاعاتی که کامپایلر جمع آوری میکند، باعث میشود تا توانایی یاری رساندن به ما در زمان توسعهی کدهایمان را داشته باشد.
صحت
عدهای فکر میکنند وقتی گفته میشود زبانهای استاتیک تایپ ضریب «صحت» بالاتری برای کدها به ارمغان می آورند، منظور فقط این است که نوع متغیرها باهم اشتباه نمیشود! مثلا اگر پارامتر تابعی را از نوع int تعریف کنیم، و بعدها به اشتباه به جایش یک دادهی string را ارسال کنیم، کامپایلر متوجه این خطا میشود. درست است، این هم در نوع خودش باعث بالا رفتن صحت کدها خواهد شد، ولی قضیه خیلی فراتر از این حرف هاست…
زبانهای استاتیکی داریم که به کمک تایپ سیستم خود، مشکل تاریخیِ ارجاعات Null را حل کردهاند! یا مثلا زبانی مانند Rust داریم که به کمک تایپ سیستم خود شرایطی را مهیا کرده است که بدون وجود GC، بتوانیم براحتی حافظه را مدیریت کنیم؛ اگر کدهای شما در این زبان کامپایل شود، یعنی تایپ سیستم تایید کرده است که Memory leak در آنها وجود نخواهد داشت. اگر کدهای شما در این زبان کامپایل شود، یعنی تایپ سیستم تایید کرده است که در بین Thread های شما Data Race اتفاق نخواهد افتاد!
چنین چیزهایی فاکتورهای بسیار مهمی هستند. و تمام شان به کمک استاتیک تایپینگ ممکن شدهاند و لازم نیست شما زحمت خاصی را برایشان متحمل شوید. کافیست در گوشه و کنار کدهایتان به طور خیلی مختصر یک سری اطلاعات را در اختیار کامپایلر قرار دهید، تا کامپایلر بتواند خودش بقیه کارها را برایتان انجام دهد.
موضوع دیگر، بازخورد سریع در صورت وقوع خطاست. یعنی اگر کدهای شما دارای موارد اشتباهی بود، در همان پروسهی کامپایل مشخص میشود و شما کلا به مرحلهی اجرا نمیرسید. در صورتی که زبان های داینامیک نمیتوانند خطا ها را بدون اجرا کردن برنامه تشخیص دهند.
سرعت
کامپایلر با اطلاعاتی که به کمک استاتیک تایپینگ درباره کدهای شما بدست میآورد، میتواند تا جایی که برایش امکان دارد کدهایتان را قبل از اجرا بهینه سازی نمایند. به همین دلیل در اکثر اوقات (نه در همهی اوقات)، زبانهای استاتیک سرعت بالاتری به نسب زبانهای داینامیک دارند.
هر چه یک زبان تایپ سیستم بهتری داشته باشد، و هرچه برنامهنویس بتواند بهتر از تایپ سیستم در کدهایش استفاده کند، کامپایلر قادر خواهد بود اطلاعات بیشتری از کدها بدست بیاورد. و هر چقدر هم که کامپایلر بیشتر اطلاعات بدست بیاورد، ضریب بهینهسازی هایی که میتواند روی کدها انجام دهد بالاتر خواهد رفت.
در زبانهای داینامیک نمی توان قبل از اجرای برنامه هیچ حدسی راجع به کدها داشته باشیم! راه حلی که برای بهینهسازی در زبانهای داینامیک پیشنهاد میشود استفاده از سیستم JIT است. این سیستم میتواند به منظور کسب اطلاعات مورد نیاز برای بهینهسازی، کدها را در زمان اجرا زیر نظر داشته باشد تا بر مبنای اطلاعاتی که جمع آوری میکند کدهایتان در همان حالی که در حال اجرا هستند بهینه سازی کند!
مشکل اینجاست که خود JIT نوعی سربار است! چرا که این سیستم همگام با برنامهی اصلی شما اجرا خواهد شد و به طور مداوم در حال کاوش در کدهای تان خواهد بود. یعنی خودش نیاز به CPU و حافظه اضافی دارد. از طرفی JIT یک راه حل «موقتی» است! زیرا زبانهای استاتیک در هر نسخهی جدیدی که ارائه میکنند سعی در این دارند که تایپ سیستم شان را نیز تقویت میکنند؛ به همین موازات کامپایلر به اطلاعات بیشتری دسترسی پیدا میکند و میتواند بهینهسازی های بیشتری انجام دهد. مثلا خیلی از بهینهسازی هایی که امروزه در زبانهای استاتیک صورت میگیرد، شاید تا همین ۵-۶ سال پیش ممکن نبودهاند.
مستندات
از خصوصیتهای مستند سازی این است هر کسی با یک لحن متفاوت و از زوایه دید خودش آنها را مینویسد. فرضا یک برنامهنویس شاید فکر کند که تابعی به بیشتر از یک خط مستندات نیاز نداشته باشد، در صورتی که برنامه نویس دیگر حس کند که توضیحات بیشتری باید لحاظ شود.
از طرفی مستندات نیاز به حوصلهی بالایی دارند و ممکن است خیلی وقتها زیر فشار و استرس ناشی از پروداکشن نادیده گرفته شوند؛ تا بعدها در فرصت بهتری به آنها رسیدگی شود. بنابراین این احتمال دارد که شما کدهایتان را تغییر دهید، ولی مستندات آن را چند روز بعد آپدیت کنید.
تایپ، خودش یک نوع مستند سازی است! یعنی حتی اگر برای تابعی هیچ مستنداتی هم ارائه ندهیم، باز هم درک آن تابع از نسخهی مترادفاش در یک زبان داینامیک راحتتر خواهد بود؛ چون اینجا حداقل برنامهنویس لازم نیست نوع دادههای ورودی و خروجی را خودش «حدس» بزند.
مستندات فقط نوشته میشوند، ولی قابل چک شدن و اعتبارسنجی نیستند!
ابزارهای جانبی
یکی از اصلی ترین مزایای زبانهای استاتیک این است که «کامپایلر» تنها عاملی نیست که میتواند درباره کدها اطلاعات جمع آوری کند! «ابزارهای جانبی» نیز میتوانند کدهای شما را آنالیز کنند و اطلاعات مورد نیازشان را از آن استخراج نمایند.
آنها به کمک این اطلاعات قادر خواهند بود خدمات زیادی به برنامهنویسان ارائه کنند. مثلا IDE ها با آنالیز کدها، هنگامی که برنامهنویس مشغول نگارش است مدام او را در امر نوشتن راهنمایی می کنند و گزینههای مختلف را به او نشان میدهند. وجود چنین ابزارهایی زبان را برای استفاده در تیمهای بزرگ آماده میکند.
خوبی زبانهای استاتیک این است که وقتی از طرف یک ابزار جانبی می خواهید با آنها طرف شوید، به شکل یکسانی با آنها در ارتباط خواهید بود. همهی برنامهنویسان میدانند که قرار است به چه حالتی با تایپ سیستم در ارتباط باشند. فرضا سیستمهایی داریم که در صورت مشاهدهی پیغام خطا در ترمینال، میتواند آن را پردازش نمایند و به برنامهنویس اطلاع دهند. در زبانهای داینامیک خیلی از پیغام ها بسته به سلیقهی برنامه نویس آن پروژه نگارش میشوند در صورتی که در زبان های استاتیک از طرف خود زبان تولید میشوند و همیشه فرم یکسانی دارند.
مدلسازی، قبل از پیادهسازی
در زبانهای استاتیک قبل از اینکه کدهای اصلیتان را بنویسید، ابتدا به کمک تایپها ملزومات برنامه را مدل سازی می کنید. کامپایلر با کمک این مدلها با کاری که قرار است انجام گیرد آشنا میشود؛ تا در هنگامی که به پیادهسازی این مدلها میرسید، کامپایلر بتواند شما را در پیادهسازی بهتر کدهایتان راهنمایی کند.
در زبانهای داینامیک شما یک سری از تشریفات اینچنینی را لازم ندارید و میتوانید به سرعت کدهایتان را پیاده سازی کنید. این هم در نوع خودش یک مزیت است! ولی اینجا دیگر فقط خودتان هستید و خودتان! یعنی دیگر دستیاری در کار نیست که شما را در کار همراهی کند.
بازسازی (Refactoring)
فرض کنید به هر دلیلی تصمیم دارید قسمتی از کدهایتان را تغییر دهید. اگر کل کدهایتان در حد چندصد خط باشد، شاید خیلی این قضیه برایتان مهم جلوه نکند. ولی وقتی پروژه بزرگی را در اختیار داشته باشید متوجه میشوید که حتی اعمال تغییر در یکی از خطوط، میتواند در عملکرد چندین سورس کد دیگر تاثیر گذار باشد. اوضاع وقتی بدتر میشود که چند نفره در حال توسعهی این پروژه باشید و اطلاع نداشته باشید که همکارتان چیزی را در جایی تغییر داده است.
بدون وجود استاتیک تایپینگ، شما خیلی از مواقع متوجه این تدخلات نمیشوید. حتی ممکن است برنامه در ابتدا درست کار کند. شما هم آن را به مشتری تحویل دهید و یا روی پروداکشن فعالاش کنید. یکدفعه دو روز بعد مشتری زنگ میزند و اطلاع میدهد که در فلان جای برنامه مشکلی پیش آمده. باور کنید یا نکنید، خیلی از این خطاها با یونیت تست هم آشکار نمیشود. مخصوصا در برنامههای GUI یا برنامههای وب که تست کردن قسمتهای گرافیکی برنامه خیلی راحت نیست.
اعتماد به نفس بالاتر!
به عنوان برنامه نویسی که کدهای داینامیک زیادی نوشته، اعتراف میکنم که همیشه هنگام تحویل پروژه به مشتری بسیار استرس داشتهام! حتی همین الان که در حال نوشتن این مطلب هستم میدانم که کدهای چند سال قبلام در برخی پروژهها، ممکن است در یک سری از سناریوهای خاص به مشکل بربخورد (و در حقیقت از روی شانس است تا الان بدون مشکل کار کردهاند!).
همین استرس را موقع تحویل دادن کدهای استاتیک نیز دارم، ولی به مراتب کمتر! چون خیالم راحت بوده که کدهایم حداقل از لایه نظارتی تایپ سیستم عبور کرده است و این موضوع از شدت نگرانیهایم کم میکند. اگر هم بعدها لازم باشد پروژه را تغییر دهم، دیگر تک به تک خطها را با ترس ادیت نمیکنم! میدانم که کامپایلر از کدهایی که من یک سال قبل نوشتهام، بهتر از خودم اطلاع دارد! کامپایلر پشتیبان من خواهد بود!
سوال و جوابهای متداول
**با وجود تست ها، باز هم به تایپ نیاز داریم؟**
تایپ ها میتوانند شما را از تست نوشتن برای گروه بزرگی از موارد راحت کنند! و شما را قادر میسازند تا برای آن گروه از موارد دیگر نیز تست های موثر تری ارایه دهید. یعنی حالا تست های شما متوجه موارد خاص تر و مهم تر خواهد بود. نه اینکه بیایید و تست کنید که آیا اگر در فلان تابع به جای مقدار عددی، مقدار رشته ای وارد کردیم، تابع قرار است چگونه عکس العمل نشان دهد!
حالا خودمانیم! واقعا فکر میکنید همهی برنامهنویسها با وسواس برای کدهایشان تست مینویسند؟ یا همانهایی هم که می نویسند، چند درصد از تستهایشان واقعا موثر هست و چند درصد فقط جنبهی نمایشی دارد برای راضی نگه مدیر پروژه؟
**چطور یکی از پایدارترین سیستمهای نرمافزاری دنیا با ارلنگ که یک زبان داینامیک است نوشته شده؟**
این داستان برمیگردد به آپتایم 99.9999999% برخی از سرویسهای اریکسون که با ارلنگ نوشته شدهاند. بدست آوردن این درصد بالا از آپتایم، کلا در هیچ زبانی راحت نیست؛ فرقی هم ندارد که زبان استاتیک باشد یا داینامیک.
درباره ارلنگ، باید چند موضوع را در نظر داشته باشید:
-
اصلیترین مزیت ارلنگ، خصوصیت Fault tolerance بودن آن است. یعنی مکانیزهای زیادی در آن پیشبینی شده تا در مواجه با خطا، سیستم بتواند به کار مداوم خود ادامه دهد. بنابراین آن آپتایم عجیب و غریبی که میبینید به این خاطر نیست که در ارلنگ هیچ خطایی پیش نخواهد آمد؛ ممکن است در همان سیستم نیز روزانه صدها و شاید هزاران خطا پیش میآمده، ولی مهندسان حتما از خصوصیتهای Fault tolerance استفاده کردهاند تا سیستم حتی با وجود این خطاها نیز متوقف نشود. قضیه کلا ربطی به استاتیک بودن یا داینامیک بودن ارلنگ ندارد!
-
داینامیک بودن ارلنگ، بر مبنای «نیاز سیستم» بوده است؛ و نه بر مبانی «راحتی»! قضیه این است که رانتایم ارلنگ به منظور خاصیت Fault tolerance بودن آن، طبیعتای بسیار داینامیک دارد. و منطقی است که برای طرف شدن با چنین رانتایمی، از یک زبان داینامیک استفاده شود.
-
سیستمهای ارلنگ در اریکسون، توسط خود سازندگان ارلنگ و تیم توسعه دهنده آن ساخته شده است. افرادی که بسیار بهتر از من و شما از داخل و خارح ارلنگ خبر دارند. مشخص است اگر کار را به چنین چنین گروهی بدهید نتیجه مناسبی خواهید گرفت. واقعا فکر میکنید تمام دیگر شرکتهایی که از ارلنگ استفاده کردهاند هم همینطور آپتایم بالا داشتهاند؟
-
به گفتهی جو آرمسترانگ استفاده از Dialyzer موقع توسعهی کدهای ارلنگ برای پروداکشن، یک پیشفرض محسوب میشود! باید مطلع باشید که ارلنگ از مدتها قبل به استاتیکتایپینگ اختیاری مجهز شده است؛ Dialyzer تایپچِکِرِ مختص به ارلنگ است که میتواند کدهای ارلنگ را از نظر درستی تایپها بررسی کند. درصد بالایی از برنامهنویسان ارلنگ کدهایشان را تایپ نگاری می کنند.
**پس چرا فیسبوک هنوز از PHP که یک زبان داینامیک است استفاده میکند؟**
استفاده نمیکند! با بزرگ شدن فیسبوک، خودشان متوجه شدند که PHP دیگر جواب گوی نیازشان نیست. فیسبوک در نهایت به خاطر کمبود سرعت و مشکل در ریفکتور کردن کدها، مجبور به ساختن Hack و HHVM شد. اطلاعات بیشتر درباره وضعیت PHP در فیسبوک.
**پس چرا اینستاگرام هنوز از پایتون که یک زبان داینامیک است استفاده میکند؟**
پایتون در اینستاگرام، آن چیزی نیست که شما از سایت رسمیِ پایتون دانلود می کنید! پایتونی که در اینستاگرام استفاده میشود از بالا و پایین و چپ و راست بهینه سازی شده! جدای از مشکل سرعت، اینستاگرام هم در رفکتور کردن کدها به مشکل برخورده و کدهاش را کم کم به سمت MyPy که تایپ سیستم اختیاری پایتون است میبرد. مدتی پیش اعلام کرد که توانسته یک/سوم کدهایش را با MyPy سازگار کند. اطلاعات بیشتر درباره وضعیت پایتون در اینستاگرام.
**من برایم سرعت مهم نیست؛ آیا باز هم به استاتیک تایپنگ نیاز دارم؟**
زبانهای مبتنی بر جاوا اسکریپت همگی روی استاتیک تایپ بودن مانور میدهند. PHP در هر نسخهی جدید که منتشر میکند در حال توسعهی تایپ نگاری در کدهاست تا با ابزارهای نظیر Phan بتواند کدها را آنالیز کند. پایتون برای خودش پروژهی MyPy را راه انداخته که خالق پایتون نیز مدیر این پروژه است. کلوژور در ورژنهای جدیدتر تایپ نگاری را جدی گرفته. ارلنگ و الیکسیر از دیرباز دارای استاتیک تایپینگ اختیاری بودهاند…
نکته این جاست: اضافه کردن قابلیتهای استاتیک تایپینگ در این زبانهایی که اسم بردم، هیچ منفعتی از نظر سرعت برایشان نداشته است! فرضا اگر کدهای پایتون را تایپ نگاری کنید، هیچ فرقی از سرعت با کدهای تایپ نگاری نشده نخواهند داشت. پس اگر همه چیز سرعت بود، چرا سازندگان و توسعه دهندگان این زبانها در تکاپو هستند که امکانات استاتیک تایپینگ را به زبان اضافه کنند؟ سرعت، «فقط یکی» از عوامل سودمند استاتیک تایپینگ است.
**برنامهی من زیاد بزرگ نیست، آیا باز هم به استاتیک تایپنگ نیاز دارم؟**
اول باید مشخص کرد که منظور ما از یک «برنامهی بزرگ» چیست! فرضا من اگر پروژه ای داشته باشم که کدهایش بیشتر از ۲-۳ هزار خط شود، آن پروژه را یک برنامهی بزرگ به حساب میآورم! ممکن است بگویید مقیاسی که عنوان کردی بسیار ناچیز و کوچک است؛ اما من بزرگ بودن برنامه را به میزان سرعت، یا بزرگی تیم، یا شمار بالای مشتریان نمیبینم؛ برای من بزرگی پروژه مبتنی بر این است که تا چه حد بتوانم بخشهای مختلف آن را ذهن نگه داری کنم؟
فرضا اگر خواستم در فایل B، یکی از توابعی را که خودم در فایل A نوشتهام را استفاده کنم، باید بتوانم خیلی راحت این کار را انجام دهم. اما اگر طرز کار یا پارامترهای آن تابع را یادم رفت و مجبور شدم برای یادآوری فایل A را دوباره باز کنم تا بتوانم نگاهی به آن تابع بیندازم، یعنی پروژه به قدری بزرگ شده که من نتوانستهام تمام بخشهای آن را در ذهن نگه داری کنم. در این چنین شرایطی استفاده از یک زبان استاتیک تایپ مناسب خواهد بود.
بنابراین جواب این سوال بستگی به خودتان دارد. اگر مقیاس برنامه در حدی بود که براحتی توانستید بخشهای مختلف آن را به ذهن بسپارید، بنابراین زبانهای داینامیک هم گزینهی مناسبی هستند.
سخن آخر
اصلی ترین مزیت زبانهای داینامیک تمرکز روی الگوریتم است. یعنی با کمترین تشریفات و پیشنیازها، بتوانیم فکر و وقت خود را به پیاده سازی الگوریتم اختصاص دهیم.
زبانهای استاتیک مانند یک سرمایه گذاری هستند! یعنی شما کمی بیشتر وقت میگذارید تا کدهای تان را بهتر برای کامپایلر توضیح دهید، اما از آن طرف هم کامپایلر هوای شما را خواهد داشت. اگر این سرمایه گذاری را انجام دهید و زبان نتواند به میزان کافی به شما سود برساند آن موقع می گوییم که زبان، تایپ سیستم مناسبی ندارد؛ یا شاید هم ما بدرستی از تایپ سیستم زبان استفاده نکرده ایم! که در بیشتر مواقع این دومی است!به صرف این قضیه که در یک زبان استاتیک کد مینویسید، کدهای شما ایمن نخواهند شد. و اگر هم در یک زبان داینامیک کد بزنید، قرار نیست حتما دچار مشکل شوید. نقش شما به عنوان برنامه نویس در این قضایا بسیار مهم است. انتخاب بین زبانهای استاتیک و داینامیک نیز به تصمیم شما و سناریو ای که برای پروژه پیش روی خود دارید وابسته است…
نظرات
comments powered by Disqus