
купил и радуюсь 1
58 дн. назад
Комментарии [2]
Дегикизация
139 дн. назад
“Итоги года” пост.
Прошлый год
За прошлый год, наверное, основное достижение – это то, что я перестал себя подгонять как ломовую лошадь. Сказалось влияние советов Насима Талеба, Hammock-Driven Development’a Ричарда Хикки. Из других достижений – около $30K заработанных денег и около 30 прочитанных книг; записался в школу игры на губной гармошке и пересел за мак, в плане выпуск собственного продукта (онлайн версия карточной игры Диксит – это что-то вроде игры Крокодил с карточками)
Из новых языков программирования, которые начал осваивать – это Clojure. По субъективным ощущениям – язык непростой, но интересный. Недавно вышла версия 1.3, где успели поработать над производительностью и внесли некоторые изменения, т.е. язык активно развивается. Самый основной плюс Clojure – это сообщество. Рич Хикки (Rich Hickey), создатель языка, – мужик с харизмой, философ-программист с обширным опытом работы с JEE, а это значит, что как ни крути Clojure ориентируется на веб-разработку. Одна маленькая победа у Clojure уже есть – это твиттеровский проект Storm, которую они использует для просмотра статистики в realtime.
Из других языков попавших в мое поле зрения – это Ceylon (от создателей ORM Hibernate) и Kotlin (от JetBrains). Оба еще не вышли, но в целом не очень интересные. Kotlin – ява со свистульками. Ceylon – Java c продвинутой системой типов, встроенным учетом зависимостей и версий и т.д. Второй выглядит получше, но в целом, как было написано в одном блоге, Ceylon пишут для того, чтобы было проще написать Hibernate, а Kotlin для того, чтобы было проще разрабатывать Intellij Idea.
На работе выпустили несколько игр. В плане опыта больше всего прибыло в понимании, что такое хорошая архитектура. Так получается, что наш отдел по социальным играм разбит на 3 отдельных команды (у каждой своя игра) и я занимаюсь больше инфраструктурой частью, что дает мне возможность заглянуть в код на всех 3 проектах. Со стороны видно как отличается стиль и методы в каждом проекте. Если подвести итог коротко, то основная проблема – это грань между абстрактным и конкретным, размытый уровень предметной области. Здесь и мне не мешало бы поучиться, чего греха таить. И здесь я торжественно клянусь дочитать и применять на практике книгу Эрика Эванса Domain-Driven Desgin.
Этот год
Решил провести этот год по знаком дегикизации. Отписался от старых гиков/пердунов. Думаю еще через пол года уже прилично играть на гармошке и научиться рисовать (ссылка в тему: Journey of an Absolute Rookie).
Для прототипирования хочу освоить inDesign и какие-то базовые вещи по типографике, работе с цветом и композицией. Все-таки на примере своих кустарных стартапов в этом году лишний раз убедился, что код – это хуйня и просто, а дизайн (не только оформление, а дизайн самого продукта как вещи) – это сложно и 90% успеха. Технические вещи всегда можно исправить, но если продукт – хуйня, то его не спасет то, как он круто написан и что там применен паттерн Цепочка обязанностей и масштабирование на уровне. В обратную сторону – все ок. Первым человеком, которого наняла Quora, был именно дизайнер.
Техническую часть, конечно, не буду совсем забрасывать. Продолжу следить за Clojure. На днях должна выйти новая редакция книги по 1.3. К сожалению, реального применения для себя не вижу. Может быть буду решать небольшие алгоритмические задачи для TopCoder’a (еще один старый пункт в моем todo-листе).
Из новых языков для изучений – что-то мейнстримовое. Основные претенденты: JavaScript + HTML5, ObjectiveC + iOS, ActionScript + Flash.
В плане работы – реализация своих проектов. Для начала Диксит, а там уже будет видно.
В целом, хотелось бы в этом году поменьше работать, но больше зарабатывать. Надеюсь, что всё получится :)
Недостатки Java: Threads
393 дн. назад
Когда я говорил о недостатках Java, то упустил одну вещь, а именно – многопоточность.
Стандартные реализация потоков в Яве имеет некоторые проблемы, некоторые из которых я попробую описать. На полноту я не претендую, поэтому расскажу только то, что знаю, самые очевидные из них.
Небольшой ликбез
В яве центральное понятие для мнопоточности – это понятие “монитора”. Монитор можно представить себе как объект специального назначения, который представляют собой набор некоторого кода, процедур, доступ к которым гарантирован по принципу взаимного исключения (mutal-exclusion), или взаимо-исключающему семафору (mutal-exclusion semaphore или просто mutex, мьютекс). Мониторы существуют только на уровне работы JVM, они не доступны как объекты Java.
Основная идея мьютекса – это владение. Только один поток может завладеть мьютексом в одно время. Если другой поток попытается захватить мьютекс, это заблокирует его пока первый поток не отпустит мьютекс.
Если несколько потоков ждут освобождения мьютекса, то только один получит мьютекс, когда тот освободится. Остальные продолжат ожидание.
Т.е другими словами, имея код:
synchronized (this) {
doSomething();
}
мы можем представить его себе, как:
this.mutex.acquire();
try {
doSomething();
} finally {
this.mutex.release();
}
Проблема 1: Каждый объект в Java имеет только один монитор
Чтобы объяснить это, приведу аналогию, которую я прочел в одной из книг по потокам и она мне показалась очень удачной.
Представим себе, что монитор – это туалет на борту самолета. Только один человек (поток, thread) может воспользоваться туалетов в одно время. Все остальные вынуждены ждать пока туалет не освободится, создавая очереди и так далее, и так далее. Пока дверь закрыта – все ждут.
В этом примере, объект – это самолет. Пассажиры – потоки. Туалет – монитор. Замок на двери – мьютекс.
В яве, у каждого объекта есть один и только один монитор. В тоже время, один монитор (туалет) может иметь несколько дверей в него. Каждая дверь представляет собой synchronized блок. Когда пассажир заходит в туалет, то все двери закрываются. Это и есть проблема и ограничение.
С другой стороны, если в туалет ведут двери, на которые не установлен замок (нет synchronized блока), то пассажир может войти в туалет, не закрыв замки и вполне может ожидать, что его потревожит кто-то другой (другой поток).
Можно проиллюстрировать с помощью следующего кода:
public class EveryObjectIsMutex {
private int count;
private int anotherCount;
static public void main(String[] args) {
final EveryObjectIsMutex mutex = new EveryObjectIsMutex();
new Thread(new Runnable() {
public void run() {
mutex.setCount(20);
}
}).start();
System.out.println(mutex.getCount());
System.out.println(mutex.getAnotherCount());
}
synchronized public int getCount() {
return count;
}
synchronized public void setCount(int count) {
// some long calculations goes here
this.count = count;
}
synchronized public void setAnotherCount(int anotherCount) {
this.anotherCount = anotherCount;
}
synchronized public int getAnotherCount() {
return anotherCount;
}
}
Здесь пока выполняется метод setCount(20) в отдельном потоке, никакой другой методов над объектом mutex выполнить нельзя. Даже getAnotherCount(), хотя тот и использует совсем другие данные, никак не пересекаясь с данными метода setCount().
Выход из этой ситуации делать synchronized над разными объектами внутри setCount() и setAnotherCount() с помощью:
…
private Object lock1;
pirvate Object lock2;
…
public void setCount(int count) {
synchronized (lock1) {
// some long calculations goes here
this.count = count;
}
}
synchronized public void setAnotherCount(int anotherCount) {
synchronized (lock2) {
this.anotherCount = anotherCount;
}
}
wait() и notify()
Wait() и notify() – это еще способ синхронизации. Первый – взаимное исключение с помощью мьютексов – позволяет осуществлять последовательный доступ к общим данным.
Второй – это кооперация с помощью wait() и notify(). Это необходимо, когда один поток зависит от другого потока (например, ждет данных, которые еще не поступили).
С этими методами связано несколько проблем.
Первая – wait() принимает как параметр таймаут, максимальное время, которые нужно ждать, но при возврате из метода wait() нет никакой возможности узнать был ли возврат вызван таймаутом или тем, что другой поток вызвал notify().
Вторая проблема – nested-monitor lockout (не знаю, как перевести по-хорошему на русский). С wait() и notify(), как и с любыми блокирующими операциями, очень легко нарваться на это вид deadlock’a. Проблема заключается в том, что блокирующая функция может быть вызвана из синхронизированного кода. И единственный способ разблокировать ее – вызвать другой синхронизированный метод.
Пример:
public class BlockingObject {
public synchronized void sleep() {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void wakeUp() {
notify();
}
};
public class NestedMonitorLockout {
private BlockingObject object = new BlockingObject();
public static void main(String[] args) {
final NestedMonitorLockout nestedLock = new NestedMonitorLockout();
new Thread(new Runnable() {
public void run() {
nestedLock.sleep();
}
}).start();
nestedLock.wakeUp();
}
private synchronized void sleep() {
object.sleep();
}
private synchronized void wakeUp() {
object.wakeUp();
}
}
Основное правило, как избежать этого – не делать блокирующих вызовов внутри синхронизированных методов. А если делать, то должен быть не синхронизированный метод, который может достучаться к блокируемому объекту.
Пока все.
На этом пока можно остановится. Уже из этих примеров видно, что многопоточное программирование в яве – нетривиальная задача. Стандартные средства есть, но они несовершенны (wait() мог бы возвращать boolean, индикатор, что возврат был по таймауту или по notify(), synchronized блок не поддерживает таймауту по умолчнанию). И так далее. О других вещах и как обойти эти ограничения – в следующий раз.
Воскрешение блога II
395 дн. назад

По уже доброй традиции.
REST: Основы
395 дн. назад
Введение
REST – термин такого же рода как “объектно-ориентированный”. Под этим терминов понимается подход к архитектуре. Это если в общих словах.
Точно также как и в ООП есть некоторых набор концепций (инкапсуляция, наследование, полиморфизм), так и REST определяет некоторый набор принципов (statelessness, addressability, connectedness, единый интерфейс и т.д.).
В ООП также есть свои понятия:
- класс
- объект
- методы
- передача сообщений
В REST тоже есть свои понятия:
- Resource – ресурс (например, список ссылок)
- Representation – виды ресурса (например, html – страница со ссылками в браузере, rss – таже страница, но в для рсс-фида)
- Адрес ресурса (например, URL страницы)
- Единый интерфейс (GET, POST, PUT, DELETE и другие методы для HTTP-протокола)
Точно также как можно написать программу на объектно-ориентированном языке не используя никаких из принципов ООП, так и сайты, что хоть и доступны с помощью отличной реализации REST-принципов – протокола HTTP, сами эти REST принципы могут и не использовать.
Понятия REST (поподробнее)
Ресурс
Ресурс – под ресурсом понимается все что угодно достаточно важное для того, чтобы иметь ссылку на себя. Ресурсом может быть ссылка, карта города, статья в энциклопедии об осьминоге, случайное число больше 100 и меньше 323.
То, что делает, ресурс ресурсом – это наличие хотя бы одного адреса. Если у ресурса нет адреса и к нему нельзя обратиться, значит это не ресурс, а просто набор данных, битов, который описывает какой-то другой ресурс.
Адрес
Адрес – это имя ресурса, его местоположение. Ресурс может иметь несколько адресов, от одного и больше.
В вебе, у нас есть своей название для адреса – URL, universal resource locator.
Представление ресурса (representation)
Стоит различать ресурс и его представление. Ресурс – это некоторая идея то, что находится.
Когда пользователь заходит на страницу /shop, он получает не идею ресурса, а определенный набор байтов, данные – это и есть представление ресурса. Сервер может по запросу /shop вернуть набор товаров в этом магазине, а может вернуть изображение этого магазина на карте.
Представление ресурса – это информация о текущем состоянии ресурса.
Информация о том какое представление следует выбрать, если их доступно несколько, может находится как и в адресе ресурса (например, если это страница в журнале, /article.en указывает на английскую версию, /article.ru – на русскую), так и зависеть от контекста запроса (в этом примере, клиент посылает http-заголовок о том, где он находится и какой язык предпочитает)
Принципы REST (поподробнее)
Addressability
Наличие адреса, который может сохранить, обратится по нему к ресурсу – это самое большое благо. Это может показаться тривиально, но даже такие монстры как Гугл не всегда следует этому правило.
Возьмем к пример, Gmail. Так весь интерфейс построен на ajax’e, нет очевидной возможности обратится к некоторому письму напрямую по адресу. Поэтому для доступа к отдельному письму приходится заходить на Gmail и вручную выбирать его из списка. Если тебе позже понадобится это письмо, то придется проделывать все эти действия еще раз. Добавить ссылку на письмо в текстовый файл, в букмарки не выйдет, т.к. адреса нет.
Statelessness
Отсутствие состояния. Это означает, что любой запрос к ресурсу происходит в полной изоляции, т.к. как будто этот запрос был выполнен впервые. Запрос не зависит ни от каких данных из прошлых запросов. Все необходимая информация находится в теле запроса.
Connectedness
Наличие связей между ресурсами – огромный плюс. Если бы у ресурса не было бы связей, нам пришлось запомнить адреса ко всем ресурсам, правила по которым эти адреса создаются и так далее.
Приведу пример. Представим, что было бы если Google Maps не возвращал кнопок “вверх-вниз”, “влево-вправо”, “увеличить-уменьшить”. Единственный способ навигации для пользователя – это запоминать текущую широту и долготу и вручную править градусы левее или правее, чтобы увидеть следующий участок на карте. Вряд ли бы таким сервисом кто-то пользовался.
Но если рассматривать не пользовательский веб, а веб-сервисы, которые созданы для компьютера, а не человека, то такая проблема будет довольно распространена.
Единый интерфейс
Единый интерфейс означает лишь то, что каждый ресурс использует одни и те же методы для доступа к своим данным. Причем важно не то, как эти методы называются, а то что они выполняют схожую функции независимо от ресурса.
В вебе, метод GET – означает получить представление об ресурсе. Было бы странно увидеть сайт, на которым с помощью GET’a удалялись статьи, а с помощью POST можно было увидеть ее представление. Со стандартным браузером таким сайтом было бы невозможно пользоваться, т.к. браузер рассчитывает получить представление с помощью метода GET, а с помощью POST – отправить команду на обновление или удаление.
Это все.
Все, что нужно знать про REST. Четыре понятия и четыре принципа. Конечно, еще много вопросов остается открытыми, но об этом поговорим потом.
P.S. На самом деле я хотел набросать себе небольшую подсказку, как распределить реальные данные по ресурсам, какие шаги нужно выполнить и так далее, и так далее, но об этом позже.