Monthly Archives: April 2011

Как проверить базовое знание SQL

Written by elwood

На днях вспомнил об одной задаче, которая мне попалась на работе года полтора назад.
В то время я еще не знал об sql-ex.ru и мои познания в SQL были достаточно слабыми, на уровне
простейших селектов с inner join’ами. И, как я помню тогда, я не смог решить эту задачу без
дополнительного подзапроса. Сейчас, после нескольких десятков решенных задач на sql-ex.ru я
без проблем с ней справился, что навело меня на мысль о том, что это – неплохой тест на знание
азов SQL. В отличие от более сложных задач, эта задачка не требует большого количества времени, но
покрывает почти всё, что требуется для среднего программера в вопросе знания SQL, особенно если решать её в уме. Сразу отпадают вопросы наподобие “что такое JOIN, чем LEFT JOIN отличается от INNER JOIN, как работает группировка” итд.

Итак, формулировка такова. Есть 2 таблицы – Collection и Item.

Необходимо сделать выборку
Collection.ID Collection.Name Collection.Count
тех коллекций, которые содержат меньше 5 элементов.
Вот и всё.

ДАЛЬШЕ СПОЙЛЕР, НЕ ЧИТАТЬ !!!111 (Я не научился пока скрывать в вордпрессе куски постов, но как только научусь – оформлю соответствующе).

Алгоритм решения задачи.
Ну ясно же – надо сделать JOIN, делаем JOIN, группируем по Collection.ID, выводим ID, Name, Count(*).
Черт. При группировке по ID нельзя вывести Name. Значит, надо либо завернуть полученную выборку в еще 1 запрос, либо дописать в группировку этот Name. Ок, работает. Только пустые коллекции не выводятся. Почему ? Ну ясно же – они не попадают в результат INNER JOIN’a, надо использовать LEFT JOIN. О, теперь получилось. Только коллекции-то пустые, а count(*) выводит единицу вместо нуля. Ах да, это же LEFT JOIN, он джойнит Collection.ID Collection.Name NULL NULL и count(*) дает единицу. Как поправить-то. Вычесть 1 нельзя, поскольку так можно запороть непустые коллекции. Надо как-то проверить, является ли коллекция пустой, и для нее вывести 0, а для остальных – count(*). Да у нас же справа NULL, можно их в какую-нибудь агрегатную функцию запихнуть, и сравнить с NULL’ом. Если NULL, значит, коллекция пустая, и для нее выводим 0, иначе – count(*). Эврика! Ну и добавляем HAVING. Пишем запрос:

SELECT
  c.ID, c.Name, CASE WHEN COUNT(*) = 1 AND MAX(i.CollectionID) IS NULL THEN 0 ELSE COUNT(*) END
FROM Collection c
LEFT JOIN Item i ON c.ID = i.CollectionID
GROUP BY c.ID, c.Name
HAVING COUNT(*) < 5

Открытие недели: JRebel

Written by elwood

Если вам нужно что-то постоянно передеплоить, а то и перезапускать, и вам надоело ждать по 3 минуты, когда стартует JBoss Portal, не отчаивайтесь ! Используйте JRebel.
Эта штука реализует подход, более продвинутый, чем HotSwap, и можно не только менять код существующих методов в классах, но и дописывать новые, добавлять филды (в т.ч. статические), конструкторы итд. Для сервлет-контейнеров и app серверов есть специальные приблуды типа корректной обработки релоада не только джаваклассов, но и jsp, Hibernate proxy, в общем много чего.
Последнюю версию с таблэткой можно найти на том же rutracker.
bin/jrebel-app-config.cmd поможет вам настроить Вашу любимую IDE. Только учтите, что при создании run_jrebel.bat вам, скорее всего, нужно будет запускать не run.bat а run_jpda.bat (вы же хотите отлаживать свой код, не так ли?).

Единственный вопрос, остающийся после визарда – что должен содержать rebel.xml и вообще зачем он нужен ? Этот файл должен быть внутри деплоящегося модуля (jar, war) и должен содержать пути к классам, которые могут обновляться. JRebel при первой загрузке модуля смотрит его и начинает мониторить указанные директории. Если классы/jsp в них обновляются (по timestamp), он их перезагружает из этих директорий. В jar этот xml файл должен лежать в корне. Таким образом,

portal-core-lib.jar
> META-INF
> classes
> > some stuff
> rebel.xml

А в rebel.xml вот такая борода:

<?xml version="1.0" encoding="UTF-8" ?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">
<classpath>
<dir name="C:/elwood/work/portal/core/out/production/portal-core-lib" />
</classpath>
</application>

HotSwap в IDEA можно (и даже нужно, скорее всего, поскольку он не будет работать корректно) отключить. Классы помечаются для релоада после их перекомпиляции посредством Ctrl-Shift-F9 (compile one class).
Релоадятся классы не сразу, а при доступе приложения к ним.

Немного о фреймворках

Written by elwood

Обычно считается, что фреймворки для разработки полезны тем, что предоставляют возможность программисту пользоваться некой готовой инфраструктурой. То есть основной плюс – в том, что ДОБАВЛЯЮТСЯ ВОЗМОЖНОСТИ использовать готовое. Но мне в последнее время кажется, что главное преимущество даже не в этом, а в том, что фреймворки, как правило, помимо дополнительных возможностей также накладывают существенные ограничения на код, который будет в рамках него работать.

Пример – Spring MVC предлагает только несколько стандартных способов написать обработчик запроса. Хочешь обработать запрос – пропиши маппинг и добавь метод в контроллер. Хочешь датабиндинг – используй @ModelAttribute. Почему это хорошо ? Потому что разработчику нужно меньше шевелить мозгами, раздумывая над тем, как бы лучше запрограммировать этот кусочек. Больше времени останется на продумывание более важных вещей. Плюс к этому, все, кто знакомы со Spring MVC, будут с первого взгляда понимать то, что хотел сказать программист Вася, написавший этот код года два назад. Значит, добавление ограничений положительно влияет на процесс разработки ? Получается, так.

Действительно, имея широкий набор возможностей, тяжело научиться их правильно использовать. Причем, как правило, сначала учишься использовать правильно, набивая шишки, и попутно придумываешь правила сам. Некий кодстайл, паттерны для того, чтобы писать корректный код, не думая о деталях. Так я учился в своё время языку С++. Читая описание того, что такое header-файл, я нигде не мог найти аргументированных правил по его использованию. Сейчас такая литература появилась в изобилии, но в то время у меня еще не было интернета. И я долгое время не знал, как оформлять h-файлы и как их инклудить в cpp – что именно должно быть в h-файле, а что – в cpp, можно ли инклудить h-файл в другой h-файл; если cpp-файл использует h-файл, зависящий от другого, то нужно ли в cpp-файл включать эту зависимость итд. Поэтому сидел и морщил ум на тему, как же сделать правильно. А всё потому, что С++ предоставляет множество способов сделать это НЕправильно, а очевидности, очевидные для опытных программистов, далеко не так очевидны для новичков. Аналогичные шишки приходилось набивать и на других платформах. C#, к примеру, заставил меня призадуматься о стратегии обработки исключений и особенно о корректной реализации IDisposable в иерархии классов.

Поэтому хороший фреймворк должен не только предоставлять пачку возможностей, но и набор несложных правил о том, как, собственно, писать код. Чтобы лезть в декомпилятор/исходники/дебагер приходилось как можно реже. Codestyle & FAQ – идеальные форматы для такой информации.