در این قسمت که در آگوست ۲۰۱۱ ضبط شده است مارکوس ولکر با یوناس بونر در مورد Akka صحبت می‌کند. Akka یک چارچوبِ کاری مبتنی بر اسکالا است که برای برنامه‌های هم‌روند (Concurrent) و توزیع‌شده استفاده می‌شود. Akka از اکتورها، ارتباط از راه دور، و حافظه‌ی تراکنشی پشتیبانی می‌کند. در این مصاحبه به مهم‌ترین جنبه‌های Akka و چگونگی استفاده از آن نگاهی می‌اندازیم. علاوه بر این به طور خلاصه در مورد فعالیت یوناس در شرکت Typesafe صحبت می‌کنیم.
به این قسمت از برنامه‌ی مهندسی نرم‌افزار خوش آمدید. در این قسمت باز هم در مورد چیزی مرتبط با اسکالا صحبت می‌کنیم. تا به حال دو قسمت در مورد آن داشته‌ایم: یک قسمت معرفی اسکالا و یک قسمت دیگر هم برای خبرهای جدید ، که مارتین ادرسکی مهمان آن‌ها بود. در این قسمت در مورد یک پروژه‌ی میان‌افزار (Middleware) جالب اسکالا به نام Akka صحبت می‌کنیم. احتمالاً در مورد آن شنیده‌اید. در آن سوی خط با یوناس بونر صحبت می‌کنم که توسعه‌دهنده‌ی پیشرو و مخترع Akka است. درست است؟
بله. البته امروز [انجمن] Akka بیش از من است. چند سال پیش شروع کردم و طی یک و نیم سال گذشته یک تلاش تیمی بوده است.
فکر می‌کنم ویکتور کلنگ یکی از آن‌هاست که همیشه توئیترش را می‌خوانم :-)
بله. او یکی از توسعه‌دهندگان کلیدی است؛ آدم خارق‌العاده‌ای است. توسعه‌دهندگان فوق‌العاده‌ی دیگری هم داریم و من فقط یکی از اعضای گله هستم :-)
شما قطعاً چهره‌ای هستید که بسیاری آن را به Akka نسبت می‌دهند. آیا می‌خواهید کمی خودتان را معرفی کنید تا افراد بدانند با که صحبت می‌کنیم؟
حتماً. من یوناس بونر هستم. من در سوئد زندگی می‌کنم؛ در شهر کوچکی به نام آپسالا خارج از استُکهلم. بیش از پنج سال است که با اسکالا کار می‌کنم. قبل از اسکالا با Erlang وارد برنامه‌نویسی تابعی (Functional) شدم. خلاصه این‌که از Erlang خیلی به هیجان آمدم و تلاش کردم سایر افراد -چه همکاران، و چه مشتریان- را نیز ترغیب کنم اما کار سختی بود. زبان فوق‌العاده‌ای است اما سیستم زمان اجرا و کتابخانه‌های مخصوص به خودش را دارد. اما من فکر می‌کردم چیزهای زیادی خوبی در مورد آن هست و نباید آن را در حد خوره‌های (Geek) زبان Erlang نگه داشت. می‌خواستم برخی از مفاهیم آن را به JVM منتقل کنم. بنابراین حدود دو و نیم سال پیش Akka را شروع کردم. پیش از آن در یک شرکت خوشه‌بندی JVM به نام Terracotta کار می‌کردم. در فاصله‌ی بین Terracotta و Akka در شرکت مشاوره‌ای خودم هم کار می‌کردم. قبل از Terracotta حدود چهار یا پنج سال در مجموعه BEA در تیم JRockit و تیم JVM کار می‌کردم. آن‌ها یک تیم در استُکهلم (سوئد) دارند. بنابراین من عمدتاً درگیر نوشتن محصولات میان‌افزاری در سیستم‌ها بوده‌ام. علاوه بر این در زمینه‌ی مقیاس‌پذیری همروندی کد (Code Concurrency Scalability) مشاوره می‌دهم که بیشتر مربوط به سمت سرور در پشته‌ی [تکنولوژی‌های برنامه‌نویسی] است.
با نگاه به Akka کاملاً واضح است که Erlang الهام‌بخش آن بوده است. ممکن است خلاصه‌ای از Akka به ما بگویید؟ و این‌که تأثیر‌پذیری‌های اصلی آن از Erlang چیست؟ بعداً در مورد ماژول‌های مختلف آن صحبت می‌کنیم اما فعلاً در یک توصیف اجمالی آن را خلاصه کنید.
قطعاً از Erlang تأثیر گرفته، اما از برخی زبان‌ها و ابزارهایی دیگر هم تأثیر گرفته است. من تلاش کرده‌ام برخی ابزارها و روش‌های فکری را که ممکن است به نظر یک توسعه‌دهنده‌ی عادی جاوا، بیگانه به نظر بیاید را کنار هم بیاورم. ابزارهایی که مشکلات همروندی و مقیاس‌پذیری، و تحمل‌پذیری شکست (Fault Tolerance) را به شکل زیبایی حل می‌کنند. ما مدل اکتور در همروندی (Actor Model of Concurrency) را از Erlang اقتباس کردیم که مدلی حتی بهتر از محاسبات توزیع‌شده است. سبک تحمل خطا و قابلیت اطمینان (Reliability) را هم از Erlang اتخاذ کردیم که گاهی به آن «بگذار خراب شود» (Let it Crash) یا «شکست را بپذیر» (Embrace Failure) گفته می‌شود. بعداً بیش‌تر در مورد این صحبت می‌کنیم.
ما از Akka برای مقیاس‌پذیری عمودی روی معماری‌های چند هسته‌ای استفاده می‌کنیم؛ یعنی همروندی را می‌پذیریم. همچنین از Akka برای مقیاس‌پذیری افقی روی چند JVM استفاده می‌کنیم. می‌توانید این‌کارها را انجام دهید و از همان سیستم زمان اجرا (Runtime) استفاده کنید. اساساً یک بار کد را می‌نویسید [و همه‌جا آن را اجرا می‌کنید] و به هیچ کدام از این‌ها فکر نمی‌کنید. بنابراین اگر با مدل اکتور کار کنید برنامه‌ی خود را برای مقیاس‌پذیری عمودی یا افقی و گاهی هر دو، آماده کرده‌اید. چون این سطح از واگذاری مسئولیت‌ها (Indirection) را دارید، سیستم زمان اجرا می‌تواند در زمان مقیاس‌پذیری افقی یا عمودی به جای شما این تصمیم‌ها را بگیرد.
بنابراین شما می‌گویید توسعه‌دهندگان نخست باید چیزی را یاد بگیرند که ممکن است در ابتدا عجیب به نظر برسد اما پس از آن راحت می‌شوند و می‌توانند هر کاری را که نیاز دارند، انجام دهند.
بله، کم و بیش. فقط می‌خواهم بگویم که اکتورها در بسیاری از موارد ابزار فوق‌العاده‌ای برای انجام کار هستند. اما برخی مسائل هم هستند که اکتورها به هیچ وجه نمی‌توانند آن را حل کنند؛ شرایطی که در آن مدل اکتور در هم می‌شکند. برای مثال زمانی که به اجماع (Consensus) میان چند مؤلفه‌ی همروند یا توزیع‌شده نیاز دارید. اکتور کاملاً خلاف این مسئله را پیاده‌سازی می‌کند: هیچ چیز را به اشتراک نگذار (Share Nothing). روش متداولی که این مسئله را حل می‌کنند این است که همه چیز را در پایگاه‌داده ذخیره می‌کنند. در Erlang پایگاه‌داده‌ی Mnesia را دارید. اگر در محیط جاوا هستید می‌توانید از MySQL استفاده کنید. انجام این کار در شرایطی که صرفاً به یک اجماع نیاز دارید شدیداً پرهزینه است. وقتی فقط به توافق میان دو مؤلفه در یک فرایند (Process) نیاز دارید که در نخ‌های (Thread) متفاوتی اجرا می‌شوند، چرا باید هزینه‌ی IO و دیسک را بپردازید؟ برای حل شُسته‌رُفته‌تر و کارآمدتر این مسئله از چیزی به نام حافظه‌ی تراکنشی نرم‌افزاری (Software Transactional Memory) یا به اختصار STM استفاده می‌کنیم که به ما استفاده از حافظه به صورت تراکنشی را می‌دهد؛ همان تراکنشی که در [پایگاه‌داده‌هایی نظیر] اوراکل داریم. تراکنش‌ها را شروع کرده، تثیبت (Commit) و یا عقب‌گرد (Rollback) می‌کنیم؛ که خیلی سریع است. این، بخشی از مشکلاتی را حل می‌کند که با اکتورها نمی‌توانستید  حل کنید. علاوه بر این، انتزاع‌های دیگری روی [مفاهیم] هم‌روندی و محاسبات توزیع‌شده داریم که بخش دیگری از مشکلات را حل می‌کند. بنابراین Akka بیشتر یک جعبه‌ابزار است؛ چیزی را اجبار نمی‌کند بلکه مجموعه‌ای از ابزارهای مستقل و در عین حال منسجم را به شما می‌دهد که می‌توانند به خوبی در کنار هم استفاده شوند و ترکیبی را بسازند که مسئله‌ی شما را حل کند.
بیایید به این ابزارها، اجزای سازنده یا مؤلفه‌هانگاهی بیندازیم؛ با اکتور شروع کنیم. مدت زیادی پیش یک قسمت درباره‌ی Erlang داشتیم. ممکن است افراد درباره‌ی اکتورها و سایر زبان‌های برنامه‌نویسی و چارچوب‌های‌کاری که امکان برنامه‌نویسی بر اساس اکتورها را می‌دهند، اطلاعاتی داشته باشند. اما به نظرم هنوز هم یک مرور سریع در مورد آن، مفید است. بعد از آن می‌توانیم در مورد نحوه‌ی پیاده‌سازی آن در Akka صحبت کنیم.
بله، حتماً. می‌‌توانید به اکتورها به چشم اشیاء نگاه کنید. آن‌ها وضعیت (State) و رفتار (Behavior) را محفظه‌بندی (Encapsulate) می‌کنند. هرچند میزان محفظه‌بندی‌شان به نسبت کلاس‌ها در زبان‌های شئ‌گرا بیشتر است. به نوعی شئ‌گراتر از آن چیزی هستند که در جاوا و C++ و ... وجود دارد. آن‌ها چیزی تحت عنوان «هیچ چیز را به اشتراک نگذار» را پیاده‌سازی می‌کنند. به عبارتی، محفظه‌بندیِ وضعیت به شکلی که هیچ چیزی از آن [با دنیای بیرون] به اشتراگ گذاشته نمی‌شود. یعنی وضعیت داخلی یک اکتور نمی‌تواند توسط هیچ اکتور دیگری مشاهده شود یا مورد دسترسی قرار گیرد. بنابراین هیچ راهی به جز ارسال پیام به یک اکتور و درخواست از خودِ او برای تغییر وضعیت‌اش وجود ندارد. این دقیقاً نقطه‌ی مقابله آن چیزی است که در جاوا به آن عادت داریم و نام آن هم‌روندی با وضعیت مشترک است. در آن مدل هرچند اشیاء را به زیبایی در کلاس‌ها محفظه‌بندی می‌کنید و متغیر‌های خصوصی تعریف می‌کنید، اما  هیچ چیز را محفظه‌بندی نکرده‌اید. چون نخ‌ها از این قوانین تبعیت نمی‌کنند؛ هیچ کدام از مقررات محفظه‌بندی که در سیستم انواع‌تان (Type System) تعریف کرده‌اید را رعایت نمی‌کنند. این به آن معنی است که شما باید مقدار زیادی کارِ گِل انجام دهید و با اضافه کردن قفل‌ها در کدتان، امنیت و قطعیت را به وجود آورید. مدل اکتور سطح انتزاع را بالاتر می‌برد و مسئله را برای شما حل می‌کند. اکتورها ذاتاً برای نخ‌ها ایمن (Thread-Safe) هستند. هیچ راهی برای دیدن وضعیت و ایجاد شرایط رقابتی (Race Condition) و ... درون یک اکتور وجود ندارد. تمام کارِ گِل توسط سیستم زمان اجرا انجام می‌شود و شما به عنوان توسعه‌دهنده می‌توانید بر نوشتن منطق کسب و کار تمرکز کنید. هم‌روندی از کارِ گِل به گردشِ کار (Workflow) تبدیل می‌شود. در کار با  اکتورها به گردش کار فکر می‌کنید؛ این‌که پیام‌ها چطور در سیستم گردش پیدا می‌کنند. نه به این‌که چطور با استفاده از قفل‌ها از خود محافظت کنید.
پس مسئله‌ی اصلی این است که اکتورها فقط با تبادل پیام با یکدیگر ارتباط دارند. این تنها راهی است که با بیرون از خود و به طور خاص سایر اکتورها ارتباط دارند.
دقیقاً. تفاوت میان اکتورها و اشیاء این است که هر اکتور یک صندوق پیام دارد که نوعی از صف است. اگر من بخواهم با یک اکتور ارتباط داشته باشم باید به آن پیامی بفرستم. این پیام در صندوق آن اکتور قرار خواهد گرفت. زمانی که من به یک اکتور پیامی می‌فرستم، مجبور نیستم صبر کنم تا آن پیام پردازش شود. اگر به برنامه‌نویسی با JMS یا MQSeries آشنا باشید، مدل اکتور خیلی شبیه به آن است. پیام‌ها به صورت ناهمگام (Asynchronous) فرستاده می‌شوند. برخی‌ها به آن برنامه نویسی بدون Callstack هم می‌گویند. تنها کاری که انجام می‌شود این است که پیام در صندوق دریافت کننده قرار می‌گیرد و باز می‌گردد. ارسال پیام به اکتور مورد نظر بر عهده‌ی برنامه‌ریز (Scheduler) است.
از دیدگاه کسی که یک اکتور را می‌نویسد یک حلقه‌ی نامتناهی می‌نویسید که به صندوق پیام نگاه می‌کند و شاید اگر چیزی در آن نباشد، مسدود (Block) شود و وقتی چیزی در آن قرار گیرد دوباره نامسدود (Unblock) شود. درست است؟
بله، به نوعی درست است. تفاوت مهم این است که اکتورها هیچ‌وقت مسدود نمی‌شوند؛ فقط از لحاظ مفهومی مسدود می‌شوند؛ آن‌ها تنبل (Lazy) هستند؛ تا زمانی کسی به آن‌ها چیزی نگوید، کاری نمی‌کنند. مادامی که یک اکتور به صورت مفهومی مسدود شده‌است، به حالت تعلیق (Suspend) در می‌آید و هیچ منبعی مصرف نمی‌کند.
منظورم یک حلقه‌ی فعال نامتناهی نبود، منظورم این بود که اگر چیزی در صندوق نباشد، نخی که صاحب اکتور است به حالت تعلیق در می‌آید و در صورتی که پیامی در صندوق قرار بگیرد فعال می‌شود.
دقیقاً. این به شما اجازه می‌دهد سیستمی بنویسید که هزاران یا میلیون‌ها اکتور داشته باشد. چون اکتور‌ها فقط با حافظه محدود می‌شوند، این تنها منبعی است که مصرف می‌کنند.
اما هنوز هم باید حوضی از نخ‌ها (Thread Pool) داشته باشید که به صورت پویا آن را به اکتورها اختصاص می‌دهید. اندازه‌ی این حوض، تعداد اکتور‌های فعال هم‌روند را محدود می‌کند. درست است؟
بله، قطعاً.
هسته‌های بیشتر پردازنده، کارایی را افزایش می‌دهند چون تعداد بیشتری از اکتورها می‌توانند واقعاً به صورت موازی اجرا شوند.
بله، البته. این خیلی مهم است.
شما گفتید به جز از طریق پیام‌ها هیچ راهی نیست که اکتورها بتوانند با دنیای بیرون ارتباط برقرار کنند و هیچ وضعیت مشترکی ندارند. این به آن معنی است که پیام‌ها باید از لحاظ معنایی وابسته به مقدار باشند. یعنی داده‌ای که از یک اکتور به اکتور دیگری فرستاده می‌شود، به صورت مقداری (Pass By Value) و نه به صورت ارجاعی (Pass By Reference) منتقل شود. درست است؟
بله، درست است. این خیلی مهم است. این در Erlang آسان‌تر است. چون در Erlang هر اکتور Heap مخصوص به خود را دارد که کاملاً از Heap اکتورهای دیگر مجزا شده است. اما Akka به زبان اسکالا پیاده‌سازی شده است که روی JVM است. در JVM فقط یک Heap عظیم مشترک داریم. این مسئله مقداری از بار را بر دوش توسعه‌دهنده می‌گذارد. توسعه‌دهنده باید اطمینان حاصل کند که تمام پیام‌ها تغییرناپذیرند (Immutable). این همان چیزی است که شما گفتید، فقط می‌خواستم آن را توضیح دهم. این محدودیتی است که اجتناب از آن درJVM دشوار است.
اگر اکتورها را در ماشین‌های مجازی یا کامپیوترهای جداگانه پخش کرده باشید، واضح است که مفهوم نسخه‌برداری (Copy) یا انتقال با مقدار را دارید و حتی [اگر بخواهید] نمی‌توانید از آن اجتناب کنید. اما اگر به صورت محلی اجرا می‌شوید، سربار ایجاد می‌کند. آیا بهینه‌سازی زیرکانه‌ای وجود ندارد که حتی اگر مقادیر را به صورت ارجاعی انتقال دهیم برای‌مان مسئله‌ساز نشود؟ آهان، الان فهمیدم! چون تغییرناپذیر است در واقع انتقال با ارجاع را انجام می‌دهید اما کسی نمی‌تواند آن را تغییر دهد!
در واقع ما هیچ کاری انجام نمی‌دهیم. JVM تضمین می‌دهد که این بهینه‌سازی را برای ما انجام می‌دهد. این یکی از دلایلی است که به طور کلی، پیاده‌سازی اکتور‌ها روی JVM -اگر به درستی انجام شود- به راحتی از لحاظ کارایی نسبت به اکتور‌های Erlang برتری پیدا می‌کند. احتمالاً به خاطر گفتن این مورد حمله قرار می‌گیریم چون همواره می‌توان خرده محک‌هایی (Microbechmarking) ساخت که آنچه شما می‌خواهید را اثبات کند. اما به نظرم این مزیتی است که ما داریم. بار بیشتری بر توسعه‌دهنده دارد اما کارایی به مراتب بیشتری خواهید داشت.
من متوجه شده‌ام که یک تفاوت میان اکتورهای Erlang و Akka این است که انتقال پیام‌ها به صورت ارجاعی است و شما از اشیاء مقداری (Value Objects) استفاده می‌کنید تا مطمئن شوید وضعیت تغییرپذیری را به اشتراک نمی‌گذارید. آیا تفاوت مهم دیگری میان Erlang و Akka وجود دارد؟
بله. تفاوت‌های نحوی (Syntax) هم هست. افراد زیادی هستند که از Erlang می‌آیند و از Akka استفاده می‌کنند و درواقع حس می‌کنند در خانه‌ی خودشان هستند. چون ما تلاش کرده‌ایم بسیاری از همان مفاهیم را حفظ کنیم. بنابراین اگر از Erlang بیاید، نباید خیلی شگفت‌زده شوید. Erlang از اوایل دهه‌ی ۸۰ از اکتورها استفاده می‌کند و به نوعی استاندارد بالفعل (De Facto) در پیاده‌سازی مدل‌های همروندی بر اساس اکتور است. ما احساس می‌کردیم که نمی‌خواهیم بیش از حد ضرورت از آن فاصله بگیریم. شاید زمینه‌هایی باشد که ما مسیر متفاوتی انتخاب کرده باشیم، اما در بیشتر موارد این کار را نکرده‌ایم. بزرگ‌ترین تفاوت در [سیستم] زمان اجراست. این‌که JVM در مقایسه با Erlang چطور رفتار می‌کند.
این جالب است. من همیشه فکر می‌کردم یکی از دلایلی که Erlang تا این حد عالی، مقیاس‌پذیر (Scalable)، و باحال است همین است؛ به خاطر سیستم زمان اجرایش است. همیشه می‌گفتم Erlang بیشتر یک برنامه، یا چارچوب‌کاری است تا یک زبان برنامه‌نویسی.
همین‌طور است. Erlang فوق‌العاده‌ است. این خیلی وابسته به مورد کاربرد شما دارد. Erlang یک زبان با انواع پویا (Dynamically Typed) است. از سوی دیگر تجربه‌ی من در استفاده از هر دوی این‌ها -هر چند که بیشتر عمرم را در JVM گذرانده‌ام- این است که برای نوشتن یک برنامه با کارایی بالا و تأخیر پایین تقریباً هیچ چیز با JVM رقابت نمی‌کند چنانچه از آن به درستی استفاده کنید و مسائل را پیچیده نکنید. بنابراین JVM در بهینه‌سازی‌ها بسیار خوب عمل می‌کند. من نمی‌خواهم از چیز دیگری استفاده کنم.
در اسکالا هم اکتورها وجود دارند. در واقع جزئی از سیستم زمان اجرای آن یا کتابخانه‌ی استاندارد آن هستند. چرا از آن‌ها استفاده نکنیم؟ تفاوت اکتورهای شما با اسکالا چیست؟
در دور اول Akka از اکتورهای کتابخانه‌های اسکالا استفاده می‌کردم. اما بعد از آن‌که به مشکلاتی با آن‌ها بر خوردم، از آن‌ها فاصله گرفتم و از اکتورهای خودم استفاده کردم. اول، مشکلات کارایی و توان عملیاتی (Throughput) داشتیم. بعداً هم نشتی‌هایی در حافظه (Memory Leak) داشتیم. بنابراین مجبور شدم اکتورهای خودم را بنویسم. علاوه بر این می‌خواستم پیاده‌سازی آشکارتری از لحاظ قابلیت پیکربندی داشته باشم. تلاش کرده‌ایم همه چیز را آشکار کنیم تا بتوانید تنظیم‌کاری (Tune) کنید. برنامه‌ریز (Scheduler) متفاوتی داریم که می‌توانند در موارد کاربرد متفاوت، تفاوت‌های شگرفی داشته باشند؛ می‌توانید آن‌ها را تعویض کنید. فکر می‌کنم از اکتورهای اسکالا ایده گرفتیم و محدویت‌های آن را برطرف کردیم. در حال حاضر تلاش می‌کنیم کتابخانه‌ی اکتورهای اسکالا را با اکتورهای Akka جایگزین کنیم. اما توسعه‌دهندگان اسکالا را رها نمی‌کنیم، چون برخی ویژگی‌های اکتورهای اسکالا که در اکتورهای Akka نیستند را از نو پیاده‌سازی خواهیم کرد؛ تلاش می‌کنیم نقاط قوت هر یک را حفظ کنیم. احتمالاً در نسخه‌ی 2.10 اسکالا که حدود یک سال دیگر منتشر می‌شود، رخ خواهد داد.
چیزی که هیچ وقت نفهمیدم این است: در برنامه‌نویسی همروند سه موضوع مهم وجود دارد. یکی اکتورها هستند؛ دیگری حافظه‌های تراکنشی نرم‌افزاری (STM) است که به زودی در مورد آن صحبت می‌کنیم؛ سومی برنامه‌نویسی تابعی است. من درک می‌کنم که چرا برنامه‌نویسی تابعی مفید است؛ هیچ اثر جانبی‌ای ندارید و ... مفاهیم مقداری و ... که همه‌اش عالی است. توابع و اکتورها چطور با هم، جور می‌شوند؟ یا این‌که با هم، جور در نمی‌آیند و این یک تصادف است که اسکالا به عنوان یک زبان شئ‌گرای تابعی دارای اکتورها است. آیا داشتن انتزاعات تابعی در کنار اکتورها فایده‌ای دارد؟
این سؤال خوب و هوشمندانه‌ای است. جواب کوتاه این است که مشترکات زیادی وجود ندارد. اما جواب کمی طولانی‌تر این است که من معمولاً هر دوی آن‌ها را در کنار هم استفاده می‌کنم. اکتورها را درشت‌دانه‌تر به کار می‌برم تا مؤلفه‌ها و سرویس‌های بیشتری را پیاده‌سازی کنم و داخل اکتورها از برنامه‌نویسی تابعی استفاده می‌کنم.
پس شما می‌گویید اگر از برنامه‌نویسی تابعی، درون اکتورها استفاده کنیم، این برنامه‌های تابعی دیگر همروند نیستند، چون واحد همروندی شما، اکتورها هستند. بنابراین از برنامه‌نویسی تابعی استفاده می‌کنید چون مختصرتر و زیبا‌تر است و نه به خاطر همروندی.
بله، دقیقاً. اما عامل‌هایی (Agent) داریم که از منظر تابعی به اکتورها می‌نگرند. درباره‌ی آن‌ها توضیح خواهم داد اما نخست می‌خواهم علت اضافه کردن آن‌ها را توضیح دهم. ساختن اکتورها کمی‌سخت است، چون شئ‌گرا هستند. شکل معمول انتزاع‌سازی و استفاده مجدد در شئ‌گرایی از طریق ارث‌بری است. معمولاً به این شکل اکتورها را گسترش داده، می‌سازید و به کار می‌گیرید. اما در دنیای تابعی این را نمی‌خواهید، ترکیب تابعی می‌خواهید. به همین علت عامل‌ها را اضافه کردیم. عامل چیزی است که ما آن را اختراع نکردیم و از زبان Clojure می‌آید و روش شسته و رفته‌ای برای استفاده از سبک اکتور از منظر تابعی است. [در مقابل]، صحبت کردیم که اکتورها وضعیت و رفتار را محفظه‌بندی می‌کنند، و این‌که فقط پیام‌های تغییرناپذیر به سایر اکتورها می‌فرستند. بنابراین اساساً یک وضعیتِ احمق را به صورت ناهمگام به رفتار می‌فرستید، چون رفتار، درون اکتورها قرار دارد.
درست است. اساساً مثل مؤلفه‌ها است. از نظر واسط رویه‌ای، ناهمگام است اما رفتار تماماً داخل مؤلفه یا همان اکتور است و به آن داده‌ی خالص می‌فرستید.
دقیقاً. آن‌ها این را برعکس کرده‌اند. عامل در واقع یک شیار حافظه (Memory Slot) است که می‌توانید چیزی در آن قرار دهید؛ یک سطل (Bucket). می‌توانید یک نگاشت (Map)، یا بردار (Vector) و یا یک عدد صحیح در آن قرار دهید. یک عامل به شما امکان می‌دهد که به جای اینکه یک نگه‌دارهنده‌ی داده احمق یا یک پیام تغییرناپذیر را به آن ارسال کنید، در عوض، یک تابع را به صورت ناهمگام به آن بفرستید و آن را به صورت تجزیه‌ناپذیر (Atomic) به سطل اعمال کنید.
اما این فقط درون یک فرایند (Process) کار می‌کند، یا این‌که به صورت از راه دور (Remote) هم قابل انجام است؟
در حال حاضر عامل‌های Akka درون فرایندی هستند. (در صدای اصلی، در اینجا گوینده از واژه اکتور استفاده می‌کند اما به نظر می‌رسد یک اشتباه لفظی است -مترجم) افراد خیلی این را از ما نخواسته‌اند. اما چیزی جلوی ما را نگرفته که این کار را انجام دهیم چون آن‌ها خودشان در داخل با اکتور نوشته شده‌اند و ما اکتورهای از راه‌دور (Remote) هم داریم.
ایده این است که به جای این‌که وضعیت را به رفتار بفرستیم، رفتار را به وضعیت بفرستیم. اکنون که تابع را ارسال می‌کنید، می‌توانید تابع را قبل از ارسال به هر شکلی که می‌خواهید ایجاد کنید. یعنی آن را متفاوت استفاده می‌کنیم. حتی ممکن است پیاده‌سازی آن بر اساس جایی که اجرا می‌شود متفاوت باشد. به این طریق می‌توان تبادل پیام ناهمگام اکتورها را از دید تابعی انجام داد.
بسیار خوب. آیا اشتباه می‌کنم یا این ما را به سمت حافظه‌ی تراکنشی نرم‌افزاری هدایت می‌کند؟ چون فکر می‌کنم پیاده‌سازی حافظه‌ی تراکنشی نرم‌افزاری در Clojure، یا حداقل یکی از سازوکارهای آن، همین عامل‌ها باشند که گفتید؛ آن چیزی که دسترسی به وضعیت مشترک را کنترل و حفاظت می‌کند. توابع را به آن می‌فرستید و این توابع از طریق صندوق پیام، هماهنگ‌شده و اعمال می‌شوند. درست است؟
بله. یک چیز منجر به دیگری می‌شود. این عامل‌ها در Akka آگاه به تراکنش هستند، در Clojure هم همین‌طور است. اگر تابع به یک اکتور اعمال شود، به زمینه (Context) نگاه می‌کند تا ببیند آیا تراکنشی در حال اجراست یا خیر. اگر تراکنشی در حال اجرا باشد، به آن تراکنش ملحق می‌شود. یعنی اگر تراکنش تثبیت (Commit) نشود، تابع روی عامل اعمال نخواهد شد. بنابراین تا زمانی که تراکنش با موفقیت تثبیت نشود، میان‌گیرها (Buffer) یا توابع را نگه‌می‌دارد. این به آن معنی است که می‌توانید آن‌ها را ترکیب کنید. می‌توانید تعداد زیادی عامل را به یک تراکنش ملحق کنید و می‌دانید یا تمام آن‌ها با موفقیت اعمال می‌شوند، یا هیچ‌یک اعمال نمی‌شود. همچنین عامل‌ها مشابه به نحوه استفاده از STM در Akka هستند. چون در Akka برای STM از ارجاعات مدیریت‌شده استفاده می‌شود. آن‌ها هم شیارهای حافظه هستند. اما تفاوت میان ارجاعات مدیریت شده و عامل‌هایی که به روش تراکنشی استفاده می‌شوند این است که عامل‌ها ناهمگام هستند، اما ارجاعات مدیریت شده نیستند.
بله، متوجه شدم. نمی‌خواهم شما را مجبور به خواندن کد کرده و این مصاحبه را به برنامه‌نویسی صوتی تبدیل کنم :-) اما ممکن است به ما بگویید واسط برنامه‌نویسیِ اکتورها و عامل‌ها به لحاظ فنی چه شکلی هستند؟ یک تصویر کلی.
حتماً. با اکتورها شروع می‌کنم. اول این‌که Akka واسط اسکالایی و جاوایی دارد. بنابراین می‌توانید تمام چیزهایی که مطرح کردیم: عامل‌ها، STM، اکتورها و ... را از طریق جاوا هم استفاده کنید.
احتمالاً فقط به ده برابر کد بیشتر احتیاج داریم :-)
:-) بله، گاهی اوقات، البته نه همیشه. ما سعی کردیم حجم آن را کم کنیم. اما الان می‌خواهم در مورد واسط اسکالا صحبت کنم. یک trait به نام Actor داریم که برای پیاده‌سازی یک اکتور استفاده می‌شود. یک trait چیزی مثل یک interface دارای پیاده‌سازی [در جاوا ۸] است، بنابراین می‌توانید آن را با هر کلاسی ترکیب کنید. سپس تنها کافی است تابع Receive را پیاده‌سازی کنید. تابع Receive، [منطق] رسیدگی به پیام را برای یک اکتور، پیاده‌سازی می‌کند. در اسکالا ما از تطبیق الگو (Pattern Match) برای مطابقت دادن پیام‌های ورودی استفاده می‌کنیم. تطبیق، روی هر پیامِ درون صندوق انجام شده و سپس کد رسیدگی به آن پیام اجرا می‌شود. تمام کد و وضعیتی که درون یک اکتور -تحت عنوان متغیرهای عضو- دارید، کاملاً در مقابل نخ‌ها ایمن (Thread-Safe) هستند؛ نیازی به متغیرهای volatile یا ارجاعات تجزیه‌ناپذیر (Atomic Reference) و اینجور چیزها ندارید.
در مقابل، عامل‌ها کد کم‌تری دارند؛ چون فقط یک شیار حافظه هستند. اگر بخواهید یک عامل بنویسید، فقط می‌نویسید agent و یک پرانتز جلویش باز می‌کنید و یک مقدار می‌دهید. [مقدار آن] می‌تواند یک نگاشت، یا هر چیز دیگری باشد. حتی می‌تواند مقدار نباشد، بلکه یک نوع باشد. در این صورت مثلاً می‌گویید agent  داخل کروشه Int. بعد تابعی با عنوان send که می‌توانید تابعی را به آن بفرستید. STM خیلی شبیه به این است. می‌نویسید ref و بعد پارامتر را می‌آورید تا آن مقدار را دربربگیرد (Wrap). و بعد این مقدار توسط STM به طور کاملاً تراکنشی مدیریت می‌شود. ساختمان‌داده‌های تراکنشی هم داریم؛ شبیه به ساختمان‌داده‌های استاندارد اسکالا هستند اما در پشت صحنه، تراکنشی هستند. بنابراین تقریباً رد همه لوله‌کشی‌های قابل‌رؤیت را پاک می‌کند.
اولین باری که با حافظه‌ی تراکنشی برخورد کردم، کلمه‌ی کلیدی atomic را می‌دیدم که بعد از آن میان آکولادها کارهایی انجام می‌شد. اما در Clojure و همین‌طور Akka، از روش صریح‌تری برای این کار استفاده می‌کنند. آن‌ها محتوای حافظه‌ای را که باید تراکنشی شود را در ارجاعاتی قرار می‌دهند و سپس به جای این‌که مستقیماً با داده‌ها کارکنید، باید با این ارجاعات کارکنید. آیا این فقط برای زیبایی نوشتاری است یا تفاوتی هست که من نمی‌فهمم؟
من یک بدبینی تاریخی نسبت به STM دارم. [پیاده‌سازی‌های] اولیه STM، کارهای جادویی زیادی از قبیل بازنویسی بایت‌کد انجام می‌دادند. درواقع به کاربر اجازه می‌دادند که وضعیت را به اَشکال عجیب و غریبی دستکاری کند، اما [ناگهان] حافظه‌ی تراکنشی همه‌چیز را درست کرده و کد به درستی کار می‌کرد. من به این اعتقادی ندارم. به نظرم وضوح و زیاده‌گویی (Verbosity) در کد، اگر بیش از حد نباشد، چیز خوبی است. چون هم می‌دانید چه وقت هزینه‌ی کارایی را می‌دهید، و هم می‌دانید چه وقت حافظه‌ی تراکنشی کد شما را تحت تأثیر قرار می‌دهد. همچنین می‌توانید خیلی ریزدانه، در مورد این‌که کدام وضعیت لازم است تراکنشی شود و کدام وضعیت لازم نیست تراکنشی شود، تصمیم بگیرید. من دوست دارم واضح باشم. مدل اکتور روشی واضح برای همروندی است؛ تلاشی برای این‌ نمی‌کند که به دروغ وانمود کند که حافظه‌ی مشترک دارد: چنین چیزی نداریم. STM هم به همین ترتیب است. آنجا هم می‌خواهم واضح باشم.
فکر می‌کنم این یک گرایش عمومی باشد. در ابتدای به وجود آمدن شئ‌گرایی، همه چیز شئ بود. تلاش می‌شد همه چیز شبیه به شئ محلی باشد. همچنین اگر دسترسی به اشیاء، مثل COBOL از راه دور بود یا مثل RMI در جاوا بود، سیستم‌هایی مستقل ماناسازی (Persistence) را داشتید که به صورت خودکار اشیاء را مانا می‌کردند و ... البته ویژگی‌های غیرعملیاتی داده‌های دور یا مانا شده، می‌توانند متفاوت باشند. فکر می‌کنم الان گرایش به این باشد که این چیزها را واضح کنند: آن را پنهان نکنند. می‌توانید این را در SOA، REST و همین‌طور در طرز پیاده‌سازی شما از حافظه‌ی تراکنشی ببینیم. فکر می‌کنم این یک گرایش عمومی باشد، درست است؟
فکر می‌کنم یک گرایش سالم است. برخی چیزها نباید پنهان شوند. همروندی یک مسئله است و پنهان کردن آن ساده‌تر است. اما پنهان کردن شبکه تقریباً غیر ممکن است. اگر بخواهید شبکه را پنهان کنید، همواره دروغ خواهید گفت: گاهی اوقات بهتر دروغ می‌گویید و گاهی اوقات بدتر :-) اما همواره دروغ می‌گویید؛ این یک انتزاع خیلی خیلی نشت‌دار است. در اکثر پیاده‌سازی‌هایی که دیده‌ام و تلاش می‌کنند وجود شبکه را پنهان کنند، این پنهان‌سازی به مراتب نشت می‌کند.
اکتورها در Akka قابل دسترسی از راه دور هستند، اما نحو (Syntax) آن‌ها تغییر نمی‌کند و این مسئله پنهان شده است. درست است؟
بله. این یکی از مسائل کلیدی بود که می‌خواستیم به آن دست بیابیم. شما اکتورها را به عنوان چیزهای زنده یا مؤلفه‌های فعال می‌نویسید. نباید مهم باشد که در محیط تک‌نخی یا چندنخی، یا در یک محیط با چند JVM اجرا می‌شوند. ما به جای این‌که تلاش کنیم سطح انتزاع را تا حدی بالا ببریم که همه چیز محلی به نظر برسد، خلاف این کار را می‌کنیم؛ می‌گوییم همه چیز آن‌طوری است که باید در [محیط] توزیع‌شده باشد. بنابراین با وجود این‌که درون یک فرایند هستیم، از تبادل پیام استفاده می‌کنیم. این به ما اجازه می‌دهد بدون آن‌که به دروغ بگوییم حافظه‌ی مشترک داریم، برنامه را در چند JVM، یا مرکز داده توسعه دهیم. بنابراین پیاده‌سازی توزیع‌شده‌ی اکتورها کاملاً  مستقل از مکان (Location Transparent) است. زمانی که یک اکتور می‌سازید، نمونه یا ارجاع مستقیمی به آن دریافت نمی‌کنید، در عوض یک ارجاع غیر مستقیم به آن خواهید داشت (اشاره‌گری به آن می‌گیرید). در Erlang، مفهوم PID را دارید که شناسه‌ی فرایند است. در Akka به آن ActorRef می‌گوییم که همان مفهوم است. می‌توان درون فرایند از آن برای دسترسی به اکتورهای محلی، یا برای دسترسی به اکتورهای دور استفاده کرد. لازم نیست کاربر این را بداند. او پیامش را ارسال می‌کند.
آیا این‌ها نماینده‌ای (Proxy) برای واسط‌های تعریف‌شده هستند که فقط به پیام‌های شما رسیدگی می‌کنند؟ و یا واسط‌های اکتورها از این جهت، عمومی هستند؟ یعنی هر پیامی را می‌پذیرند و اگر آن را نشناسند، آن را دور می‌ریزند؟
این سؤال خوبی است. این مسئله‌ی دو نوع [اکتورهای] Akka را پیش می‌کشد. اکتورهای سبک اولیه که نوع آن‌ها پویا است (Dynamically Typed). هر چند اسکالا یک زبان دارای انواع داده‌ای ایستا (Statically Typed) است، روشی که اکتورهای اولیه را پیاده‌سازی کردیم باعث می‌شود که آن‌ها نوعی پویا داشته باشند. این به آن معنی است که می‌توانید هر پیامی را به یک اکتور بفرستید و بسته به نوعی که داشته باشد، ارسال می‌شود. برای این کار از قابلیت تطبیق الگوی اسکالا استفاده می‌کنیم تا کمی هوشمندانه‌تر عمل کنیم. بنابراین می‌توانید پیام‌هایی به یک اکتور بفرستید که نمی‌تواند به آن پاسخ دهد. این چیزی است که باید به آن رسیدگی کنید.
از سوی دیگر می‌توانید پیاده‌سازی اکتورها را عوض کنید. بنابراین مراحل متفاوتی در چرخه‌ی حیات یک اکتور وجود دارد. می‌توانیم به آن به چشم یک ماشین حالت نگاه کنیم. وقتی که یک اکتور را راه‌اندازی می‌کنید، ممکن است بتواند به یک یا چند نوع از پیام‌ها پاسخ دهد. می‌توانید پیاده‌سازی را عوض کرده و انواع دیگری از پیام‌ها را پاسخ دهید. یعنی می‌توانید واسط برنامه‌نویسی و پیام‌هایی را که می‌تواند پاسخ دهد، به صورت پویا تغییر دهید.
البته این، واسط برنامه‌نویسی را تغییر نمی‌دهد. این‌که یک اکتور در درون خود به چه پیام‌هایی می‌تواند پاسخ دهد برای بیرون قابل مشاهده نیست. درست است؟
بله درست است. این یکی از چیزهایی بود که در Erlang به قدرت آن پی بردم. چون Erlang یک زبان دارای انواع داده‌ای پویاست. ما موفق شدیم به نحوی آن را در اسکالا تعبیه کنیم که به نظر طبیعی برسد. به  یک اکتور می‌گویید become و پیاده‌سازی آن را می‌دهید. یعنی می‌توانید بگویید می‌خواهم به چیز دیگری تبدیل شوم. از بیرون هم می‌توانید پیاده‌سازی یک اکتور را با استفاده از یک پیام درجا تغییر دهید. این، کاربرد کم‌تری دارد و کمی خطرناک‌تر است اما گاهی می‌تواند مفید باشد. من خیلی اوقات از become برای تعریف مجدد یک اکتور توسط خودش استفاده می‌کنم.
این در واقع الگوی پل (Bridge) است (اشاره به الگوی پل در کتاب الگوهای طراحی -مترجم)، پیاده‌سازی‌های متفاوتی برای یک چیز دارید.
بله.
اکتورهای دارای نوع هم وجود دارند. آیا آن‌ها واسط برنامه‌نویسی دارای نوع سختی (Strong Typed) دارند؟
بله، دارند. گاهی اوقات این خیلی مفید است. به شما اجازه می‌دهیم اکتورها را از طریق یک واسط با توابع استاندارد (واسط‌های جاوا یا ویژ‌گی‌های اسکالا) تعریف کرده و از اشیاء POJO عادی جاوا و اسکالا برای پیاده‌سازی آن استفاده کنید. یعنی اگر هر کلاسی که باشد را با کلمه new بسازید به یک شئ استاندارد تبدیل شود اما اگر در عوض، آن را با Factoryای که داریم بسازید، چیزی که برمی‌گردانیم خیلی شبیه به الگوی شئ فعال است. و بعد هر گاه تابعی را از آن واسط فراخوانی می‌کنید، پیامی ساخته و آرگومان‌هایش را در آن می‌پیچیم. سپس آن را به صورت ناهمگام در یک صف قرار می‌دهیم تا توسط شئ POJO جاوایی داخلی پردازش شود.
اما زمانی که به دست شئ POJO می‌رسد، به فراخوانی تابع تبدیل می‌شود؟
بله.
بنابراین یک سطح از واگذاری مسئولیت (Indirection) وجود دارد و در واقع میان واسط و پیاده‌سازی آن، یک صف قرار می‌گیرد.
بله. سپس تمامی توابع بدون خروجی را به شکل ارسال و فراموشی (Fire and Forget) می‌نویسیم و توابعی را که خروجی دارند را با پیامی بازنویسی می‌کنیم که چیزی را در Future بر می‌گرداند (اشاره به الگوی طراحی Future-مترجم). بنابراین می‌توانید از هر دو نوع ارسال پیام، ارسال و فراموشی و درخواست و پاسخ، استفاده کنید.
با استثناء‌ها (Exception) چه می‌کنید؟
اطمینان حاصل می‌کنیم که مطابق با انتظار از دریافت کننده‌ی پیام به فراخواننده‌ی آن ارسال می‌شوند.
در نماینده (Proxy) پرتاب می‌شوند؟
بله.
به صورت ناهمگام؟! نمی‌تواند این‌طور باشد.
خیر. هر زمان که در نخ دریافت کننده استثنائی رخ دهد، نوعی استاندارد از تبادل پیام را استفاده می‌کنیم. پاسخ را به نخ فراخواننده ارسال می‌کنیم و در آن‌جا استثناء را پرتاب می‌کنیم.
بسیار خوب. این در مورد Future چطور کار می‌کند؟ آن‌ها اشیائی هستند که می‌گیرید و از کلاینت می‌خواهید هر زمان که آماده بود مقدار آن را بخواند، چه در آن لحظه مقدار وجود داشته باشد، و چه خیر. بنابراین نوعی از سبک واکشی (Poll) است. کی و چطور استثناء را پرتاب می‌کنید؟ منظورم این است که کلاینت ممکن است کاملاً درگیر کار دیگری باشد.
سؤال خوبی است. دوست داشتم اگر می‌شد، مقداری کد بنویسم :-) اساساً سه راه برای انجام این کار داریم. مثلاً اگر فقط یک رشته را برمی‌گردانید (تابعی که یک رشته می‌گیرد و یک رشته برمی‌گرداند) ما Futureرا در معرض کاربر نهایی قرار نی‌دهیم. بلکه در پیاده‌سازی Future را می‌گیریم و تا زمانی که timeout شود، استثنائی رخ دهد، و یا مقدار خروجی دریافت شود، صبر می‌کنیم.
بنابراین از نگاه کلاینت، مثل یک فراخوانی مسدود شونده (Blocking) است؟
بله، دقیقاً.
حالا فهمیدم اسثناء چطور پرتاب می‌شود.
اما علاوه بر این، به شما اجازه می‌دهیم در واسط، تابعی بسازید که یک Future را در Akka برمی‌گرداند و این کنترل را به دست شما می‌دهد. این تابع می‌تواند بلافاصله برگردد و شما تصمیم می‌گیرید که فراخوانی مسدود شونده را انجام دهید و یا درخواست onCompleteCallback ثبت کنید و بررسی کنید که تابع با استثناء به پایان رسید یا مقداری برگرداند.
اگر از یک نماینده (Proxy) با فراخوانی مسدود شونده در سمت کلاینت استفاده کنید، مزایای مدل اکتور و ناهمگامی فقط در سمت سرور نمایان می‌شود. سرور از کلاینت مقیاس‌پذیرتر می‌شود. کلاینت تعداد محدودی نخ دارد و اگر تمامی آن‌ها مسدود شوند، از بد اقبالی اوست.
بله. ما همین سبک درخواست-پاسخ (Request-Reply) در توسعه را برای اکتورهای فاقد نوع هم داریم. این به ما امکان می‌دهد که پیامی را بفرستیم و سپس پاسخ آن را از طریق یک Future دریافت کنیم. ما تلاش می‌کنیم به افراد بگوییم که از فراخوانی‌های مسدود شونده روی Furureها حتی‌الامکان خودداری کنند. در محک‌های (Benchmark) انجام شده نشان داده شده است که توان عملیاتی (Throughput) می‌تواند تا یک سوم به نسبت حالت نامسدود شونده کاهش پیدا کند.
بله چون باز دارید از یک چیز همگام مسدود شونده استفاده می‌کنید.
بله. چون بر روی نخ‌ها نشسته‌اید و اگر این کار را برای چند هزار فراخوانی هم‌زمان انجام دهید این منابع را مصرف می‌کنید و به محدودیت تعداد نخ‌ها برمی‌خورید. چیزی که در Akka 1.1 اضافه کرده‌ایم یک واسط برنامه‌نویسی کاملاً نامسدود شونده برای Futureها است تا بتوانید تعدادی از آن‌ها را گرفته و با آن کار کنید. حتی آن‌ها را ترکیب کنید، بدون این‌که مسدود شوید. سپس با توجه به مقادیری که هنوز آماده نشده‌اند [تصمیم بگیرید که] محاسباتی را انجام دهید و انسداد را حتی‌الامکان به تأخیر بیاندازید. همچنین onCompleteCallback را اضافه کردیم که به شما اجازه می‌دهد تابعی را ثبت کنید تا وقتی مقدار مورد نظر دریافت شد، آگاه شوید. اگر از این روش استفاده کنید، هیچ انسدادی وجود نخواهد داشت.
اما این به مقداری جادوی اسکالا احتیاج دارد، درست است؟ نمی‌توانید به راحتی این را در جاوا انجام دهید. حداقل با یک نحو (Syntax) قابل قبول نمی‌شود.
آنجا نیاز به واسط‌های زشت جاوایی دارید: می‌گویید new Function و سپس تابع run آن را پیاده‌سازی می‌کنید. یک کم کد بیشتر می‌خواهد (این مصاحبه در سال 2011 و قبل از انتشار جاوا 8 ضبط شده است. در جاوا 8 امکان تعریف توابع لامدا به جاوا اضافه شد که این مشکل را برطرف می‌کند-مترجم).
چرا اسکالا را انتخاب کردید؟ آیا فقط به این‌خاطر بود که زبان روز است؟ یا فقط به آن علاقه‌مند بودید؟ آیا اسکالا ویژگی‌های خاصی دارد که برای Akka مناسب است؟ منظورم این است که می‌توانید هر چیزی را با نحو قبیح جاوا پیاده‌سازی کنید، اما اسکالا چقدر در انجام کاری که Akka انجام می‌دهد اهمیت دارد؟
فکر می‌کنم اصلی‌ترین چیزی که داشت این بود که بتوانیم بستر Akka را خیلی زودتر به اجرا برسانیم. استفاده از تغییرناپذیری (Immutability) در بطن کار و استفاده از ساختمان‌داده‌های عالی اسکالا [کمک زیادی کرد]. من خودم سامانه‌های مشابهی را داشته‌ام: کارهایی که در Terracotta داشتم، میان‌افزارهای مقیاس‌پذیری که در BEA بود، WebLogic و اینجور چیزها. احساس می‌کنم اعتماد به نفس بیشتری در کدهایی که به زبان اسکالا می‌نویسم دارم. خطاها کم‌تر است؛ کد کم‌تری برای نوشتن، خواندن، نگه‌داری و فهمیدن است. سطح انتزاع را بالا می‌برد تا به جای این‌که به کارِ گِل بپردازید، بتوانید بیشتر به ارزش پیاده‌سازی طبیعی فکر کنید. علاوه بر این Akka به زیبایی با اسکالا در رویکرد تغییرناپذیری و هم‌روندی تطبیق پیدا می‌کند. همچنین فکر می‌کنم با صرف وقت کافی می‌توانستم همین کد را با همین کارایی در جاوا هم بنویسم. جالب اینجاست که اسکالا همان کارایی را تقریباً با همان بایت کد به شما می‌دهد. در واقع زبان دیگری که روی JVM اجرا شود و این امکان را به شما بدهد وجود ندارد. اکثر آن‌ها دارای انواع داده‌ای پویا هستند که قابل قبول نیست. برنامه‌های زیادی مثل برنامه‌های وب هستند که نسبت به کارایی حساس نیستند، اما من نمی‌توانم از چنین زبان‌هایی برای نوشتن میان‌افزار استفاده کنم. اما می‌توانم از اسکالا برای نوشتن میان‌افزار استفاده کنم که کاملاً جای جاوا را پر می‌کند و این خیلی عالی است.
بیایید کمی در مورد تحمل شکست (Fault Tolerance) صحبت کنیم. پیش از این اشاره کردید که از سبک «بگذار خراب شود» در Erlang استفاده کردید. این به آن معنی است یک اکتور، بر دیگری نظارت می‌کند. اگر یکی به علت خرابی بمیرد، یکی دیگر به جای آن راه‌اندازی می‌شود. این درست است؟ چرا این کار را می‌کنید؟
به طور خلاصه این به ما امکان می‌دهد سامانه‌ای بنویسیم که خودش را درمان می‌کند. می‌توانید نحوه‌ی پاسخگویی سامانه به شکست را اعلان کرده و پیکربندی کنید. اما در سبک سنتیِ رسیدگی به خطا در جاوا اولاً، یک وضعیت بحرانی دارید که یک خطا در وضعیت هسته‌ی کسب و کار، معمولاً سرتاسر برنامه را آلوده می‌کند. دوماً این‌که معمولاً با استفاده از try-catchها در همه‌جا به شدت تدافعی (Defensive) برنامه‌نویسی می‌کنید و این توهم را دارید که جلوی رخ دادن خطا را می‌گیرید. اما اگر با سامانه‌های دارای کارایی بالا و سامانه‌های توزیع شده سر و کار داشته باشید، می‌دانید که شکست غیرقابل انکار است؛ نمی‌توانید از آن جلوگیری کنید. چه بخواهید، چه نخواهید رخ خواهد داد. در این روش برنامه‌نویسی برای تحمل خطا، به جای این‌که تلاش کنید تدافعی برنامه بنویسید، شکست را در آغوش می‌گیرید و آن را به عنوان یک وضعیت طبیعی در چرخه‌ی حیات برنامه در نظر می‌گیرد. خرابی همان‌قدر طبیعی است که شروع به کار و ارسال موفق پیام‌ها طبیعی هستند. این به شما راهی برای فکر کردن به مسئله می‌دهد. مثلاً به شما امکان برنامه‌نویسی در سطح مدیریت شکست را می‌دهد که به سامانه کمک می‌کند خودش را ترمیم کند.
به نوعی شبیه به یک رسیدگی‌کننده‌ی سراسری استثناءهاست (Global Exception Handler). اگر اشتباهی رخ داد آن را از نو اجرا کن :-)
بله. شاید برای همه‌ی مسائل مناسب نباشد اما من در طیف وسیعی از مسائل و مشتریان، آن را به کار برده‌ام؛ موفقیت زیادی هم داشته‌ام. اساساً ایده این است که مؤلفه‌هایتان را به یک وضعیت پایدار برمی‌گردانید و ادامه می‌دهید. روشی که معمولاً به وسیله‌ی آن برنامه‌هایتان را سازمان‌دهی می‌کنید شبیه به یک پیاز است. وضعیت بحرانی را در داخلی‌ترین قسمت دارید. سپس لایه‌های دفاعی بعدی را دارید. درخواستی که از کاربر می‌آید معمولاً به خارجی‌ترین خط دفاعی می‌رسد. خیلی سخت است که یک خطا از بیرونی‌ترین لایه به داخلی‌ترین لایه-که حساس و ظریف است-منتشر شود. زمانی که برنامه می‌نویسم اگر از یک وضعیت حساس مراقبت می‌کنم که برایم اهمیت دارد و باید کاری انجام دهم، هیچ‌وقت آن کار را خودم انجام نمی‌دهم. همیشه یک اکتور می‌سازم و کار را به او می‌سپارم. اگر او بمیرد اشکالی ندارد چون من هستم. با اضافه کردن این سطح از واگذاری مسئولیت می‌توانم به شکل زیبایی از خودم مراقبت کنم. در عین حال همه چیز اعلانی (Declarative) می‌شود؛ یعنی قوانین برپا شدن را اعلان می‌کنم و سامانه خودش از پس آن بر می‌آید.
فکر می‌کنم تعریف این قوانین و روابط میان اکتورها-این‌که چه‌کسی از دیگری مراقبت کند و چه کسی دیگری را راه‌اندازی مجدد کند- نمی‌تواند غیر بدیهی باشد. منظورم این است که اگر در این‌جا اشتباهی رخ دهد، همه چیز به فنا می‌رود. چطور این را تست می‌کنید؟ چطور از آن مطمئن می‌شوید؟
این یکی از چیزهایی است که الان در تیم Akka به شدت روی آن کار می‌کنیم؛ ساختن ابزارهای جدید تست. مشکل، گسترده‌تر از تست کردن شکست مؤلفه‌هاست. این مسئله هم هست که معمولاً مؤلفه‌ها را در نخ‌های متفاوتی اجرا می‌کنید. بنابراین مسئله به سادگی به تست مؤلفه‌ها به شکل همروند، تبدیل می‌شود. ما با فراهم کردن یک توزیع‌کننده (Dispatcher) که شما رامجبور می‌کند همه‌چیز را در یک نخ ارسال کنید، تلاش کردیم به این کار کمک کنیم. در نتیجه ارتباطات به صورت ترتیبی خواهند بود که تست را خیلی راحت‌تر می‌کند. ابزارهای دیگری هم در مؤلفه‌ی تست Akka داریم که امکان تست کردن این دنیای هم‌روند را به شکلی قابل پیش‌بینی‌تر فراهم می‌کند. اما این قطعاً یک چالش است. فکر می‌کنم چالش آن از یک برنامه به سبک جاوا پراز try-catch کم‌تر نباشد. مسئله را به سطح دیگری می‌برد. آن را ساده نمی‌کند بلکه رویکرد دیگری به آن خواهید داشت.
فکر می‌کنم خوبی آن این است که مجموعه‌ی مشخصی از حدود و واسط‌ها دارید، که همان اکتورها هستند. بنابراین فراهم کردن عملکرد ردگیری -که به شما نمودار زمانی یا نوعی از لاگ که زمان رخ دادن عملیات را نشان می‌دهد- در مقایسه با اینکه بخواهید در سطوح دیگر کدهای پیاده‌سازی آن را انجام دهید، راحت‌تر است.
بله، قطعاً. چیز دیگری که به نظر ارزش مطرح کردن دارد این است که اگر می‌خواهید برنامه‌ای هم‌روند در جاوا بنویسید، معمولاً از یک ExecutorService و یک ThreadPool استفاده می‌کنید و توابع قابل فراخوانی را به آن ارسال می‌کنید تا کارها را انجام دهند. اگر یک نخ بمیرد، حتی اگر try-catch یا هر چیز دیگری که تلاش کند وضعیت را ترمیم کند داشته باشید، معمولاً stacktrace آن را تا بالاترین لایه‌ی ExecutorService خواهید دید. چون استثناء‌ها میان ‌نخ‌ها جابجا نمی‌شوند. هیچ راهی نیست که متوجه شویم نخ‌مان مرده است. اما شما این ارتباط و نظارت را دیده‌اید که به شما امکان می‌دهد سایر مؤلفه‌های هم‌روند را مانیتور کنید و آگا‌ه‌سازی‌هایی از خلال نخ‌ها دریافت کنید. این مسئله‌ای غیربدیهی در نوشتن کدهای هم‌روند است. من شخصاً به آن علاقه دارم. برای برطرف کردن آن در کدهای چندنخی استاندارد جاوا با مشکلات زیادی مواجه می‌شوید.
فکر می‌کنم مهمترین موارد مربوط به هسته‌ی Akka را پوشش دادیم.
بله، این طور فکر می‌کنم. فکر می‌کنم سه پایه اصلی، هم‌روندی، مقیاس‌پذیری و تحمل شکست هستند. فکر می‌کنم این‌ها اساس Akka هستند. تعدادی ماژول دیگر هم برای تعامل با دنیای خارج داریم؛ سرویس‌ها دیگر، ماژول‌های دیگر و ...
فکر می‌کنم باید خلاصه‌ای از این‌ها به ما بگویید. مثلاً می‌خواهم بدانم Spring Integration چیست؟ بعد از آن AMQP، OSGi و REST. صرفاً خلاصه‌ای از این‌ها به ما بگویید تا بدانیم که چطور آن‌ها را با دنیای فعلی ارتباط دهیم.
حتماً. همان‌طور که گفتید یک ماژول Spring داریم که با آن اکتورهای دارای نوع Akka را با Spring پکپارچه می‌کنیم. چون اکتورهای دارای نوع Akka در واقع Spring Bean هستند-یک پیاده‌سازی به همراه یک واسط دارند-کاملاً طبیعی است. یک زبان مختص حوزه (DSL) برای Spring داریم. یک فضای نام شخصی‌سازی‌شده در فایل XML متن برنامه (Application Context) که به شما اجازه می‌دهد سیم‌کشی‌ها[ی مربوط به تزریق وابستگی‌ها] را انجام دهید. سپس می‌توانید به سلسله‌مراتب‌ها و ساختن اکتورها از راه‌دور، تماماً از طریق Spring رسیدگی کنید. می‌توانید از روش استاندارد تزریق وابستگی‌ها در Spring برای تزریق چیزی در اکتورهایتان استفاده کنید. این خیلی خوب است. اگر به Google Guice علاقه‌مند باشید، مشابه‌اش را برای آن هم داریم. آن هم از اکتورهای دارای نوع استفاده می‌کند تا راهش را به دنیای Guice پیدا کند. یک ماژول هم برای AMQP داریم که AMQP را در قالب اکتورها انتزاع می‌دهد.
برای این‌که مطمئن باشیم مخاطب منظورمان را می‌داند بگویید AMQP چیست.
مخفف Advanced Message Queuing Protocol است. استانداردی است که تعدادی از سرمایه‌گذاران بانکی به رهبری JPMorgan آن را ساختند، چون فکر می‌کردند که تحت تسلط سرویس‌های تبادل پیام MQSeries هستند و دیگر نمی‌خواستند هزینه‌ی گواهی‌نامه‌ی آن را بپردازند. این استاندارد از آن پس رشد کرد. در ابتدا مشخصات خوبی داشت. در بازبینی‌های اخیر انتقادهای زیادی داشته‌اند چون پیچیده شده است. اما من هنوز فکر می‌کنم مشخصات تر و تمیزی است.
این چطور با JMS جور در می‌آید؟
اکثر کارگزارهای JMS شروع به پیاده‌سازی AMQP کرده‌اند. داریم در این موضوع به اجماع می‌رسیم.
بنابراین در لایه‌های زیرین از JMS به عنوان فناوری ترابری ارتباطات (Communication Transport) برای تبادل پیام میان اکتورها استفاده می‌کنید.
فکر می‌کنم در واقع برعکس باشد. چون AMQP یک استاندارد شبکه است؛ یک پروتکل باینری است. بنابراین در لایه‌ی شبکه است. احتمالاً می‌شود از واسط برنامه‌نویسی JMS استفاده کرد اما در زیر، همه چیز AMQP است.
اگر JMS را کنار بگذاریم، فقط با AMQP صحبت کردن به این معنی است که اکتورها همان هستند که بودند اما آن‌ها را به نحوی سیم‌کشی می‌کنید که از طریق AMQP پیام‌ها را دریافت کنند.
بله، دقیقاً. پروتکل ارتباط در حال حاضر AMQP است (در مقابلِ پروتکل مبتنی بر TCP در Akka).
بله، متوجه شدم. آیا OSGi هم داستانی دارد؟
ما تلاشی کردیم تا همه چیز در Akka را دارای قابلیت OSGi کنیم، اما بیش از حد دردناک بود و مجبور شدیم به عقب برگردیم. در حال حاضر هسته‌ی Akka-فایل akka-actor.jar که در آن تمام اکتورها را داریم-دارای قابلیت OSGi است. اگر فقط از آن استفاده کنید می‌توانید از OSGi استفاده کنید. در مواردِ جز این باید کاربران را ناامید کنم.
فکر می‌کنم هایکو بالاخره آن را برطرف خواهد کرد :-)
بله، البته او می‌خواست این کار را بکند اما پشیمان شد. آخرین ماژولی که می‌خواهم در موردش صحبت کنم Akka Camel که مربوط به پروژه‌ی Apache Camel است.
Camel چیست؟
Camel یک چارچوب کاری برای پیاده‌سازی الگوهای یکپارچه‌سازی سازمانی (Enterprise Integration Pattern) است. اساساً یک زبان مختص حوزه برای سیم‌کشی نقاط مرزی به هم است. ممکن است مشتی پیام از JMS دریافت کنید که بخواهید آن‌ها را از طریق یک مسیر در AMQP رونوشت‌برداری کنید و در همان حال آن را در یک پایگاه‌داده‌ی MySQL ذخیره کنید؛ علاوه بر این، آن را برای حساب‌رسی در جای دیگری قرار دهید. اساساً Camel می‌تواند تمام این نقاط را به سبک هوشمندی به هم متصل کند و لوله‌کشی بین آن را انجام دهد.
Akka این را انتزاع می‌دهد. اگر از منظر کد به آن نگاه کنید تنها کاری که انجام می‌دهید این است که یک اکتور عادی را به عنوان یک مصرف‌کننده معرفی می‌کنید و یک فیلد از نوع رشته تعریف می‌کنید که پروتکل را تعریف می‌کند. مثلاً می‌توانید آن را HTTP قرار دهید. بنابراین اگر یک مصرف‌کننده‌ی HTTP بسازید و آن را راه‌اندازی کنید، به این معنی است که اگر کاربری آن URL خاص را از طریق HTTP باز کند، چیزی را POST می‌کند که به عنوان یک پیام درون اکتور من قرار می‌گیرد و من می‌توانم در قبالش عکس‌العمل نشان دهم. سپس می‌توانم reply را فراخوانی کنم تا به آن پاسخ دهم. زیبایی‌اش اینجاست که اگر بخواهم نقطه‌ی مرزی را تغییر دهم، کافی است یک خط کد را تغییر دهم. مثلاً آن را از HTTP به JMS تغییر دهم. در این صورت تبدیل به اکتوری می‌شود که پیام‌های JMS را دریافت کرده و مصرف می‌کند؛ همین‌طور می‌توانم آن را مصرف‌کننده AMQP بکنم. برای تولید‌کننده هم به همین شکل است. بنابراین همه چیز کاملاً شبیه به اکتور است؛ پیام‌ها را ارسال و دریافت می‌کنید اما پیام‌ها میان نقاط مرزی جابجا می‌شوند. این راه زیبایی است که Akka با دنیای بیرون تعامل می‌کند.
آیا داستانی هم در مورد REST وجود دارد؟
بله. Akka یک یک ماژول HTTP هم دارد که نام پیاده‌سازی اولیه‌ی‌ آن Mist بود و نمی‌دانم می‌خواهم نام آن را عوض کنیم یا نه :-)
شما می‌دانید معنی Mist در زبان آلمانی چیست، نه؟ :-)
بله، این یکی از دلایلی است که می‌خواهیم نام آن را عوض کنیم. برخی از توسعه‌دهندگان فنلاندی هم به من گفتند که در آنجا هم معنی خوبی ندارد :-) اما پیدا کردن نامی که در هیچ زبانی معنی بدی نداشته باشد سخت است.
بله درست است :-)
بنابراین این لایه‌ی Mist امکان کار به صورت ناهمگام (Asynchronous) با Http را می‌دهد. در ابتدا از Jetty استفاده می‌کردیم اما الان برطبق Servlet 3 هستیم تا بتوانیم امکان تعلیق و از سرگیری اتصالات Http به روشی اکتوری را داشته باشیم. اساساً شما پیام‌های PUT، GET، POST و ... را می‌گیرید و به روشی زیبا به اکتورهایتان می‌فرستید. این یک واسط برنامه‌نویسی خیلی سطح پایین است. اما افرادی هستند که چیزهای جالبی روی آن ساخته‌اند. مثلاً یک چارچوب کاری به نام Spray هست که یک زبان مختص حوزه (DSL) به سبک Sinatr در Ruby روی لایه‌ی سطح پایین Akka Mist ساخته است.
ماژول‌های دیگری هم داریم. یکی از آن‌ها که ارزش مطرح کردن دارد ماژول FSM برای ماشین‌های حالت متناهی است. اکتورها عمدتاً ماشین‌های حالت هستند به همین علت سراغ آن رفتیم.
بسیار خوب. اجازه بدهید با صحبت کردن در مورد این‌که Akka کجا و چطور استفاده می‌شود، بحث را جمع کنیم. چطور مقیاس می‌پذیرد؟ از کجا می‌فهمید؟
این سؤال خوبی است. البته ما آن را با آن تعداد گره‌هایی که دوست داشتیم  امتحان نکرده‌ایم، چون مسئله‌ی هزینه در میان بود. اما بزرگ‌ترین نصبی که مشتریان امتحان کرده‌اند ۲۷۴ هسته است و از آن خیلی راضی بودند و خوب از پسِ آن برآمد. مثل همیشه نمی‌توانم منبع آن را ذکر کنم، اما یک نصب خیلی بزرگ بود. به نظر می‌رسد Akka کارش را خوب انجام بدهد که گاهی باعث تعجب من می‌شود :-) اما به نظر می‌رسد همان‌طور که انتظار می‌رود کار می‌کند. البته همیشه این‌طور نیست و در آن موقع مشکلات را برطرف می‌کنیم. Akka به اندازه‌ی کافی در محصولات استفاده شده است، در برخی موارد بیش از ۲ سال. ما از اینکه برای مدت طولانی یک پروژه متن‌باز بوده‌ایم، بهره زیادی برده‌ایم. منظورم این است که افراد با ایده‌ها، وصله‌ها (Patch)، گزارش‌های خطا و ... برای مدت زیادی در آن مشارکت کرده‌اند؛ به همین علت فکر می‌کنم در وضعیت خوبی باشد.
آیا کاربردی در شرکتی که بتوانید نام آن را بگویید داشته است؟
بله، اما باید به آن فکر کنم. مثلاً تلویزیون سوئد از آن استفاده می‌کند. CSCEC یک نصب بزرگ دارد و از آن استفاده می‌کند.
عمدتاً از آن برای سیستم پشت‌کار وب استفاده می‌کنند، درست است؟ یا برای برنامه‌های معظم (Enterprise)؟
در واقع در زمینه‌های متفاوتی استفاده می‌شود. ای‌کاش می‌توانستم تمام شرکت‌هایی که به آن کار می‌کنیم و کاربردشان را نام ببرم، اما نمی‌توانم. اما خلاصه بگویم که اکثر کاربردها در صنایع مالی است البته این با تجارت الکترونیک (E-Commerce) تفاوت دارد. مثلاً در برنامه‌های تجاری که تعداد زیادی تراکنش دارند (توان عملیاتی بالا و تأخیر پایین). در شرط‌بندی و بازی‌سازی هم استفاده شده است. در موارد کاربرد متفاوتی که تراکنش‌های خیلی زیادی دارد. بازی‌های آنلاین چندکاربره‌ی بزرگ (MMO) و همین‌طور بازی‌های سنتی‌تر مثل بازی‌های سبک کازینو و شرط‌بندی ورزشی. در شبیه‌سازی هم برای خُرد کردن داده‌های (Data Crunching) بزرگ استفاده شده است. در تجارت الکترونیک هم بوده است، اما بزرگ‌ترین بخش نبوده است. تعداد زیادی [کاربرد در] رسانه‌های اجتماعی هم داریم.
به خاطر دارم که توئیتر از اسکالا استفاده می‌کند. آیا از Akka هم استفاده می‌کند؟
فکر نمی‌کنم از Akka استفاده کنند. آن‌ها راه‌حل‌های توسعه‌داده شده توسط خودشان را دارند اما وابستگی زیادی به اسکالا دارند. Foursquare و سایر سایت‌های این‌چنینی هم همین‌طور هستند.
آیا داستانی میان Akka و Lift هست؟
می‌دانم که افراد از آن‌ها در کنار هم استفاده می‌کنند.
اما هیچ ائتلاف خاصی وجود ندارد؟
خیر. ما با هیچ چارچوبِ‌کاری وبی (Web Framework) مستقیماً کار نمی‌کنیم، [یعنی] بیش از مبدلی (Adaptor) که دیگران نوشته‌اند. در مورد Lift مقداری کار در این زمینه انجام شده است و همین‌طور در مورد Play که ماژول Akka Play را برای آن داریم و همین‌طور در مورد سایر چارچوب‌های کاری کوچک در اسکالا. ما به جای وابسته شدن به یک چارچوبِ‌کاری وبِ خاص تلاش می‌کنیم با هر چارچوب‌ِکاری‌ای کار کنیم.
ما می‌خواستیم این برنامه را هفته‌ی گذشته ضبط کنیم، اما من وقت نداشتم. در اصل می‌خواستیم دو هفته پیش این کار را کنیم اما شما وقت نداشتید چون یک اتفاق بزرگ در حال رخ دادن بود. می‌خواهید کمی در مورد TypeSafe (نام شرکت به Lightbend تغییر کرده است -مترجم) صحبت کنید؟
بله، حتماً. من در مورد Typesafe خیلی هیجان‌زده‌ام. در واقع راه‌حل‌های مقیاس‌پذیرِ شرکت من است. شرکتی مشاوره‌ای که در آن Akka را توسعه دادم و بعداً تبدیل به یک شرکت محصول حول Akka شد. من و ویکتور کلنگ و چند نفر دیگر (۵ نفر بودیم) به شرکت مارتین اودرسکی به نام Scala Solutions ملحق شدیم تا بتوانیم پشته‌ای روی اسکالا بسازیم. اسکالا یک شالوده دارد و یک پشته‌ی کامل به همراه میان‌افزار و ابزارها و همچنین ائتلافی با چارچوب‌های کاری وب مختلف دارد. ما شرکتی را در ژانویه تأسیس کردیم و تقریباً دو هفته پیش آن را با پشته‌های پیشنهادی که برای آن اشتراک و پشتیبانی داریم، راه‌اندازی کردیم. هنوز تمامی‌اش متن‌باز است. برنامه داریم که بعداً محصولات تجاری هم داشته باشیم اما تا اینجا همه چیز متن‌باز است. در واقع این یک بسته‌ از اسکالا، Akka، و SBT و ابزارهای محیط توسعه‌ی مجتمع (IDE) است که خیلی تست شده است.
به نظر می‌آید که تعدادی زیادی از افراد در دنیای اسکالا را استخدام کرده باشید. شنیده‌ام که هایکو قرار است با شما کار کند.
بله، هایکو از ابتدای ژون شروع می‌کند که فرداست :-) بله من خیلی در مورد آن هیجان زده‌ام. ما توسعه‌دهندگان خوبی از تیم Akka و از تیم مارتین در Scala Solutions داریم. اما به جز آن هم موفق شده‌ایم مغزهای بزرگی را استخدام کنیم. مثلاً توسعه‌دهنده‌ی Multiverse STM که Akka بر آن تکیه می‌کند: پیتر ونجیر اکنون عضوی از Typesafe است. مارک هارا را استخدام کردیم که توسعه‌دهنده‌ی SBT است. پال فیلیپس که یکی از بنیان‌گذاران است و نفر دوم در کامپایلر اسکالا بعد از مارتین است. مغزهای بزرگی هستند.
شنیده‌ام افرادی را از Scala Eclipse IDE استخدام کرده‌اید تا بتوانیم امیدوار باشیم :-)
بله، در شرکت به شدت روی آن کار می‌کنیم تا نه تنها آن را قابل استفاده کنیم بلکه تدریجا‌ً آن را به سطح جاوا برسانیم.
آن موقع من از آن استفاده خواهم کرد :-)
خیلی از افراد این را می‌گویند. برای همین خیلی مهم است.
بله. منظورم این است که اگر یک زبان دارای نوع دارید که تمام توانایی‌های بالقوه برای پشتیبانی IDE را دارد اما یک IDE خوب نداشته باشید، به نوعی همه چیز خراب می‌شود.
بله، متوجه‌ام. من شخصاً هنوز در ویرایشگر متن می‌نویسم؛ به آن عادت کرده‌ام. من سال‌های زیادی با Emacs و TextMate و ... کار کرده‌ام و حتی به آن فکر هم نمی‌کنم. اما این یکی از چالش‌های بزرگ ماست. اما فکر می‌کنم در حال حل کردن آن هستیم. آخرین افزونه‌ی Eclipse خیلی خوب است و الان یک تیم داریم که به آن اختصاص داده شده است تا در هر انتشار آن را بهتر کند. فکر می‌کنم چند ماه طول بکشد تا خیلی خوب شود.
آیا چیزی هست که فراموش کردیم در موردش صحبت کنیم؟ چیزی که بخواهید قبل از پایان بگویید؟
نمی‌دانم. فکر می‌کنم زمان هیجان‌انگیزی برای اسکالا است. افراد را به امتحان آن توصیه می‌کنم و به تدریج که به مشکلات مقیاس‌پذیری بر بخورند فکر می‌کنم باید به Akka نگاهی بیندازند. تعدادی چارچوب‌کاری و ابزارهای دیگر هم در انجمن اسکالا هست. آن یک انجمن عالی با بسیاری توسعه‌دهندگان خوب است که چیزهای خوب زیادی تولید می‌کنند. بنابراین قطعاً ارزش امتحان کردن دارد. اگر در جاوا هستید باز هم می‌توانید از Akka استفاده کنید. یک واسط خوب جاوا هم دارد که نباید مانع امتحان کردن شما شود.
فکر می‌کنم اسکالا نزدیک‌ترین موقعیت را داشته باشد که به بزرگ‌ترین زبان بعد از جاوا تبدیل شود. مطمئن نیستم که هرگز زبانی بتواند اقبال عمومی‌ که جاوا دارد و تا کنون داشته است را به دست بیاورد. اما قطعاً اسکالا در این مسیر قدم بر می‌دارد. همان‌طور که گفتید هیجان‌انگیز است.
من هم به این بزرگ‌ترین زبان بعدی که در موردش صحبت می‌شود، اعتقاد ندارم. این روزها ساختن زبان خیلی ساده است. با وجود JVM دیگر مانع چندانی وجود ندارد. افراد به استفاده از چند زبان عادت کرده‌اند و آن‌قدرها از جابجا شدن میان آن‌ها نمی‌ترسند. فکر می‌کنم بیش‌تر و بیش‌تر به سمت دنیای چندزبانی پیش می‌رویم.
جالب است که هرچند زبان‌های بیشتری به وجود می‌آیند، بسیاری از آن‌ها در اصل ویژگی‌های یکسانی دارند. اساساً یا تابعی است، یا شئ‌گرا، و یکسری فرابرنامه‌نویسی (Metaprogramming) دارند. و دو نوع سیستم داده ایستا و پویا هم وجود دارد. اما مشترکات زیادی میان این زبان‌ها هست.
بله، همین‌طور است. یک هم‌گرایی دارد. بسیاری از ایده‌ها، بلکه تقریباً همه‌ی آن‌ها قدیمی هستند :-) LISP و زبان‌های دیگر ۴۰ سال یا ۲۰ سال قدمت دارند. ما یک چرخه کامل زده‌ایم و آنچه امروزه می‌آید از ۴۰ سال پیش بهتر است.
قطعاً. خیلی متشکرم که در برنامه شرکت کردید. من خیلی از آن لذت بردم. من از بحث در مورد چارچوب‌های کاری میان‌افزارهای زبان لذت می‌برم و امیدوارم شما هم از آن لذت برده باشید.
بله. من مفتخرم که بخشی از آن بودم. خیلی متشکرم که اجازه دادید در برنامه باشم.