Кстати, у такого подхода есть очевидный недостаток. Допустим, сайт очень хорошо нагружен. Например, десятки или сотни запросов в секунду. Если во время генерации кэшируемого объекта поступает ещё один запрос, то мы этот объект генерим два раза. Вот если бы код можно было бы заключить в критическую секцию, подобного эффекта не наблюдалось бы. А всё потому, что PHP.
Нет, картинки — это не табличные данные. Например, список юзеров (логин, дата регистрации, чего-ещё-придумаете) можно расположить в виде таблицы (с заголовком и данными). Или оборотная ведомость — это тоже таблица (заголовок, данные, группировка по товарам, датам и т.п и футер). А вот картинки с подписями — не таблица ни разу. Особенно, когда неизвестно заранее, сколько картинок нужно разместить в одном ряду. Тем более, что картинки с подписями — это всего лишь пример. Могу и другие привести. Скажем, blockquote с нарисованными аккуратными кавычками-ёлочками слева вверху и справа внизу.
В html-файле мы описываем только логическую часть документа и ничего из оформления (да-да, это именно то, о чём мечтали те старые пердуны из W3C). Оформление ложится полностью на плечи css.
К сожалению, это неправда. Зачастую, чтобы сделать более-менее вменяемое оформление средствами одного только CSS, приходится городить бессмысленные div'ы и span'ы. Виной тому недостаточная мощность CSS в смысле задания относительного расположения элементов страницы. Кроме того, приходится использовать подмножество фич, имеющихся в CSS, т.к. браузеры поддерживают не всё или некорректно. Пусть те, у кого не было подобного рода проблем, скажем, с выстраиванием картинок с подписями в ряд, бросят в меня камень.
Кстати, у Java есть ещё фатальный недостаток — её библиотеки. Если с серверной частью всё более-менее гладко, то вот клиентское ПО писать на Java — это самоубийство. Например, для Java есть два GUI-фреймворка и оба кривые.
> Я думаю, это интересная тема для отдельного поста, кстати. Как реализуются замыкания поверх JVM.
А что тут интересного? Если всё так, как я думаю, тогда просто на каждую переменную, на которую мы ссылаемся из анонимного класса, создаётся поле у этого класса и при создании экземпляра класса значение переменной просто копируется в это поле. Потому, видимо, и ввели требование на то, чтобы переменные, видимые в анонимном классе, были final.
Ну уж не знаю, наверняка там тонкости есть. Например, может VM переджитит какой-то метод со статическим вызовом, если ей так будет угодно. Ну или это как-то может помочь инлайнингу в некоторых случаях. А вообще, посмотрел я VM Spec и не увидел какой-то специальной инструкции для невиртуального метода. Хотя с другой стороны, была же какая-то история, что у Vector все методы сделали final «для скорости», а потом все плевались.
Ну это не так страшно. getter/setter сгенерить может IDE. А события замещаются ручной реализацией соответствующего паттерно. Обидно, конечно, но не фатально
— нет лямбд и замыканий;
Есть анонимные классы, и таки немного замыкания. Причём замыкания там даже более каноничные, ведь они же изначально пришли из функциональных языков, где переменные иммутабельны. Почему раз сумели сделать анонимные классы, не сделали анонимных функций — загадка.
— странный механизм аннотаций, который не такой эллегантный как атрибуты в шарпе;
Чем же он не такой элегантный?
— дженерики поддерживаются на уровне языка, но не на уровне виртуальной машины, что иногда приводит к неудобствам;
Да, вот это страшно. Особенно удручает то, что «благодаря» такому механизму мне ничего не остаётся делать, кроме как городить @SuppressWarnings, чтобы при моих настройках IDE не показывал warning'ов (они непротиворечивые, но строгие). Но, как я понял, это было сделано специально, ибо к тому времени, как для Java сделали generics, она была старше и пришлось бы дублировать больший функционал, чем в C# (а в C# его продублировали — см, например, System.Collections и System.Collections.Generic).
— нет вывода типов, динамиков, ко/контравариантности;
Динамики не нужны :-) Вывод типов для переменных действительно отсутствует. Зато он есть для generic'ов, и на топ спасибо. Ко/контрвариантность таки есть.
Зато добавлю от себя более значительных минусов:
— checked exceptions. В принципе, штука имеющая право на существование. Но я всё же за выбрасывание unchecked exceptions. Всё бы ничего, да вот очень многие вещи в JDK выбрасывают checked exceptions. Особенно страшная в этом смысле ситуация с reflection.
— отсутствие аналога IDisposable/using. Для эмуляции схожего функционала приходится городить нечто страшное. Или нагородить кучу helper-методов для безопасного освобождения ресурсов и использовать чуть менее страшную конструкцию.
— отсутствие генераторов (yield return). В связи с этим реализация Iterable — работа для настоящих джедаев. Посему в Java, там где уместно использовать генератор, принято постоянно создавать и заполнять кучу небольших ArrayList'ов, что негативно сказывается на производительности. Впрочем, есть маленький плюс — генераторы сложнее отлаживать.
Я что-то не понимаю, о чём статья. Об очередях сообщений? Ну дык они уже давно используются, например, во многих GUI-фреймворках, и никто не жалуется. Ну а зачем использовать их где попало? Ну и тем более, что в ОС как раз есть на низком уровне эта самая «очередь сообщений». Называется планировщик задач. Только там сообщением потенциально может оказаться одна машинная инструкция. И мир уже давно пользуется фичами, предоставляемыми такой вот очередью сообщений.
Runnable task = new Runnable() {
public void run() {
while (true) {
try {
SwingUtils.invokeLater(new Runnable() {
public void run() {
JOptionPane.showMessageDialog(null, "1");
}
});
Thread.sleep(5000);
} catch (InterruptedException ex) {
break;
}
}
}
};
new Thread(task).start();
Выглядит страшновато, но это потому, что в Java нет анонимных функций, а есть анонимные классы. Ждём 7-й версии или пишем то же самое на С# и будет щасте. Тем более, что пример ужасно примитивный. На работе я строю тяжёлые отчёты примерно по такому же механизму. Во только task у меня реализует расширенный Runnable, который умеет уведомлять о состоянии генератора отчёта (прогресс + текущая выполняемая операция). А реализую я не непосредственно свой интерфейс, а свой же абстрактный класс, где определены protected методы reportProgress и reportActivity, в которых и дёргается SwingUtils.invokeLater. Так что получается, я пишу тот же последовательный код, в котором местами дёргаются reportProgress и reportActivity. А юзер не ждёт, пока программа выйдёт из цикла и начнёт реагировать, а видит гламурное окошко с прогрессбаром. Так что всем хорошо.
Ну и наконец, замечу, что однажды мне пришлось писать веб-морду для некоего XML-RPC сервиса (нужно было просто последовательно дёрнуть 2-3 удалённых метода) и толстого клиента для него же. Так вот оказалось, что JS сильно проиграл в выразительности Java за счёт отсутствия поддержки многопоточности.
Ну вот, начинаются костыли для того, чтобы «писать правильно». Кстати, это не мешает писать ещё и медленно, ибо проблемы с автокомплитом. А вот о преимуществах, ради которых приходится покупать оборудование помощнее, что-то никто не пишет.
Ой, хабр съел кусочек сообщения. «Где list имеет тип List» следует читать как «Где list имеет тип List<MyClass>». Вот как полезно бывает юзать предпросмотр
> тормознутость динамических языков с лихвой компенсируется достаточно недорогим серверным железом и высокой скоростью разработки.
Замечательно. Если язык/платформа позволяет сильно удешевить процесс разработки/поддержки по сравнению с другой платформой, но при этом требует больше вычислительных мощностей, то всё равно мы её предпочтём. Тогда внимание: какие преимущества с точки зрения скорости разработки у динамически типизированных языков перед статически типизированными?
> Для Ruby есть множество IDE, которые отлично с ним ладят, я уже не говорю о Python
… но ни одна из этих IDE не сможет даже близко повторить тот функционал, который поддерживает для Java NetBeans, Eclipse JDT, IDEA или VS + Resharper для C#. Ну хотя бы рефакторинг. Если сигнатура метода неизвестна заранее, то вряд ли мы сможем его автоматом переименовать. Или, скажем, исключить рудиментарный параметр, не нагородив при этом потенциальных ошибок. Ну или так. Вот пишу я в Java:
list.get(i).
Где list имеет тип List. Что вывалится в том же NetBeans, я прекрасно представляю. А вот в случае Ruby не вывалится ничего.
Ну да, отстала. Но мне Java больше нравится по политическим соображениям, нежели чем по технологическим. А начиная где-то версии 5-6, мне на ней хотя бы не противно писать. Ненавижу мелкомягких менеджеров, которые своей политикой гробят такую прекрасную технологию.
> Работая с открытыми технологиями, вы можете непосредственно влиять на разработку. Люди, разрабатывающие продукт, публично известны и с ними легко можно установить прямой контакт. Возникшую проблему можно решить и самостоятельно, а решение отправить на суд разработчикам и другим членам сообщества.
Ну с платными технологиями такая же штуковина. Всё зависит от, на самом деле. Бывают и плохо поддерживаемые откртые проекты, и хорошо поддерживаемые проприетарные.
> Выбирая платную библиотеку вы, как правило, руководствуетесь не качеством, а рекламным слоганом, написанным на сайте.
Ну что-то качеством открытые библиотеки для Java, которые я использую на работе, не отличаются. А вот на прошлом месте работы мы как раз юзали .NET и нареканий не было. Впрочем, там ситуация неоднозначная. Вот у меня много ругани вызывает связка JasperReports + iReport + jfreechart, причём порой оказывается, что нужная фича таки есть, но прикручена она куда-нибудь глубоко внутрь и совсем не документирована. А индусы, которые пишут всякие руководства, как правило, идут по пути индус-way, так что для решения проблемы приходится тщательно изучать код самому. Можно, конечно, купить книжечку по JasperReports, но это уже денежки.
> лишенный прелестей динамического языка
Это какие у динамических языков прелести? Я вот к недостаткам, помимо тормознутости, могу прибавить ещё и большую сложность разработки, ибо IDE просто на порядки лучше поддерживает статически-типизированные языки.
> В один момент мы поняли, что в наших проектах мы тратим более половины времени на доработку изъянов .NET и изобретение собственных «велосипедов»
Честно говоря, с какой бы технологией я не работал, никогда не видел, чтобы удалось полностью избежать описанного.
А вообще, заголовок статьи немного провокационный. Да, у дотнета есть определённые проблемы с web. Но дотнет вебом не ограничивается. Там ещё куча технологий. Например, лучше WPF в плане построения пользовательских интерфейсов, я ещё ничего не видел. Какой-нибудь Swing, который я сейчас использую, и для которого приходится изобретать кучу велосипедов и применять множество костылей, даже рядом не валялся. Так что может стоило назвать «почему мы сказали ASP.NET'у нет»?
Может, это проблема X Window? У нас на работе есть софт, написанный на Java. Так вот если по rdp (по обычному интернету, в том числе в городах с плохой связью) он вполне нормально шевелится, то вот с иксами проблема. Частично решается установкой стандартной свинговой темой и отключением двойной буферизации в свинге же.
Да банально C#. Всё подряд он не выводит, как та же Скала, но даже и с его простеньким выводом типов пишется довольно-таки легко и ненавязчиво. Ну или, например, JavaFX script (жаль только там нет поддержки generics).
По моему опыту, отngen'енные приложения как-то помедленнее работают. Лучше уж пусть программа 2-3 секунды JIT'ится при запуске. Особенно это критично для серверного ПО (а там вообще сервер стартовать может по несколько минут, причём отнюдь не по вине JIT'а).
К сожалению, это неправда. Зачастую, чтобы сделать более-менее вменяемое оформление средствами одного только CSS, приходится городить бессмысленные div'ы и span'ы. Виной тому недостаточная мощность CSS в смысле задания относительного расположения элементов страницы. Кроме того, приходится использовать подмножество фич, имеющихся в CSS, т.к. браузеры поддерживают не всё или некорректно. Пусть те, у кого не было подобного рода проблем, скажем, с выстраиванием картинок с подписями в ряд, бросят в меня камень.
А что тут интересного? Если всё так, как я думаю, тогда просто на каждую переменную, на которую мы ссылаемся из анонимного класса, создаётся поле у этого класса и при создании экземпляра класса значение переменной просто копируется в это поле. Потому, видимо, и ввели требование на то, чтобы переменные, видимые в анонимном классе, были final.
Ну это не так страшно. getter/setter сгенерить может IDE. А события замещаются ручной реализацией соответствующего паттерно. Обидно, конечно, но не фатально
Есть анонимные классы, и таки немного замыкания. Причём замыкания там даже более каноничные, ведь они же изначально пришли из функциональных языков, где переменные иммутабельны. Почему раз сумели сделать анонимные классы, не сделали анонимных функций — загадка.
Чем же он не такой элегантный?
Да, вот это страшно. Особенно удручает то, что «благодаря» такому механизму мне ничего не остаётся делать, кроме как городить @SuppressWarnings, чтобы при моих настройках IDE не показывал warning'ов (они непротиворечивые, но строгие). Но, как я понял, это было сделано специально, ибо к тому времени, как для Java сделали generics, она была старше и пришлось бы дублировать больший функционал, чем в C# (а в C# его продублировали — см, например, System.Collections и System.Collections.Generic).
Динамики не нужны :-) Вывод типов для переменных действительно отсутствует. Зато он есть для generic'ов, и на топ спасибо. Ко/контрвариантность таки есть.
Зато добавлю от себя более значительных минусов:
— checked exceptions. В принципе, штука имеющая право на существование. Но я всё же за выбрасывание unchecked exceptions. Всё бы ничего, да вот очень многие вещи в JDK выбрасывают checked exceptions. Особенно страшная в этом смысле ситуация с reflection.
— отсутствие аналога IDisposable/using. Для эмуляции схожего функционала приходится городить нечто страшное. Или нагородить кучу helper-методов для безопасного освобождения ресурсов и использовать чуть менее страшную конструкцию.
— отсутствие генераторов (yield return). В связи с этим реализация Iterable — работа для настоящих джедаев. Посему в Java, там где уместно использовать генератор, принято постоянно создавать и заполнять кучу небольших ArrayList'ов, что негативно сказывается на производительности. Впрочем, есть маленький плюс — генераторы сложнее отлаживать.
качать 1ГБ Windowsпокупать за $150? Расскажите о преимуществах разработчикам GRUBRunnable task = new Runnable() { public void run() { while (true) { try { SwingUtils.invokeLater(new Runnable() { public void run() { JOptionPane.showMessageDialog(null, "1"); } }); Thread.sleep(5000); } catch (InterruptedException ex) { break; } } } }; new Thread(task).start();Выглядит страшновато, но это потому, что в Java нет анонимных функций, а есть анонимные классы. Ждём 7-й версии или пишем то же самое на С# и будет щасте. Тем более, что пример ужасно примитивный. На работе я строю тяжёлые отчёты примерно по такому же механизму. Во только task у меня реализует расширенный Runnable, который умеет уведомлять о состоянии генератора отчёта (прогресс + текущая выполняемая операция). А реализую я не непосредственно свой интерфейс, а свой же абстрактный класс, где определены protected методы reportProgress и reportActivity, в которых и дёргается SwingUtils.invokeLater. Так что получается, я пишу тот же последовательный код, в котором местами дёргаются reportProgress и reportActivity. А юзер не ждёт, пока программа выйдёт из цикла и начнёт реагировать, а видит гламурное окошко с прогрессбаром. Так что всем хорошо.
Ну и наконец, замечу, что однажды мне пришлось писать веб-морду для некоего XML-RPC сервиса (нужно было просто последовательно дёрнуть 2-3 удалённых метода) и толстого клиента для него же. Так вот оказалось, что JS сильно проиграл в выразительности Java за счёт отсутствия поддержки многопоточности.
Замечательно. Если язык/платформа позволяет сильно удешевить процесс разработки/поддержки по сравнению с другой платформой, но при этом требует больше вычислительных мощностей, то всё равно мы её предпочтём. Тогда внимание: какие преимущества с точки зрения скорости разработки у динамически типизированных языков перед статически типизированными?
> Для Ruby есть множество IDE, которые отлично с ним ладят, я уже не говорю о Python
… но ни одна из этих IDE не сможет даже близко повторить тот функционал, который поддерживает для Java NetBeans, Eclipse JDT, IDEA или VS + Resharper для C#. Ну хотя бы рефакторинг. Если сигнатура метода неизвестна заранее, то вряд ли мы сможем его автоматом переименовать. Или, скажем, исключить рудиментарный параметр, не нагородив при этом потенциальных ошибок. Ну или так. Вот пишу я в Java:
list.get(i).
Где list имеет тип List. Что вывалится в том же NetBeans, я прекрасно представляю. А вот в случае Ruby не вывалится ничего.
Ну с платными технологиями такая же штуковина. Всё зависит от, на самом деле. Бывают и плохо поддерживаемые откртые проекты, и хорошо поддерживаемые проприетарные.
> Выбирая платную библиотеку вы, как правило, руководствуетесь не качеством, а рекламным слоганом, написанным на сайте.
Ну что-то качеством открытые библиотеки для Java, которые я использую на работе, не отличаются. А вот на прошлом месте работы мы как раз юзали .NET и нареканий не было. Впрочем, там ситуация неоднозначная. Вот у меня много ругани вызывает связка JasperReports + iReport + jfreechart, причём порой оказывается, что нужная фича таки есть, но прикручена она куда-нибудь глубоко внутрь и совсем не документирована. А индусы, которые пишут всякие руководства, как правило, идут по пути индус-way, так что для решения проблемы приходится тщательно изучать код самому. Можно, конечно, купить книжечку по JasperReports, но это уже денежки.
> лишенный прелестей динамического языка
Это какие у динамических языков прелести? Я вот к недостаткам, помимо тормознутости, могу прибавить ещё и большую сложность разработки, ибо IDE просто на порядки лучше поддерживает статически-типизированные языки.
> В один момент мы поняли, что в наших проектах мы тратим более половины времени на доработку изъянов .NET и изобретение собственных «велосипедов»
Честно говоря, с какой бы технологией я не работал, никогда не видел, чтобы удалось полностью избежать описанного.
А вообще, заголовок статьи немного провокационный. Да, у дотнета есть определённые проблемы с web. Но дотнет вебом не ограничивается. Там ещё куча технологий. Например, лучше WPF в плане построения пользовательских интерфейсов, я ещё ничего не видел. Какой-нибудь Swing, который я сейчас использую, и для которого приходится изобретать кучу велосипедов и применять множество костылей, даже рядом не валялся. Так что может стоило назвать «почему мы сказали ASP.NET'у нет»?