В Scala есть еще implicit convertions и implicit parameters. При помощи них можно придумать много чего самострельного. Хуже то, что для этого не нужно что-то изобретать — наступить эти на грабли можно даже не специально. Если Вам нужны примеры, зайдите на StackOverflow и поищите по «scala implicit» и среди 5800 результатов посмотрите какие у людей с ним проблемы. Кроме всего прочего, такой инструмент при неумелом использовании пораждает различные bad practice. А для умелого использования не хватает четко обозначенных use cases, где использовать это необходимо или разумно.
Не понял на счет контрпримеров. C — это мощный, сложный, но слаботипизированный язык (как говорил мой препод — язык среднего уровня), утыканный граблями. Haskell — наоборот, простой язык с четкой идеей.
Если это все выстрелы, то все очень даже неплохо. В scala есть один хороший способ выстрелить себе одновременно в ногу, затылок и задницу, и задеть всех, кто стоит рядом. Это implicit. И если его добавить в пункт 5, то будет просто прекрасно.
Вообще во многих случаях scala ведет себя так, что то, что написано — это совсем не то, что имеется ввиду. В лучшем случае, вы смотрите на кусок кода и не понимаете что к чему без знания всего контекста. Так уж закономерность — чем мощнее инструмент, тем легче им отрезать палец.
P.S. в 9-м пункте ключи разные:
cache.put(«IAmNull», null)
getter(«IamNull»)
Он там все еще есть, но отключается автоматически, если в запросе используется какая-то несовместимая с ним фича.
CBO вообще не такой умный как кажется, поэтому нам пришлось для некоторых запросов ставить /*+Rule*/, чтобы выполнение было всегда оптимальным и предсказуемым. CBO почему-то для некоторых запросов периодически выбирал неоптимальный план, а для нескольких всегда следовал неоптимальному плану, даже при собранной статистике.
Размер таблицы клиентов может быть сравним с заказами и в общем случае не помещаться в память. Любой кеш сильно усложняет архитектуру, особенно когда хотите кешировать запросы. Кстати, многие RDBMS умеют делать materialized views для медленных запросов, который по сути и есть кеш. Для любого решения, которое вы сможете придумать, JOIN-ы будут работать проще и быстрее, пока не встанет проблема горизонтального масштабирования…
И как это у вас получается? Дизайн реляционной базы отличается от NoSql тем, что все сущности нормализованы и распеханы по разным таблицам, тогда как NoSQL может разные сущности иерархически в одной коллекции. И чтобы получить мало-мальски релевантную информацию, всегда приходится запрашивать данные сразу из нескольких таблиц. Чтобы получить список заказов, придется запрашивать также таблицу клиентов, т.к. нам хочется показать его имя, а не FK ID. Без JOIN-ов это можно сделать лишь для каждого заказа запрашивать клиента из таблицы (проблема N+1 query), либо объединить необходимых клиентов в один запрос: SELECT… FROM Clients WHERE id IN(?,?,...). Но в любом случае JOIN будет быстрее на порядки.
Так что если Вы пользуетесь реляционной базой, глупо не пользоваться стандартным функционалом в угоду предрассудкам. Другое дело, если реляционная модель уже не подходит решаемой задаче.
Это еруйня. С верии 10 Oracle планировщик (Cost-based optimizer) не различает вообще как вы соединяете таблицы: JOIN-ом, WHERE, используете IN или SELECT FROM subquery. Также нет разницы между порядком указания таблиц, даже если их объем сильно различается. Планировщик все приводит к стандартному виду и оптимизирует на основе статистики. Если Вы старую версию Oracle, либо указываете в запросе явно использовать Rule-based optimizer, тогда да — запросы выполняются на основе списка правил. В редких случаях это имеет смысл.
Ну да, вцелом тезис понятный, но многое спорно. Если удается выделить функциональную единицу, почему бы ее сразу не оформить ввиде отдельного модуля, компонента или библиотеки? Изначально сделанный дизайн системы (в соответствии с правилами слабой связанности и делегирования ответственности) и правильно выбранные абстракции упрощают разработку, тестирование и поддержку кода. И ничего не вижу плохого в том, что дизайн и код будут эволюционировать. Главное всегда уметь выявить зависимости, чтобы знать какой код затронет каждое изменение (поэтому я и не пишу на языках с динамической типизацией). Оверинжиниринг случается не из-за модульного дизайна, а когда люди пытаются абстрагироваться от решаемой задачи, поставив свой модуль как саму цель, а не как часть конкретного решения. И тогда да — появляется куча ненужных методов «на будуще» и абстракций для «расширения функционала».
С ремонтом подразумевается, что ты профессиональный мастер и что далеко не первый дом делаешь. А переделывать приходится когда резко меняются функциональные реквизиты клиента (теперь это будет не дом, а гараж), либо когда этих изменений накапливается такое большое количество, что старый дизайн системы уже не имеет смысла. И тогда созревает новый релиз 2.0, который пишется фактически с нуля, учитывая новые реквизиты. И да, старая ветка идет в помойку. Практически вся.
Руководство по ремонту дома от Tom Smykowski.
Шаг 0. Не делайте ремонт.
Шаг 1. Используйте самые дешевые материалы.
Шаг 2. Теперь переделайте все, используя дорогие материалы.
Шаг 3. Сделайте все быстро и тяп-ляп.
Шаг 4. Теперь все сломайте и переделайте как надо.
Шаг 5. Сделайте настил на пол из цельного куска ДСП.
Шаг 6. Отдерите настил, распилите на доски и прибейте их по отдельности.
Шаг 7. Заготовьте краску и доски для будущего ремонта.
Как-то так.
Не понятна основная идея: зачем мне два раза писать один и тот же код — сначала плохо, а затем хорошо, если я сразу в состоянии сделать хорошо? И да, рефакторить код время от времени необходимо, удаляя лишнее. Это не для кого не секрет. Только зачем это делать со всем написанным кодом?
Ну, можно попробовать закантактироваться с самими авторами, чтобы прислали или залили куда-нибудь свои презентации. Если Вы пишите на Груви, то посмотреть их тоже не помешает.
По поводу «инь-ян»: не все так красиво, как хотелось бы. Вот электрический заряд существует, а магнитный почему-то нет. И уравнения ваши не симметричны…
Это все очень хорошо, свежо и альтернативно, но неверно. Основная идея Вачовски была экранизировать гностический миф в стиле киберпанка. Это даже не скрывается, а открыто демонстрируется в именах героев, названиях, различных главных и второстепенных символах.
В гностицизме Ялдабаоф-архитектор пытался создать свой мир из костной материей. Но все его создания были нежизнеспособны: неспособны к развитию и самоорганизации, что каждый раз заканчивалось крахом. Поэтому он поработил свободный дух и заключил его в костную материю, дабы сделать процесс жизнеспособным.
Теперь становится понятной необходимость подключения людей к матрице. Это вычислительные элементы, а вовсе не генераторы энергии. В отличие от машин они не обладают детерминированной логикой (свободная воля), и выполняют роль основного двигателя в эволюции матрицы.
P.S. Кто-нибудь вкурсе, что изначальный сценарий имел совсем другуе развитие, нежели отснятый в фильме? Например, что никто никогда не покидал Матрицу...
Проблема в том, что это будут люди. А людям свойственны пороки. А пороки будут требовать фильтровать и изменять информацию в угоду себе. И очень быстро Орден Хранителей Знаний превратится в Министерство Правды.
Достаточно посмотреть доклады Евгения Борисова и Баруха Садогруского про Groovy, чтобы понять чтО это за язык. При кажущемся простом и логичном выражении мысли постоянно спотыкаешься о всевозможные грабли.
Кроме того статическая типизация там пятым колесом — все динамически типизировано. А динамика меня угнетает (даже с умной Idea).
Планируете ли Вы помимо языка создание и поддержку инициативы вроде Typesafe по формированию стека технологий для наиболее актуальных задач на базе языка Kotlin?
Теоретически ничем. Схема — это фишка исключительно парсера, который в случае ее указания, пытается сначала проверить XML на соответствие оной. Если схема не указана, XML парсится без нее как есть. А затем уже сервер готовит контекст, зная заранее структуру.
Обычно сервера держат необходимые схемы в локальных ресурсах, и подгружаться ничего не должно. Просто Вы зачем-то взяли уж очень экзотическую и старую схему для web.xml. Обычно используют что-то вроде этого:
В документации же в простой и доходчивой форме написано:
MessageFormat uses patterns of the following form:
MessageFormatPattern:
String
MessageFormatPattern FormatElement String
То есть, как легко заметить даже невооруженным взглядом, FormatElement должен быть отделен от другого FormatElement-а как минимум String. К сожалению, разработчики забыли упомянуть что такое этот 'String'. Но тут даже ребенку ясно, что это любая непустая строка, и что "" не может являться 'String'-ом. Как-то так. Кроме того, данный паттерн успешно работает в обратную сторону — на .format() и генерирует правильную строку.
Этот паттерн у меня прописан в config-файле для генерации имени для лог-файлов. Проблема обнаружилась, когда нужно было автоматически чистить старые логи: при проверке имени файла на паттерн парсер валился.
Проблема в том, что это не просто не удается сделать, а наоборот, это можно сделать туевой хучей способов (струнные теории, петлевая гравитация, etc)… И все одинаково плохие.
Само пространство-время. В ОТО это не статичная независимая сущность, как в механике ньютона, а динамическая, меняющаяся, и способная искривляться и переносить энергию.
А раз так, — сказали квантовые механики, — значит энергия гравитационного поля должна квантоваться и должен быть элементарный переносчик этой энергии (гравитон). И тут их ждал лютый облом, который продолжается и по сей день, и выхода пока не видно...
Граблями я бы это не назвал. Грабли — это то, что лежит под ногами, на что постоянно наступают новички. Такое как String.equals() и ==. А это — подводные скалы в лагуне мертвых кораблей, куда нормальный моряк соваться никогда не будет.
А вот пример реальных граблей, на которые я наступил на прошлой неделе:
new MessageFormat(«file-{0,date,yyyyMMdd}{1,date,yyyyMMdd}.log»)
.parse(«file-2016020720160208.log»);
Не понял на счет контрпримеров. C — это мощный, сложный, но слаботипизированный язык (как говорил мой препод — язык среднего уровня), утыканный граблями. Haskell — наоборот, простой язык с четкой идеей.
Вообще во многих случаях scala ведет себя так, что то, что написано — это совсем не то, что имеется ввиду. В лучшем случае, вы смотрите на кусок кода и не понимаете что к чему без знания всего контекста. Так уж закономерность — чем мощнее инструмент, тем легче им отрезать палец.
P.S. в 9-м пункте ключи разные:
cache.put(«IAmNull», null)
getter(«IamNull»)
CBO вообще не такой умный как кажется, поэтому нам пришлось для некоторых запросов ставить /*+Rule*/, чтобы выполнение было всегда оптимальным и предсказуемым. CBO почему-то для некоторых запросов периодически выбирал неоптимальный план, а для нескольких всегда следовал неоптимальному плану, даже при собранной статистике.
Так что если Вы пользуетесь реляционной базой, глупо не пользоваться стандартным функционалом в угоду предрассудкам. Другое дело, если реляционная модель уже не подходит решаемой задаче.
С ремонтом подразумевается, что ты профессиональный мастер и что далеко не первый дом делаешь. А переделывать приходится когда резко меняются функциональные реквизиты клиента (теперь это будет не дом, а гараж), либо когда этих изменений накапливается такое большое количество, что старый дизайн системы уже не имеет смысла. И тогда созревает новый релиз 2.0, который пишется фактически с нуля, учитывая новые реквизиты. И да, старая ветка идет в помойку. Практически вся.
Шаг 0. Не делайте ремонт.
Шаг 1. Используйте самые дешевые материалы.
Шаг 2. Теперь переделайте все, используя дорогие материалы.
Шаг 3. Сделайте все быстро и тяп-ляп.
Шаг 4. Теперь все сломайте и переделайте как надо.
Шаг 5. Сделайте настил на пол из цельного куска ДСП.
Шаг 6. Отдерите настил, распилите на доски и прибейте их по отдельности.
Шаг 7. Заготовьте краску и доски для будущего ремонта.
Как-то так.
Не понятна основная идея: зачем мне два раза писать один и тот же код — сначала плохо, а затем хорошо, если я сразу в состоянии сделать хорошо? И да, рефакторить код время от времени необходимо, удаляя лишнее. Это не для кого не секрет. Только зачем это делать со всем написанным кодом?
В гностицизме Ялдабаоф-архитектор пытался создать свой мир из костной материей. Но все его создания были нежизнеспособны: неспособны к развитию и самоорганизации, что каждый раз заканчивалось крахом. Поэтому он поработил свободный дух и заключил его в костную материю, дабы сделать процесс жизнеспособным.
Теперь становится понятной необходимость подключения людей к матрице. Это вычислительные элементы, а вовсе не генераторы энергии. В отличие от машин они не обладают детерминированной логикой (свободная воля), и выполняют роль основного двигателя в эволюции матрицы.
P.S. Кто-нибудь вкурсе, что изначальный сценарий имел совсем другуе развитие, нежели отснятый в фильме? Например, что никто никогда не покидал Матрицу...
Кроме того статическая типизация там пятым колесом — все динамически типизировано. А динамика меня угнетает (даже с умной Idea).
<web-app version=«2.4» xmlns=«http://java.sun.com/xml/ns/j2ee» xmlns:xsi=«http://www.w3.org/2001/XMLSchema-instance» xsi:schemaLocation=«http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd»>
А с недавнего времени (servlet 3.0, лет 5 как уже) используют это:
<web-app xmlns=«http://java.sun.com/xml/ns/javaee»
xmlns:xsi=«http://www.w3.org/2001/XMLSchema-instance»
xsi:schemaLocation=«http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd»
version=«3.0»
metadata-complete=«false»>
В этих случаях ничего нигде ниоткуда не подгружается, сервер знает все схемы.
MessageFormat uses patterns of the following form:
MessageFormatPattern:
String
MessageFormatPattern FormatElement String
То есть, как легко заметить даже невооруженным взглядом, FormatElement должен быть отделен от другого FormatElement-а как минимум String. К сожалению, разработчики забыли упомянуть что такое этот 'String'. Но тут даже ребенку ясно, что это любая непустая строка, и что "" не может являться 'String'-ом. Как-то так. Кроме того, данный паттерн успешно работает в обратную сторону — на .format() и генерирует правильную строку.
Этот паттерн у меня прописан в config-файле для генерации имени для лог-файлов. Проблема обнаружилась, когда нужно было автоматически чистить старые логи: при проверке имени файла на паттерн парсер валился.
А раз так, — сказали квантовые механики, — значит энергия гравитационного поля должна квантоваться и должен быть элементарный переносчик этой энергии (гравитон). И тут их ждал лютый облом, который продолжается и по сей день, и выхода пока не видно...
А вот пример реальных граблей, на которые я наступил на прошлой неделе:
new MessageFormat(«file-{0,date,yyyyMMdd}{1,date,yyyyMMdd}.log»)
.parse(«file-2016020720160208.log»);