Оказывается celeryd загрузчик перекрывает стандартную logging конфигурацию для того чтобы облегчить жизнь разработчику.
Иинциатива конечно хорошая, однако для нас это было полной неожиданностью.
К счастью есть как минимум два способа изменить это поведение.
Быстрое, но не совсем полное решение это установить CELERYD_HIJACK_ROOT_LOGGER = False.
Чуть более сложное, но концептуально верное решение это использовать setup-logging хук/сигнал, который предоставляет Celery.
Ссылки:
In 2.1 logging behavior was changed to not configure logging if it was
already configured. The problem is that some libraries does not play
nice and hijack the root logger, or use logging.basicConfig – resulting
in users not getting any output or logs.
http://readthedocs.org/docs/celery/en/release21-maint/changelog.html#version-2-1-4
By default any previously configured logging options will be reset, because the Celery programs “hijacks” the root logger.
If you want to customize your own logging then you can disable this behavior.
http://ask.github.com/celery/configuration.html#celeryd-hijack-root-logger
setup_logging signal.
Celery won’t configure the loggers if this signal is connected, so you can use this to completely override the logging configuration with your own.
http://ask.github.com/celery/userguide/signals.html#setup-logging
вторник, 13 декабря 2011 г.
воскресенье, 16 октября 2011 г.
SQLAlchemy for Python. Some queries examples including generated SQL
UPDATE on 2011-10-18. Ответил на некоторые комментарии прямо внизу поста.
Не так давно мне посчастливилось организовать technology validation самого продвинутого ORM-фреймверка для языка Python, который называется SQLAlchemy.
Признаюсь что перед стартом этого процесса я был достаточно скептически настроен, у меня была уверенность что я не увижу функционала, который бы хотя бы немного дотягивал до Java/Hibernate или .NET/NHibernate.
На моем последнем .NET-проекте, который назывался TravelConfirm, я предложил использовать NHibernate, о чем ни разу не жалею.
Более того, рекомендую всем сомневающимся внедрять его везде, где бы вы планировали использовать Entity Framework. NHibernate в связке с Fluent NHibernate прекрасно показали себя в работе с MySQL и Amazon RDS несмотря на то, что мы использовали в том числе и хранимые процедуры.
Но давайте вернемся к SQLAlchemy.
Статья на Wikipedia гласит что SQLAlchemy это open source SQL toolkit и object relational mapper, первый релиз которого был в феврале 2006-го года и что проект лицензируется под достаточно лояльной open source лицензией MIT.
http://en.wikipedia.org/wiki/SQLAlchemy
SQLAlchemy поддерживает довольно внушительный список СУБД, который в первом приближении сопоставим с таковым у Java/Hibernate:
Актуальную информацию по поддерживаемым диалектам можно увидеть тут:
http://www.sqlalchemy.org/docs/dialects/index.html
Еще одна особенность, которую я постояно наблюдаю в стеке Python, так это огромное изобилие библиотек, функциональность которых перекрывает, а иногда даже дублирует друг друга. Это вносит некоторую дополнительную головную боль разработчику, но это "правильная вещь". В рамках SQLAlchemy это выражается в том, что диалект каждой из представленных СУБД умеет работать поверх нескольких реализаций DB-API драйверов.
Например с MySQL я могу работать используя MySQL Connector/J, MySQL Connector/Python, mysql-python, OurSQL либо pymysql.
Подробную информацию о поддерживаемых диалектах и DB-API драйверах можно увидеть по следующей ссылке:
http://www.sqlalchemy.org/docs/core/engines.html#supported-databases
Думаю что вводной информации более чем достаточно, перейдем к делу. Ниже я буду приводить набор Python-тестов, которые используют ту или иную функциональность SQLAlchemy, сразу после кода теста будет приводится SQL запрос к SQLite базе, который генерирует SQLAlchemy.
Хочу сделать акцент на том, что SQLAlchemy меня просто поразил чистотой генерируемого SQL-кода, который часто превосходит даже такого титана как NHibernate. Код приводится как есть, я только лишь расставил переносы строк и отступы для лучшей читаемости - в оригинале все эти запросы формируются в несколько длинных строк. Точно так же как это делает NHibernate.
Нативный SQL-запроса с параметрами:
Извлечение пользователей с сортировкой по трем параметрам в разных направлениях:
Извлечение пользователя, который первым попался под руку:
Извлечение всех уникальных имен пользователей:
Использование традиционных агрегирующих функций:
Извлечение с группировкой:
Надуманный вариант с подзапросом вместо традиционного join'а:
Выборка данных с тремя inner join'ами:
Выборка данных с одним jeft outer join'ом:
Ограничение выборки используя методы limit и offset из querying DSL:
Ограничение выборки используя метод slice с двумя параметрами из querying DSL. Вероятно в каком-то из диалектов метод slice может быть более эффективен:
Объединение нескольких запросов через использование union:
Объединение нескольких запросов через использование union all:
Вот примерно так выглядят типичые запросы на SQLAlchemy. К счастью мои опасения были напрасны - SQLAlchemy прекрасно справляется с задачей, когда нужно произвести выборку данных из базы.
Более того, DSL для построения запросов в SQLAlchemy даже умеет ряд вещей, которых я не видел ни в NHibernate ни в Linq, а именно:
SQLAlchemy поддерживает три основных варианта мэппинга иерархии классов аналогично NHibernate, правда они используют немного другие термины.
У SQLAlchemy термины Single Table Inheritance, Joined Table Inheritance, Concrete Table Inheritance соответствуют терминам Table per class hierarchy, Table per subclass, Table per concrete class из NHibernate:
http://www.sqlalchemy.org/docs/orm/inheritance.html
Более детально ознакомится с функциональными возможностями и их использованием можно используя официальную документацию SQLAlchemy:
http://www.sqlalchemy.org/docs/
UPDATE on 2011-10-18. Ответил на некоторые комментарии прямо внизу поста.
> Что с Foreign Keys? (mapping/использование/генерируемый SQL)
GUID. Поддержка реализована в первую очередь для PostgreSQL, но она не сложная и может быть расширена для других СУБД:
http://www.sqlalchemy.org/docs/core/types.html#backend-agnostic-guid-type
GUID.Comb не поддерживается, так что если алгоритм очень нужен, то придется его портировать с NHibernate.
HiLo генератор так же не реализован. Есть пример кастомного генератора для database shards, где говорится что его можно использовать как прототип для HiLo генератора:
https://bitbucket.org/sqlalchemy/sqlalchemy/src/54ee83285eef/examples/sharding/attribute_shard.py
Post Insert генераторы не выделены явно, однако поддерживаются по-умолчанию. Identity, Guid.Native и любой другой генератор, который вычисляется на стороне БД декларируется одинаково:
http://www.sqlalchemy.org/docs/core/schema.html#server-side-defaults
Database Sequence генератор:
http://www.sqlalchemy.org/docs/core/schema.html#defining-sequences
Composite Primary Key генератор как частный случай Assigned Key генератора:
http://stackoverflow.com/questions/2374243/is-it-possible-to-get-sqlalchemy-to-create-a-composite-primary-key-with-an-integ
К сожалению привести примеры SQL не могу, так как для этого нужно делать тесты.
> 2nd layer cache (memcached)?
SQLAlchemy умеет работать поверх Beaker Caching, который отправляет NHibernate в тяжелый нокаут по количеству поддерживаемых cache-бекендов.
С другой стороны, SQLAlchemy предоставляет более явный Caching API, что одновременно и хорошо и плохо - все зависит от личных предпочтений:
http://www.sqlalchemy.org/docs/orm/examples.html#beaker-caching
> Подзапросы в NH не так красиво как в Py, но всё же
Если быть более точным, то поздапросы в NHibernate работают только при использовании QueryOver и недоступны в Linq.
> NHibernate {bulk/batching} на вскидку 2 варианта и с недавнего (3.2) времени дэфолтный:
Bulk insert и query batching это немного разные вещи. Насколько эффективно реализован query batching в SQLAlchemy сказать не могу. Но вот bulk insert в SQLAlchemy реализован удобно, просто и не зависит от СУБД. При этом NHibernate поддерживает bulk insert только у Microsoft SQL Server'а, поскольку эта функциональность упирается в возможности нижележащего ADO.NET Data Provider'а.
Не так давно мне посчастливилось организовать technology validation самого продвинутого ORM-фреймверка для языка Python, который называется SQLAlchemy.
Признаюсь что перед стартом этого процесса я был достаточно скептически настроен, у меня была уверенность что я не увижу функционала, который бы хотя бы немного дотягивал до Java/Hibernate или .NET/NHibernate.
На моем последнем .NET-проекте, который назывался TravelConfirm, я предложил использовать NHibernate, о чем ни разу не жалею.
Более того, рекомендую всем сомневающимся внедрять его везде, где бы вы планировали использовать Entity Framework. NHibernate в связке с Fluent NHibernate прекрасно показали себя в работе с MySQL и Amazon RDS несмотря на то, что мы использовали в том числе и хранимые процедуры.
Но давайте вернемся к SQLAlchemy.
Статья на Wikipedia гласит что SQLAlchemy это open source SQL toolkit и object relational mapper, первый релиз которого был в феврале 2006-го года и что проект лицензируется под достаточно лояльной open source лицензией MIT.
http://en.wikipedia.org/wiki/SQLAlchemy
SQLAlchemy поддерживает довольно внушительный список СУБД, который в первом приближении сопоставим с таковым у Java/Hibernate:
- Drizzle
- Firebird
- IBM DB2 / Informix
- MaxDB
- Microsoft Access
- Microsoft SQL Server
- MySQL
- Oracle
- PostgreSQL
- SQLite
- Sybase
Актуальную информацию по поддерживаемым диалектам можно увидеть тут:
http://www.sqlalchemy.org/docs/dialects/index.html
Еще одна особенность, которую я постояно наблюдаю в стеке Python, так это огромное изобилие библиотек, функциональность которых перекрывает, а иногда даже дублирует друг друга. Это вносит некоторую дополнительную головную боль разработчику, но это "правильная вещь". В рамках SQLAlchemy это выражается в том, что диалект каждой из представленных СУБД умеет работать поверх нескольких реализаций DB-API драйверов.
Например с MySQL я могу работать используя MySQL Connector/J, MySQL Connector/Python, mysql-python, OurSQL либо pymysql.
Подробную информацию о поддерживаемых диалектах и DB-API драйверах можно увидеть по следующей ссылке:
http://www.sqlalchemy.org/docs/core/engines.html#supported-databases
Думаю что вводной информации более чем достаточно, перейдем к делу. Ниже я буду приводить набор Python-тестов, которые используют ту или иную функциональность SQLAlchemy, сразу после кода теста будет приводится SQL запрос к SQLite базе, который генерирует SQLAlchemy.
Хочу сделать акцент на том, что SQLAlchemy меня просто поразил чистотой генерируемого SQL-кода, который часто превосходит даже такого титана как NHibernate. Код приводится как есть, я только лишь расставил переносы строк и отступы для лучшей читаемости - в оригинале все эти запросы формируются в несколько длинных строк. Точно так же как это делает NHibernate.
Нативный SQL-запроса с параметрами:
def test_query_with_from_native_sql_with_parameters(self):
with DbSession() as session:
result = session.query(User)\
.from_statement('SELECT * FROM user where name=:name')\
.params(name='User 4')\
.all()
Generated SQL:SELECT * FROM user where name=?
Извлечение пользователей с сортировкой по трем параметрам в разных направлениях:
def test_query_with_order_by_several_columns(self): with DbSession() as session: result = session.query(User)\ .order_by(User.password)\ .order_by(User.name.desc())\ .order_by(User.age)\ .all()Generated SQL:
SELECT user.user_id AS user_user_id, user.name AS user_name, user.age AS user_age, user.password AS user_password FROM user ORDER BY user.password, user.name DESC, user.age
Извлечение пользователя, который первым попался под руку:
def test_query_with_first(self): with DbSession() as session: result = session.query(User).first()Generated SQL:
SELECT user.user_id AS user_user_id, user.name AS user_name, user.age AS user_age, user.password AS user_password FROM user LIMIT ? OFFSET ?
Извлечение всех уникальных имен пользователей:
def test_query_with_distinct(self): with DbSession() as session: result = session.query(User.name).distinct().all()Generated SQL:
SELECT DISTINCT user.name AS user_name FROM user
Использование традиционных агрегирующих функций:
def test_query_with_max_min_avg_count(self): with DbSession() as session: max_user_age = session.query(func.max(User.age)).scalar() min_user_age = session.query(func.min(User.age)).scalar() avg_user_age = session.query(func.avg(User.age)).scalar() count_user_age = session.query(func.count(User.age)).scalar()Generated SQL:
SELECT max(user.age) AS max_1 FROM user SELECT min(user.age) AS min_1 FROM user SELECT avg(user.age) AS avg_1 FROM user SELECT count(user.age) AS count_1 FROM user
Извлечение с группировкой:
def test_query_with_group_by(self):
with DbSession() as session:
result = session.query(User.name, func.count(User.user_id))\
.group_by(User.name)\
.all()
Generated SQL:SELECT user.name AS user_name, count(user.user_id) AS count_1 FROM user GROUP BY user.name
Надуманный вариант с подзапросом вместо традиционного join'а:
def test_query_with_subquery(self): with DbSession() as session: subquery = session.query(User.name).filter(User.age > 21).subquery() result = session.query(Developer).join(subquery, subquery.c.name == Developer.name).all()Generated SQL:
SELECT developer.developer_id AS developer_developer_id, developer.name AS developer_name FROM developer JOIN (SELECT user.name AS name FROM user WHERE user.age > ?) AS anon_1 ON anon_1.name = developer.name
Выборка данных с тремя inner join'ами:
def test_query_which_join_three_tables(self): with DbSession() as session: result = session.query(User, Developer, Parent)\ .join(Developer, Developer.name == User.name)\ .join(Parent, Developer.name == Parent.name)\ .all()Generated SQL:
SELECT user.user_id AS user_user_id, user.name AS user_name, user.age AS user_age, user.password AS user_password, developer.developer_id AS developer_developer_id, developer.name AS developer_name, parent.parent_id AS parent_parent_id, parent.name AS parent_name FROM user JOIN developer ON developer.name = user.name JOIN parent ON developer.name = parent.name
Выборка данных с одним jeft outer join'ом:
def test_query_with_left_outer_join(self): with DbSession() as session: result = session.query(Developer, Parent)\ .outerjoin(Parent, Parent.name == Developer.name)\ .all()Generated SQL:
SELECT developer.developer_id AS developer_developer_id, developer.name AS developer_name, parent.parent_id AS parent_parent_id, parent.name AS parent_name FROM developer LEFT OUTER JOIN parent ON parent.name = developer.name
Ограничение выборки используя методы limit и offset из querying DSL:
def test_query_with_limit_offset(self): with DbSession() as session: result = session.query(User).order_by(User.name).limit(1).offset(1).all()Generated SQL:
SELECT user.user_id AS user_user_id, user.name AS user_name, user.age AS user_age, user.password AS user_password FROM user ORDER BY user.name LIMIT ? OFFSET ?
Ограничение выборки используя метод slice с двумя параметрами из querying DSL. Вероятно в каком-то из диалектов метод slice может быть более эффективен:
def test_query_with_slice(self): with DbSession() as session: result = session.query(User).order_by(User.name).slice(start=1, stop=2).all()Generated SQL:
SELECT user.user_id AS user_user_id, user.name AS user_name, user.age AS user_age, user.password AS user_password FROM user ORDER BY user.name LIMIT ? OFFSET ?
Объединение нескольких запросов через использование union:
def test_query_with_union_selects_distinct_records(self): with DbSession() as session: query1 = session.query(User.name) query2 = session.query(Developer.name) query3 = session.query(Parent.name) result = query1.union(query2, query3).all()Generated SQL:
SELECT anon_1.user_name AS anon_1_user_name FROM (SELECT user.name AS user_name FROM user UNION SELECT developer.name AS developer_name FROM developer UNION SELECT parent.name AS parent_name FROM parent) AS anon_1
Объединение нескольких запросов через использование union all:
def test_query_with_union_all(self): with DbSession() as session: query1 = session.query(User.name,) query2 = session.query(Developer.name) query3 = session.query(Parent.name) result = query1.union_all(query2, query3).all()Generated SQL:
SELECT anon_1.user_name AS anon_1_user_name FROM (SELECT user.name AS user_name FROM user UNION ALL SELECT developer.name AS developer_name FROM developer UNION ALL SELECT parent.name AS parent_name FROM parent) AS anon_1
Вот примерно так выглядят типичые запросы на SQLAlchemy. К счастью мои опасения были напрасны - SQLAlchemy прекрасно справляется с задачей, когда нужно произвести выборку данных из базы.
Более того, DSL для построения запросов в SQLAlchemy даже умеет ряд вещей, которых я не видел ни в NHibernate ни в Linq, а именно:
- подзапросы
- предложения UNION, UNION ALL, EXCEPT, EXCEPT ALL, INTERSECT, INTERSECT ALL, HAVING, CASE
- indexing hint'ы
- bulk insert для любой СУБД (у NHibernate есть ограниченные возможности, причем работают только в Microsoft SQL Server)
- bulk update/delete. При этом database session/unit of work не трекает изменений, но не смотря на это такая функциональность бывает нужна приложению
SQLAlchemy поддерживает три основных варианта мэппинга иерархии классов аналогично NHibernate, правда они используют немного другие термины.
У SQLAlchemy термины Single Table Inheritance, Joined Table Inheritance, Concrete Table Inheritance соответствуют терминам Table per class hierarchy, Table per subclass, Table per concrete class из NHibernate:
http://www.sqlalchemy.org/docs/orm/inheritance.html
Более детально ознакомится с функциональными возможностями и их использованием можно используя официальную документацию SQLAlchemy:
http://www.sqlalchemy.org/docs/
UPDATE on 2011-10-18. Ответил на некоторые комментарии прямо внизу поста.
> Что с Foreign Keys? (mapping/использование/генерируемый SQL)
GUID. Поддержка реализована в первую очередь для PostgreSQL, но она не сложная и может быть расширена для других СУБД:
http://www.sqlalchemy.org/docs/core/types.html#backend-agnostic-guid-type
GUID.Comb не поддерживается, так что если алгоритм очень нужен, то придется его портировать с NHibernate.
HiLo генератор так же не реализован. Есть пример кастомного генератора для database shards, где говорится что его можно использовать как прототип для HiLo генератора:
https://bitbucket.org/sqlalchemy/sqlalchemy/src/54ee83285eef/examples/sharding/attribute_shard.py
Post Insert генераторы не выделены явно, однако поддерживаются по-умолчанию. Identity, Guid.Native и любой другой генератор, который вычисляется на стороне БД декларируется одинаково:
http://www.sqlalchemy.org/docs/core/schema.html#server-side-defaults
Database Sequence генератор:
http://www.sqlalchemy.org/docs/core/schema.html#defining-sequences
Composite Primary Key генератор как частный случай Assigned Key генератора:
http://stackoverflow.com/questions/2374243/is-it-possible-to-get-sqlalchemy-to-create-a-composite-primary-key-with-an-integ
К сожалению привести примеры SQL не могу, так как для этого нужно делать тесты.
> 2nd layer cache (memcached)?
SQLAlchemy умеет работать поверх Beaker Caching, который отправляет NHibernate в тяжелый нокаут по количеству поддерживаемых cache-бекендов.
С другой стороны, SQLAlchemy предоставляет более явный Caching API, что одновременно и хорошо и плохо - все зависит от личных предпочтений:
http://www.sqlalchemy.org/docs/orm/examples.html#beaker-caching
> Подзапросы в NH не так красиво как в Py, но всё же
Если быть более точным, то поздапросы в NHibernate работают только при использовании QueryOver
> NHibernate {bulk/batching} на вскидку 2 варианта и с недавнего (3.2) времени дэфолтный:
Bulk insert и query batching это немного разные вещи. Насколько эффективно реализован query batching в SQLAlchemy сказать не могу. Но вот bulk insert в SQLAlchemy реализован удобно, просто и не зависит от СУБД. При этом NHibernate поддерживает bulk insert только у Microsoft SQL Server'а, поскольку эта функциональность упирается в возможности нижележащего ADO.NET Data Provider'а.
пятница, 30 сентября 2011 г.
Кто собирал Twisted для Python под Windows 64 bit?
Фух. Сегодня выдался нелегкий денек...
Оказалось что фреймверк Twisted не собран под Windows 64. Пробовали MinGW, потом MinGW 64, потом Cygwin, потом MSVC. К сожалению пока так ничего и не получилось :(
Ознакомились с модулем logging. Нашли библиотеку которая позволит отправлять логи на нашу любимую Log2Console в формате log4j XML.
Продолжали разбираться с SQLAlchemy ORM фреймверком. Оказывается он умеет делать bulk delete/update, чего не умеет делать даже NHibernate.
В понедельник еще попробую помучать Twisted, есть еще одна идея как его собрать под Windows 64 bit...
Если удастся собрать, то тогда будет возможность посмотреть на Python logging server, собственно ради него и затеяли эту возню с Twisted :)
Оказалось что фреймверк Twisted не собран под Windows 64. Пробовали MinGW, потом MinGW 64, потом Cygwin, потом MSVC. К сожалению пока так ничего и не получилось :(
Ознакомились с модулем logging. Нашли библиотеку которая позволит отправлять логи на нашу любимую Log2Console в формате log4j XML.
Продолжали разбираться с SQLAlchemy ORM фреймверком. Оказывается он умеет делать bulk delete/update, чего не умеет делать даже NHibernate.
В понедельник еще попробую помучать Twisted, есть еще одна идея как его собрать под Windows 64 bit...
Если удастся собрать, то тогда будет возможность посмотреть на Python logging server, собственно ради него и затеяли эту возню с Twisted :)
среда, 28 сентября 2011 г.
Извлечение файлов из .msi архивов
По определенным причинам я очень не люблю инсталляционные пакеты в Windows и предпочитаю работать с софтом в режиме "распаковал и запустил".
Долгое время использовал прием описанный в этой статье:
Howto: extract files from a .msi file using the Windows command line
Однако с помощью этой команды в некоторых случаях мне не удавалось распаковать файлы из .msi архива.
Сегодня читая комментарии на StackOverflow наткнулся на проект lessmsi.
Пост на StackOverflow:
how can I manually install the Office 2007 PIAs on a computer with no Office installed?
lessmsi - A tool to view and extract the contents of an Windows Installer (.msi) file:
http://code.google.com/p/lessmsi/
Пока не пробовал его в работе, но подумал, вдруг кому пригодится.
Долгое время использовал прием описанный в этой статье:
Howto: extract files from a .msi file using the Windows command line
Однако с помощью этой команды в некоторых случаях мне не удавалось распаковать файлы из .msi архива.
Сегодня читая комментарии на StackOverflow наткнулся на проект lessmsi.
Пост на StackOverflow:
how can I manually install the Office 2007 PIAs on a computer with no Office installed?
lessmsi - A tool to view and extract the contents of an Windows Installer (.msi) file:
http://code.google.com/p/lessmsi/
Пока не пробовал его в работе, но подумал, вдруг кому пригодится.
четверг, 8 сентября 2011 г.
Погружаясь в разработку на Python...
Последнее время промышляю написанием скриптов, которые автоматиризуют различные рутиные операции:
- правка файлов AssemblyInfo.cs с целью внесения build number, git branch name, git commit hash
- компиляция Visual Studio 2010 solution с проектами на C#/.NET 4.0
- анализ кода с помощью утилиты Gendarme
- подготовка deployment архивов, в которые складываем все бинарники за исключением XML-файлов с документационными комментариями, временных файлов, лог-файлов
- сбор всех тикетов Redmine для текущего билда и внесение соответсвующего комментария в каждый из этих тикетов
Планирую еще добавить запуск NUnit тестов в связке с PartCover, подготовку Test Code Coverage отчета в HTML-формате.
Сейчас Code Coverage метрики мы вообще не собираем - никак не дойдут руки добавить, а запуск NUnit тестов для нас делает TeamCity.
Хочу прийти к тому чтобы разработчик или QA имел возможность локально запустить билд скрипт, который бы выполнил всю ту же работу, которая происходит на CI-сервере TeamCity.
Какое-то время я размышял об инструменте, который можно использовать для этих целей и в итоге остановился на CPython.
Среди кандидатов еще рассматривались Cygwin + Bash, PowerShell, IronRuby + Rake, IronPython.
Cygwin + Bach кроссплатформенные, однако язык Bash за счет своей долгой истории развития выглядит достаточно несогласованным в плане синтаксиса. На нем не очень удобно писать императивный код и я не видел чтобы кто-то использовал там дебаггер.
PowerShell напротив, отличается очень хорошей синтаксической согласованностью. У этого языка отличная интеграция с платформой Windows и .NET, что для меня как .NET разработчика неоспоримое преимущество. К тому же мне удалось найти редактор скриптов с отладчиком. Но все таки мне хотелось иметь возможность писать императивный код средней сложности, который был бы кроссплатформенным.
IronRuby + Rake можно расценивать как готовую билд систему с хорошим императивным языком. Если бы у меня не было работы с язком Pyhton, то, возможно, я бы выбрал именно этот вариант.
Python думаю не нужен в особой рекламе. Достаточно сказать что я его выбрал :) Ну а если серьезно, язык я выбрал для решения поставленных задач из-за того что он довольно популярен, решает задачи общего назначения, кросплатформенный, используется для разработки как Desktop так и Web-решений. Так же его используют для нетривиальных задач системного администрирования, которые не может "вытянуть" Bash. Наверное переломным для меня моментом была находка библиотеки Paver, которая судя по всему делает все то же, что и библиотека Rake.
На первых этапах разработка велась с использованием IronPython + paver + Visual Studio 2010 + Python Tools for Visual Studio 2010 beta, позже на CPython 2.7 + paver + concurrent.futures + lxml + Eclipse + PyDev. Сейчас присматриваюсь к среде разработки JetBrains PyCharm, хотя использование коммерческого продукта для подобных задач кажется расточительным.
По состоянию на сегодняшний день build/deplyment скрипты представляют из себя сборную солянку следующих библиотек:
- paver, BSD
- concurrent.futures, BSD
- lxml, BSD
- py-restkit, BSD
- simplejson, MIT
- http-parser, MIT
Так же я обращал внимание на следующие библиотеки:
- GitPython, BSD, работает, но не понадобилась
- PyActiveResource, MIT, не подошла из-за функциональных ограничений
- python-rest-client, GPLv3, не пробовал из-за лицензионных ограничений
- правка файлов AssemblyInfo.cs с целью внесения build number, git branch name, git commit hash
- компиляция Visual Studio 2010 solution с проектами на C#/.NET 4.0
- анализ кода с помощью утилиты Gendarme
- подготовка deployment архивов, в которые складываем все бинарники за исключением XML-файлов с документационными комментариями, временных файлов, лог-файлов
- сбор всех тикетов Redmine для текущего билда и внесение соответсвующего комментария в каждый из этих тикетов
Планирую еще добавить запуск NUnit тестов в связке с PartCover, подготовку Test Code Coverage отчета в HTML-формате.
Сейчас Code Coverage метрики мы вообще не собираем - никак не дойдут руки добавить, а запуск NUnit тестов для нас делает TeamCity.
Хочу прийти к тому чтобы разработчик или QA имел возможность локально запустить билд скрипт, который бы выполнил всю ту же работу, которая происходит на CI-сервере TeamCity.
Какое-то время я размышял об инструменте, который можно использовать для этих целей и в итоге остановился на CPython.
Среди кандидатов еще рассматривались Cygwin + Bash, PowerShell, IronRuby + Rake, IronPython.
Cygwin + Bach кроссплатформенные, однако язык Bash за счет своей долгой истории развития выглядит достаточно несогласованным в плане синтаксиса. На нем не очень удобно писать императивный код и я не видел чтобы кто-то использовал там дебаггер.
PowerShell напротив, отличается очень хорошей синтаксической согласованностью. У этого языка отличная интеграция с платформой Windows и .NET, что для меня как .NET разработчика неоспоримое преимущество. К тому же мне удалось найти редактор скриптов с отладчиком. Но все таки мне хотелось иметь возможность писать императивный код средней сложности, который был бы кроссплатформенным.
IronRuby + Rake можно расценивать как готовую билд систему с хорошим императивным языком. Если бы у меня не было работы с язком Pyhton, то, возможно, я бы выбрал именно этот вариант.
Python думаю не нужен в особой рекламе. Достаточно сказать что я его выбрал :) Ну а если серьезно, язык я выбрал для решения поставленных задач из-за того что он довольно популярен, решает задачи общего назначения, кросплатформенный, используется для разработки как Desktop так и Web-решений. Так же его используют для нетривиальных задач системного администрирования, которые не может "вытянуть" Bash. Наверное переломным для меня моментом была находка библиотеки Paver, которая судя по всему делает все то же, что и библиотека Rake.
На первых этапах разработка велась с использованием IronPython + paver + Visual Studio 2010 + Python Tools for Visual Studio 2010 beta, позже на CPython 2.7 + paver + concurrent.futures + lxml + Eclipse + PyDev. Сейчас присматриваюсь к среде разработки JetBrains PyCharm, хотя использование коммерческого продукта для подобных задач кажется расточительным.
По состоянию на сегодняшний день build/deplyment скрипты представляют из себя сборную солянку следующих библиотек:
- paver, BSD
- concurrent.futures, BSD
- lxml, BSD
- py-restkit, BSD
- simplejson, MIT
- http-parser, MIT
Так же я обращал внимание на следующие библиотеки:
- GitPython, BSD, работает, но не понадобилась
- PyActiveResource, MIT, не подошла из-за функциональных ограничений
- python-rest-client, GPLv3, не пробовал из-за лицензионных ограничений
среда, 17 августа 2011 г.
Цитаты из книги "Программист-прагматик. Путь от подмастерья к мастеру"
На прошлой неделе закончил читать книгу Эндрю Ханта и Дэвида Томаса "Программист-прагматик. Путь от подмастерья к мастеру".
Читал книгу в формате FictionBook на своем смартфоме Samsung Galaxy S с помощью замечательной программы-читалки Cool Reader.
Впечатления очень положительные. Изложение в книге не сложное, так как там практически отсутствуют точные технические сведения, как это часто бывает в нашей технической литературе.
Авторы раскрывают скорее принципы, которыми должен руководствоваться любой программист в своей повседневной работе.
Крайне рекомендую прочитать эту книгу любому программисту, независимо от его уровня. Начинающий разработчик найдет для себя целый срез полезных знаний, опытный разработчик также с очень большой вероятностью найдет для себя что-то новое.
Лично мне читать эту книгу было крайне легко, так как большую часть вещей изложенных в книге я уже использую в своей повседнемной работе. Очень понравилась компактность изложения и столь большое количество системных советов, которыми могут руководствоваться разработчики независимо от их профиля и выбранной платформы.
Ниже привожу цитаты из книги, которые мне понравились.
(Об управлении временем жизни у зависимых объектов)
Есть три основных варианта развития событий:
1. Структура верхнего уровня также несет ответственность за освобождение любых входящих в нее подструктур. Затем эти структуры рекурсивно удалят данные, содержащиеся в них, и т. д.
2. Структура верхнего уровня просто освобождается. Любые структуры, на которые она указывает (и на которых нет других ссылок), становятся "осиротевшими".
3. Структура верхнего уровня отказывается освобождать себя, если в нее входят какие-либо подструктуры
Хотя принцип "модель-визуальное представление-контроллер" обычно реализуется в контексте графического интерфейса, на самом деле он является универсальной методикой программирования. Визуальное представление – это некая интерпретация модели (возможно, подмножества), и она не обязана быть графической. Контроллер в большей части является механизмом координации и не должен ассоциироваться с устройством ввода любого типа.
Подсказка 24: Занимайтесь устранением проблемы, а не обвинениями
Программное обеспечение работает несколько по-иному. В отличие от строительства, написание программ ближе к садоводству, оно ближе к живой природе, чем к бетонным конструкциям. Вы высаживаете в саду множество растений согласно первоначальному плану и условиям. Некоторые растения разрастаются, другим же уготована компостная яма. Вы можете пересаживать растения друг относительно друга, чтобы извлечь пользу из взаимодействия света и тени, ветра и дождя. Переросшие растения разрубают или обрезают, растения определенного цвета пересаживают на другие участки, где они становятся более приятными глазу с точки зрения эстетики. Вы выпалываете сорняки и подкармливаете растения, которые нуждаются в дополнительном питании. Вы постоянно следите за состоянием сада и при необходимости вносите изменения (в почву, растения, общий план)
Метафора садоводства намного ближе к реальности разработки программного обеспечения. Возможно, некая программа переросла себя или пытается осуществить слишком много – ее необходимо разбить на две. Все, что не получается в соответствии с планом, подлежит прополке или обрезке.
Попробуйте объяснить этот принцип вашему шефу, пользуясь аналогией с медициной: рассматривайте программу, нуждающуюся в реорганизации,реорганизации, как «опухоль». Чтобы удалить ее, требуется хирургическое вмешательство. Вы можете начать сразу и извлечь ее, пока она небольшая. Но если вы будете ждать, пока она вырастет и распространится, то ее удаление станет более дорогой и опасной процедурой. Подождите еще, и вы можете потерять пациента окончательно.
Многие книги и учебные пособия относят процедуру сбора исходных требований к начальной фазе проекта. Термин «сбор» напоминает о племени счастливых аналитиков, занимающихся собирательством камней-самородков мудрости, разбросанных по земле на фонеприглушенного звучания "Пасторальной симфонии". Этот термин напоминает о том, что все требования уже имеются в наличии, нужно лишь отыскать их, положить в корзину и весело шагать дальше.
Это не совсем так. Требования редко лежат на поверхности. Обычно они находятся глубоко под толщей предположений, неверных представлений и политики.
Важно обнаружить основополагающую причину того, почему пользователи поступают определенным образом, а не так, как они привыкли это делать. В конечном итоге разрабатываемой программе придется решать проблемы их бизнеса, а не просто отвечать их заявленным требованиям.
Вы отклонились от графика выполнения проекта или уже отчаялись увидеть систему работающей, поскольку конкретную проблему "невозможно решить". В этот момент необходимо сделать шаг назад и задать себе несколько вопросов:
• Существует ли более простой способ?
• Вы пытаетесь решить главную проблему или отвлекаетесь на второстепенные технические детали?
• Почему это является проблемой?
• Что делает эту проблему столь сложной для решения?
• Стоит ли делать это именно таким образом?
• Стоит ли это делать вообще?
И во многих случаях секрет удивительным образом раскроется перед вами, как только вы попробуете ответить на один из этих вопросов.
Подсказка 59: Дорогие инструменты не всегда создают лучшие решения
Конечно, в разработке программ есть место формальным методам. Однако, столкнувшись с проектом, философия которого заключается в изречении "диаграмма класса и есть приложение, все остальное – лишь механическое составление текста программы", знайте, что имеете дело с проектной командой, которая уцепилась за плавучее бревно и медленно гребет к берегу.
В группе L Стоффел руководит шестью первоклассными программистами – это руководящая работа, которую можно приравнять к управлению бродячими котами.
Журнал "Washington Post" от 9 июня 1985 г.
Подсказка 66: Дефект должен обнаруживаться единожды
Если дефект проскальзывает через сеть существующих тестов, вам необходимо добавить новый тест, чтобы поймать его в следующий раз.
В абстрактном смысле приложение успешно, если оно корректно реализует свои спецификации. К сожалению, это и оплачивается лишь абстрактно.
В действительности успех проекта измеряется тем, насколько он соответствует надеждам своих пользователей. Проект, не оправдавший их надежд, обречен на неудачу, неважно, насколько хорошо он соответствовал срокам.
Программисты-прагматики не уклоняются от ответственности. Вместо этого они испытывают радость, принимая вызовы и распространяя свой опыт. Если мы несем ответственность за проектное решение или фрагмент программы, мы делаем работу, которой можем гордиться.
Читал книгу в формате FictionBook на своем смартфоме Samsung Galaxy S с помощью замечательной программы-читалки Cool Reader.
Впечатления очень положительные. Изложение в книге не сложное, так как там практически отсутствуют точные технические сведения, как это часто бывает в нашей технической литературе.
Авторы раскрывают скорее принципы, которыми должен руководствоваться любой программист в своей повседневной работе.
Крайне рекомендую прочитать эту книгу любому программисту, независимо от его уровня. Начинающий разработчик найдет для себя целый срез полезных знаний, опытный разработчик также с очень большой вероятностью найдет для себя что-то новое.
Лично мне читать эту книгу было крайне легко, так как большую часть вещей изложенных в книге я уже использую в своей повседнемной работе. Очень понравилась компактность изложения и столь большое количество системных советов, которыми могут руководствоваться разработчики независимо от их профиля и выбранной платформы.
Ниже привожу цитаты из книги, которые мне понравились.
(Об управлении временем жизни у зависимых объектов)
Есть три основных варианта развития событий:
1. Структура верхнего уровня также несет ответственность за освобождение любых входящих в нее подструктур. Затем эти структуры рекурсивно удалят данные, содержащиеся в них, и т. д.
2. Структура верхнего уровня просто освобождается. Любые структуры, на которые она указывает (и на которых нет других ссылок), становятся "осиротевшими".
3. Структура верхнего уровня отказывается освобождать себя, если в нее входят какие-либо подструктуры
Хотя принцип "модель-визуальное представление-контроллер" обычно реализуется в контексте графического интерфейса, на самом деле он является универсальной методикой программирования. Визуальное представление – это некая интерпретация модели (возможно, подмножества), и она не обязана быть графической. Контроллер в большей части является механизмом координации и не должен ассоциироваться с устройством ввода любого типа.
Подсказка 24: Занимайтесь устранением проблемы, а не обвинениями
Программное обеспечение работает несколько по-иному. В отличие от строительства, написание программ ближе к садоводству, оно ближе к живой природе, чем к бетонным конструкциям. Вы высаживаете в саду множество растений согласно первоначальному плану и условиям. Некоторые растения разрастаются, другим же уготована компостная яма. Вы можете пересаживать растения друг относительно друга, чтобы извлечь пользу из взаимодействия света и тени, ветра и дождя. Переросшие растения разрубают или обрезают, растения определенного цвета пересаживают на другие участки, где они становятся более приятными глазу с точки зрения эстетики. Вы выпалываете сорняки и подкармливаете растения, которые нуждаются в дополнительном питании. Вы постоянно следите за состоянием сада и при необходимости вносите изменения (в почву, растения, общий план)
Метафора садоводства намного ближе к реальности разработки программного обеспечения. Возможно, некая программа переросла себя или пытается осуществить слишком много – ее необходимо разбить на две. Все, что не получается в соответствии с планом, подлежит прополке или обрезке.
Попробуйте объяснить этот принцип вашему шефу, пользуясь аналогией с медициной: рассматривайте программу, нуждающуюся в реорганизации,реорганизации, как «опухоль». Чтобы удалить ее, требуется хирургическое вмешательство. Вы можете начать сразу и извлечь ее, пока она небольшая. Но если вы будете ждать, пока она вырастет и распространится, то ее удаление станет более дорогой и опасной процедурой. Подождите еще, и вы можете потерять пациента окончательно.
Многие книги и учебные пособия относят процедуру сбора исходных требований к начальной фазе проекта. Термин «сбор» напоминает о племени счастливых аналитиков, занимающихся собирательством камней-самородков мудрости, разбросанных по земле на фонеприглушенного звучания "Пасторальной симфонии". Этот термин напоминает о том, что все требования уже имеются в наличии, нужно лишь отыскать их, положить в корзину и весело шагать дальше.
Это не совсем так. Требования редко лежат на поверхности. Обычно они находятся глубоко под толщей предположений, неверных представлений и политики.
Важно обнаружить основополагающую причину того, почему пользователи поступают определенным образом, а не так, как они привыкли это делать. В конечном итоге разрабатываемой программе придется решать проблемы их бизнеса, а не просто отвечать их заявленным требованиям.
Вы отклонились от графика выполнения проекта или уже отчаялись увидеть систему работающей, поскольку конкретную проблему "невозможно решить". В этот момент необходимо сделать шаг назад и задать себе несколько вопросов:
• Существует ли более простой способ?
• Вы пытаетесь решить главную проблему или отвлекаетесь на второстепенные технические детали?
• Почему это является проблемой?
• Что делает эту проблему столь сложной для решения?
• Стоит ли делать это именно таким образом?
• Стоит ли это делать вообще?
И во многих случаях секрет удивительным образом раскроется перед вами, как только вы попробуете ответить на один из этих вопросов.
Подсказка 59: Дорогие инструменты не всегда создают лучшие решения
Конечно, в разработке программ есть место формальным методам. Однако, столкнувшись с проектом, философия которого заключается в изречении "диаграмма класса и есть приложение, все остальное – лишь механическое составление текста программы", знайте, что имеете дело с проектной командой, которая уцепилась за плавучее бревно и медленно гребет к берегу.
В группе L Стоффел руководит шестью первоклассными программистами – это руководящая работа, которую можно приравнять к управлению бродячими котами.
Журнал "Washington Post" от 9 июня 1985 г.
Подсказка 66: Дефект должен обнаруживаться единожды
Если дефект проскальзывает через сеть существующих тестов, вам необходимо добавить новый тест, чтобы поймать его в следующий раз.
В абстрактном смысле приложение успешно, если оно корректно реализует свои спецификации. К сожалению, это и оплачивается лишь абстрактно.
В действительности успех проекта измеряется тем, насколько он соответствует надеждам своих пользователей. Проект, не оправдавший их надежд, обречен на неудачу, неважно, насколько хорошо он соответствовал срокам.
Программисты-прагматики не уклоняются от ответственности. Вместо этого они испытывают радость, принимая вызовы и распространяя свой опыт. Если мы несем ответственность за проектное решение или фрагмент программы, мы делаем работу, которой можем гордиться.
воскресенье, 20 марта 2011 г.
Сегодня Windows 7 довел меня до белого каления
На системном разделе моего ноутбука объем которого составляет 25 Гб (!) нехватает свободного места. Точнее там тупо ноль байт. Из-за этого масса проблем.
В качестве решения проблемы решил перенести c:\Program Files\ и c:\Program Files (x86)\ на другой раздел и сделать Junction Point.
Скопировал все содержимое, но теперь не могу удалить каталог и поменять права, даже с правами администратора.
Администратор не имеет права на удаление этого каталога, только TrustedInstaller и Local System имеет право удалить этот каталог.
Запустить cmd сессию от Local System аккаунта можно с помощью PsTools\PsExec. Но они не работают из-за какого-то дефекта в 64-редакции Windows 7.
Есть хотфик, который решает эту проблему, но чтобы его скачать нужно ввести свой email и капчу. Терпение на исходе.
На почтовый ящик пришло письмо с прямой ссылкой и паролем. Скачал, распаковал. После чего получил сообщение что hotfix не может быть установлен.
Если посмотреть на проблему изначально - 25 Гб под системный раздел для ноутбука это много или мало по состоянию на 2011 год?
Чтобы картина была более ясна отмечу что в каталог c:\Users я не сохраняю никаких своих документов.
Весь установленный софт занимает не так уж и много места:
305 Мб - C:\Program Files\
441 Мб - C:\Program Files (x86)\
1,31 Гб - C:\soft\ причем этот каталог можно не считать, так как все данные лежат на другом разделе, а это Junction Point.
Иногда я жалею что я .NET разработчик, который зависит от операционной системы Windows.
Если бы я в повседневной работе использовал только кроссплатформенные решения, то у меня хотя бы был выбор...
Update: Удалось найти достаточно простое решение моей проблемы вот тут
http://helpdeskgeek.com/windows-7/windows-7-how-to-delete-files-protected-by-trustedinstaller/
В качестве решения проблемы решил перенести c:\Program Files\ и c:\Program Files (x86)\ на другой раздел и сделать Junction Point.
Скопировал все содержимое, но теперь не могу удалить каталог и поменять права, даже с правами администратора.
Администратор не имеет права на удаление этого каталога, только TrustedInstaller и Local System имеет право удалить этот каталог.
Запустить cmd сессию от Local System аккаунта можно с помощью PsTools\PsExec. Но они не работают из-за какого-то дефекта в 64-редакции Windows 7.
Есть хотфик, который решает эту проблему, но чтобы его скачать нужно ввести свой email и капчу. Терпение на исходе.
На почтовый ящик пришло письмо с прямой ссылкой и паролем. Скачал, распаковал. После чего получил сообщение что hotfix не может быть установлен.
Если посмотреть на проблему изначально - 25 Гб под системный раздел для ноутбука это много или мало по состоянию на 2011 год?
Чтобы картина была более ясна отмечу что в каталог c:\Users я не сохраняю никаких своих документов.
Весь установленный софт занимает не так уж и много места:
305 Мб - C:\Program Files\
441 Мб - C:\Program Files (x86)\
1,31 Гб - C:\soft\ причем этот каталог можно не считать, так как все данные лежат на другом разделе, а это Junction Point.
Иногда я жалею что я .NET разработчик, который зависит от операционной системы Windows.
Если бы я в повседневной работе использовал только кроссплатформенные решения, то у меня хотя бы был выбор...
Update: Удалось найти достаточно простое решение моей проблемы вот тут
http://helpdeskgeek.com/windows-7/windows-7-how-to-delete-files-protected-by-trustedinstaller/
суббота, 5 февраля 2011 г.
The very first .NET Saturday in IT Café_
Сегодня, пятого февраля сходил на событие, проходящее под эгидой компании Ciklum, которое называется .NET Saturday.
В большинстве случаев заметки в свой блог мне писать очень и очень лень, но тут решил написать буквально пару строк о прошедшем событии.
Формат события такой. В обычном, но довольно привлекательном кафе освобождают часть зала, в зоне которого находится докладчик, все слушатели сидят прямо за своими столиками и слушают доклад. Один за другим идет ряд докладов с 15-ти минутными перерывами между ними. В перерыве между докладами можно попить чаю, кофе, поесть печеньки или конфеты.
Были прочитаны следующие доклады:
- Александр Краковецкий (Винница, head of MS User Group) «Тестирование производительности .NET приложений»;
- Дмитрий Пасько (Харьков, Team Leader) «NuGet- package management for the .NET platform»;
- Андерс Соренсен (Дания, Site manager) «Optimizing development in an offshore context»;
- Михаил Вальков (Харьков, Senior .net developer) «Antipatterns»
Мероприятие продолжалось с 15:00 по 19:00 и количество времени выделенного на каждый доклад было достаточным.
Признаюсь, что решение идти на это мероприятие меня в первую очередь натолкнула тема первого доклада, хотя после окончания мероприятия лично для меня оказались самыми интересными доклад Дмитрия Пасько по NuGet и доклад Андерса Соренсена.
Искренне благодарю всех докладчиков за их труд и время. Это очень ценно, когда человек находит желание и силы поделиться своими знаниями с локальным сообществом. В этом отношении мне несколько стыдно, поскольку я бы наверное тоже мог бы поделиться определенными вещами с коллегами по работе в рамках того или иного доклада, но до сих пор я себя так и не смог заставить это сделать.
Хотелось бы еще отметить, что формат этого мероприятия мне крайне понравился. Его продолжительность была не маленькой, но при этом я ушел оттуда не уставшим, а может быть даже отдохнувшим. Возможность попить чаю прямо посередине прослушивания доклада, выйти на улицу в перерыв для того чтобы проветрить мозги – все это было очень кстати. Сами столики очень расслабляли и наталкивали на дискуссию, хотя я бы не отказался от более длинного перерыва, чтобы успеть и проветриться и успеть похоливарить с товарищами за столиком.
Компания Ciklum планирует проводить подобные мероприятия около одного раза в месяц по субботам. Если вы вдруг узнаете о данном мероприятии, то рекомендую на него сходить хотя бы один раз для пробы.
На всякий случай отмечу, что я не работаю в Ciklum и не имею к компании никакого отношения даже не смотря на то, что по моей «вине» на это мероприятие пришло пять моих товарищей. :) Ребята, надеюсь что вам там тоже понравилось.
В большинстве случаев заметки в свой блог мне писать очень и очень лень, но тут решил написать буквально пару строк о прошедшем событии.
Формат события такой. В обычном, но довольно привлекательном кафе освобождают часть зала, в зоне которого находится докладчик, все слушатели сидят прямо за своими столиками и слушают доклад. Один за другим идет ряд докладов с 15-ти минутными перерывами между ними. В перерыве между докладами можно попить чаю, кофе, поесть печеньки или конфеты.
Были прочитаны следующие доклады:
- Александр Краковецкий (Винница, head of MS User Group) «Тестирование производительности .NET приложений»;
- Дмитрий Пасько (Харьков, Team Leader) «NuGet- package management for the .NET platform»;
- Андерс Соренсен (Дания, Site manager) «Optimizing development in an offshore context»;
- Михаил Вальков (Харьков, Senior .net developer) «Antipatterns»
Мероприятие продолжалось с 15:00 по 19:00 и количество времени выделенного на каждый доклад было достаточным.
Признаюсь, что решение идти на это мероприятие меня в первую очередь натолкнула тема первого доклада, хотя после окончания мероприятия лично для меня оказались самыми интересными доклад Дмитрия Пасько по NuGet и доклад Андерса Соренсена.
Искренне благодарю всех докладчиков за их труд и время. Это очень ценно, когда человек находит желание и силы поделиться своими знаниями с локальным сообществом. В этом отношении мне несколько стыдно, поскольку я бы наверное тоже мог бы поделиться определенными вещами с коллегами по работе в рамках того или иного доклада, но до сих пор я себя так и не смог заставить это сделать.
Хотелось бы еще отметить, что формат этого мероприятия мне крайне понравился. Его продолжительность была не маленькой, но при этом я ушел оттуда не уставшим, а может быть даже отдохнувшим. Возможность попить чаю прямо посередине прослушивания доклада, выйти на улицу в перерыв для того чтобы проветрить мозги – все это было очень кстати. Сами столики очень расслабляли и наталкивали на дискуссию, хотя я бы не отказался от более длинного перерыва, чтобы успеть и проветриться и успеть похоливарить с товарищами за столиком.
Компания Ciklum планирует проводить подобные мероприятия около одного раза в месяц по субботам. Если вы вдруг узнаете о данном мероприятии, то рекомендую на него сходить хотя бы один раз для пробы.
На всякий случай отмечу, что я не работаю в Ciklum и не имею к компании никакого отношения даже не смотря на то, что по моей «вине» на это мероприятие пришло пять моих товарищей. :) Ребята, надеюсь что вам там тоже понравилось.
четверг, 2 сентября 2010 г.
Вышел Castle.Windsor (включая Core, DynamicProxy, DictionaryAdapter) версии 2.5
Ура товарищи.
Вышел стабильный релиз Castle.Windsor, который я со спокойной совестью теперь могу рекомендовать даже начинающим ЙОК-овцам (IoC, Inversion of Control).
В анонсе бета релиза была масса отличных новостей:
- объединили Castle.Core, Caste.DynamicProxy, Castle.DictionaryAdapter в Castle.Core
- объединили Castle.MicroKernel, Castle.Windsor в Castle.Windsor
- сделали ряд незначительных breaking changes (читал описание, там все очень экзотическое и редко используемое). Можно было бы более крепко пройтись по старому API
- весь устаревший API отметили как obsolete. До этого там была настоящая каша. Прямо как в Rhino.Mocks
Castle объединяет сборки, а (Microsoft) Unity декомпозирует. ...ребята которые пидалят Unity не ведают что творят :)
К счастью основная проблема с высоким порогом вхождения была решена - благодаря тому что методы были отмечены как obsolete, новички не будут выносить себе мозг в поисках того какие именно методы стоит использовать, а какие не стоит. Более того, разработчики обещают вообще удалить все obsolete методы в релизе 3.0.
До релиза 2.5, когда у меня спрашивали что лучше использовать в качестве IoC контейнера, я постоянно колебался в ответе. Обычно рекомендовал смотреть либо на Castle.Windsor либо на Autofac и говорил что если будут малейшие сложности с Castle.Windsor, то не морочить с ним долго голову.
Теперь же однозначно уверен что логичнее использовать Caslte.Windsor, а легкий Autofac стоит использовать только лишь в Silverlight проектах.
Пользуясь случаем приглашаю всех пользователей Caslte.Windsor "приложиться" к его улучшению, оставив свои предложения на фидбек сайте. Команда разработчиков реально прислушивается к пожеланиям их пользователей:
Provide more compact, discoverable fluent API
В качестве примера тут хорошо расписаны шаги миграции проекта S#arp Architecture на последнюю версию Castle.
Указывается как разрешить проблему зависимости NHibernate и Castle.Windsor на Castle.DynamicProxy, которая переехала в Castle.Core.
Описывается рефакторинг со старого API на новый API Castle.Windsor. Много внимания уделяется IWindsorInstaller, который мне очень понравился.
ЗЫ Да, я знаю что релиз как-бы вышел с пол месяца назад, но у меня таймауты... Уж простите :)
Вышел стабильный релиз Castle.Windsor, который я со спокойной совестью теперь могу рекомендовать даже начинающим ЙОК-овцам (IoC, Inversion of Control).
В анонсе бета релиза была масса отличных новостей:
- объединили Castle.Core, Caste.DynamicProxy, Castle.DictionaryAdapter в Castle.Core
- объединили Castle.MicroKernel, Castle.Windsor в Castle.Windsor
- сделали ряд незначительных breaking changes (читал описание, там все очень экзотическое и редко используемое). Можно было бы более крепко пройтись по старому API
- весь устаревший API отметили как obsolete. До этого там была настоящая каша. Прямо как в Rhino.Mocks
Castle объединяет сборки, а (Microsoft) Unity декомпозирует. ...ребята которые пидалят Unity не ведают что творят :)
К счастью основная проблема с высоким порогом вхождения была решена - благодаря тому что методы были отмечены как obsolete, новички не будут выносить себе мозг в поисках того какие именно методы стоит использовать, а какие не стоит. Более того, разработчики обещают вообще удалить все obsolete методы в релизе 3.0.
До релиза 2.5, когда у меня спрашивали что лучше использовать в качестве IoC контейнера, я постоянно колебался в ответе. Обычно рекомендовал смотреть либо на Castle.Windsor либо на Autofac и говорил что если будут малейшие сложности с Castle.Windsor, то не морочить с ним долго голову.
Теперь же однозначно уверен что логичнее использовать Caslte.Windsor, а легкий Autofac стоит использовать только лишь в Silverlight проектах.
Пользуясь случаем приглашаю всех пользователей Caslte.Windsor "приложиться" к его улучшению, оставив свои предложения на фидбек сайте. Команда разработчиков реально прислушивается к пожеланиям их пользователей:
Provide more compact, discoverable fluent API
В качестве примера тут хорошо расписаны шаги миграции проекта S#arp Architecture на последнюю версию Castle.
Указывается как разрешить проблему зависимости NHibernate и Castle.Windsor на Castle.DynamicProxy, которая переехала в Castle.Core.
Описывается рефакторинг со старого API на новый API Castle.Windsor. Много внимания уделяется IWindsorInstaller, который мне очень понравился.
ЗЫ Да, я знаю что релиз как-бы вышел с пол месяца назад, но у меня таймауты... Уж простите :)
среда, 11 августа 2010 г.
Полиглотное программирование в .NET это хорошо. История внедрения IronPython
Неплохая статья. Выгодно отличается трезвым взглядом человека-практика.
Признаюсь что читать все комментарии сил не нашел, но хотелось бы оставить одну галочку в Success Stories исключительно для статистики. :)
Уже несколько лет работаю на одном большом проекте в котором с самого начала присутствовал скриптинг.
Причем начиналось это все с написания скриптов общего назначения на NVelocity и это был сущий ад, поскольку Velocity ну никак не является скриптовым языком общего назначения.
Но это было время .NET 1.1, IronPython'а тогда еще не было, а нам нужна была возможность написания скриптов, которые бы вызывались во время отработки различных фабричных методов.
В какой-то момент мы нашли проект IronPython и начиная с версии 1.0 RC я был человеком, который "двигал" этот язык и передавал опыт работы другим командам внутри нашего проекта.
Все это происходило медленно, но верно. По ходу дела я переезжал с одного релиза на другой, решая разного рода проблемы взаимодействия C# и IronPython при хостинге DLR внутри C# приложения.
Вначале были переписаны скрипты с NVelocity на IronPython практически один-в-один. Разве что я старался скрипты представлять в более организованном, процедурном виде ну и использовать простейшие возможности языка.
Следующим этапом был постепенный перевод всех скриптов на более высокоуровневую объектную модель. Тут пришлось пройтись по некоторым не очевидным граблям, которые выплывали во время наследования абстрактных классов C# в типах, которые я реализовывал на языке Python.
В конечном счете теперь у нас на проекте появляется все больше и больше скриптов на IronPython, которые постепенно становятся все более "умными".
При этом, скажу что мы, как суровые челябинские разработчики, пишем без IntelliSense и без отладчика. Спасает то, что я разобрался как можно вытащить script stack trace. :)
В конечном счете я для себя сделал такой вывод:
Многоязыковость платформы .NET это однозначно хорошо, так как позволяет в определенных ситуациях находить отличные решения. И мне кажется что эта самая многоязыковость или даже "распыленность" Microsoft по C#/F#/VB.NET/IronPython/IronRuby вряд ли нанесет существенный вред платформе в целом и языку C# в частности.
Другое дело что от такого обилия языков программирования бедный разработчик теряется, но это уже проблемы этого разработчика. Кто-то пусть делает ставку на проверенную лошадку, кто-то пусть экспериментирует. Главное что всем хватает места и это очень радует.
Признаюсь что читать все комментарии сил не нашел, но хотелось бы оставить одну галочку в Success Stories исключительно для статистики. :)
Уже несколько лет работаю на одном большом проекте в котором с самого начала присутствовал скриптинг.
Причем начиналось это все с написания скриптов общего назначения на NVelocity и это был сущий ад, поскольку Velocity ну никак не является скриптовым языком общего назначения.
Но это было время .NET 1.1, IronPython'а тогда еще не было, а нам нужна была возможность написания скриптов, которые бы вызывались во время отработки различных фабричных методов.
В какой-то момент мы нашли проект IronPython и начиная с версии 1.0 RC я был человеком, который "двигал" этот язык и передавал опыт работы другим командам внутри нашего проекта.
Все это происходило медленно, но верно. По ходу дела я переезжал с одного релиза на другой, решая разного рода проблемы взаимодействия C# и IronPython при хостинге DLR внутри C# приложения.
Вначале были переписаны скрипты с NVelocity на IronPython практически один-в-один. Разве что я старался скрипты представлять в более организованном, процедурном виде ну и использовать простейшие возможности языка.
Следующим этапом был постепенный перевод всех скриптов на более высокоуровневую объектную модель. Тут пришлось пройтись по некоторым не очевидным граблям, которые выплывали во время наследования абстрактных классов C# в типах, которые я реализовывал на языке Python.
В конечном счете теперь у нас на проекте появляется все больше и больше скриптов на IronPython, которые постепенно становятся все более "умными".
При этом, скажу что мы, как суровые челябинские разработчики, пишем без IntelliSense и без отладчика. Спасает то, что я разобрался как можно вытащить script stack trace. :)
В конечном счете я для себя сделал такой вывод:
Многоязыковость платформы .NET это однозначно хорошо, так как позволяет в определенных ситуациях находить отличные решения. И мне кажется что эта самая многоязыковость или даже "распыленность" Microsoft по C#/F#/VB.NET/IronPython/IronRuby вряд ли нанесет существенный вред платформе в целом и языку C# в частности.
Другое дело что от такого обилия языков программирования бедный разработчик теряется, но это уже проблемы этого разработчика. Кто-то пусть делает ставку на проверенную лошадку, кто-то пусть экспериментирует. Главное что всем хватает места и это очень радует.
суббота, 3 апреля 2010 г.
Inversion of Control and Dependency Injection. Ссылки
Inversion of Control and Dependency Injection: Working with Windsor Container
http://msdn.microsoft.com/en-us/library/aa973811.aspx
Ознакомительная статья, раскрывающая основные концепции Inversion of Control и Dependency Injection, которую написал Oren Eini aka Ayende Rahien. Носит предельно практических характер. Достаточно много хорошего материала, все изложение идет в ключе разработки некоего приложения (или сервиса) по обработке заказов. Крайне рекомендую эту статью к прочтению.
Inversion of Control and Dependency Injection with Castle Windsor Container. Four Parts.
Цикл статей об использовании Inversion of Control и Dependency Injection с помощью популярного фреймверка Castle.Windsor.
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart1.aspx
Первая статья является вводной. Вначале статьи приводится пример кода в котором нарушается принцип разделения ответственности (Separation of concerns) и который написан без оглядки на Unit-тестирование. Затем приводится реализация кода с использованием принципа обращения зависимостей (Inversion of Control), а точнее с помощью Constuctor [Dependency] Injection. Вторая версия удобна с точки зрения тестирования, но не удобна в реальном использовании, так как клиент будет знать сразу о нескольких реальных типах. И заключительной части показывается использование IoC/DI контейнера, точнее его базовой части в виде Castle.MicroKernel API, а затем и в расширенной - Castle.Windsor.
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart2.aspx
Во второй части рассматриваются инъекция опциональных зависимостей (Property Injection), приводится пример инъекции конкретной реализации (имеет смысл, когда на один и тот же интерфейс может быть несколько реализаций). В конце статьи приводятся примеры декларативного Xml конфигурирования основных коллекций - Array, IList, IDictionary.
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart3.aspx
В третьей части показывается пример вынесения части конфигурации в отдельные разделы Xml конфигурации Castle.Windsor и включение этих параметров при декларировании сервисов. По простым примерам видно, насколько просто и одновременно мощно можно конфигурировать сервисы Castle.Windsor с помощью конфигурационного файла. Если нужно задать значение параметра, который имеет сложный пользовательский тип, то это можно сделать с помощью TypeConverter'а. Приводится, не совсем полезный пример реализации декоратора и его регистрации. Возможно это сделано для того чтобы потом можно было привести пример с define и if/else прямо внутри конфигурационного файла.
Всех описанных возможностей конфигруации хватит за глаза любому, даже самому энтерпрайзному приложению :)
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart4.aspx
В четвертой части описывается крайне важный материал - управление жизненным циклом сервисов внутри Castle.Windsor контейнера.
Любому, кто собирается работать с Caslte.Windsor стоит обязательно разобраться в том, что такое Lifestyle, Lifecycle, Commision/Decomission и Release Policy. Чтобы не было неожиданно неприятных ситуаций как со мной и Web-приложением на production сервере :)
Информация по Facility довольно полезна, но не так критична.
Building the Policy Injection in 40 Minutes with Windsor
http://ayende.com/Blog/archive/2007/03/07/Building-the-Policy-Injection-in-40-Minutes-with-Windsor.aspx
Реализация Policy Injection в виде Facility для Castle.Windsor. Типичный пример аспект-ориентированного программирования. Не знаю кто придумал термин Policy Injection, и что конкретно он обозначает, но когда мне говорят реализация аспекта (AOP), то я сразу понимаю о чем идет речь.
Caching with Castle Windsor
http://consultingblogs.emc.com/owainwragg/archive/2008/10/31/caching-with-castle-windsor.aspx
Реализация Facility, которая обеспечивает кеширование данных используя аспект-ориентированный подход. Очевидно, что с помощью IoC и AOP-подхода можно достаточно удобно решать такие вещи как Security, Logging, Caching.
The joys of Castle.Services.Transaction
http://www.jroller.com/hammett/entry/the_joys_of_castle_services
Описывается использование AutomaticTransactionFacility. Просто апофеоз декларативной attribute-driven разработки. Выглядит настолько необычно что я даже не знаю, стоит ли пытаться повторить это дома :) В любом случае идея невероятно креативная.
Hidden jewels in the Castle stack: Transaction Services
http://blogs.taiga.nl/martijn/2008/12/03/hidden-jewels-in-the-castle-stack-transaction-services
Прошу меня простить, но эта ссылка уже реальный оффтопик основной темы. В посте развивается идея сервиса транзакций из проекта Castle, только теперь транзакционность пытаются прикрутить уже к файловой системе...
List of .NET Dependency Injection Containers (IOC)
http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
Достаточно обширная подборка IoC контейнеров на платформе .NET от Scott Hanselman'а.
BitterCoder's Wiki. Container Tutorials
http://wiki.bittercoder.com/Default.aspx?Page=ContainerTutorials&AspxAutoDetectCookieSupport=1
Коллекция ссылок на туториалы по Castle.Windsor, в настоящее время представлено четырнадцать частей. Специфика этих туториалов заключается в том, что там в каждой части раскрывается только одна функциональная возможность библиотеки. Возможно для кого-то такой дробный формат изложения покажется удобным.
Внизу страницы приведена целая коллекция ссылок по рассматриваемой тематике на различные сторонние ресурсы.
Inject Some Life into Your Applications—Getting to Know the Unity Application Block
http://msdn.microsoft.com/en-us/library/cc816062.aspx
Вводная статья по Unity, IoC контейнеру, который разрабатывался силами Microsoft и затем был выпущен с открытым исходным кодом. Рассматриваются основные аспекты IoC контейнера. Все примеры кода приведены сразу на двух языках - C# и VB.NET.
IoC libraries compared
http://elegantcode.com/2009/01/07/ioc-libraries-compared/
Сравнение API у различных IoC контейнеров: Ninject, StructureMap, Unity, Spring.net, Castle.Windsor, Autofac. Следует принять во внимание что статья написана в январе 2009 года, а API каждого из перечисленный фреймверков постоянно совершенствуется.
Две простейшие реализации IoC контейнеров. По их реализации можно сделать вывод о том, какая основная задача ставится перед таким контейнером.
It's My Turn To Build An IoC Container In 15 Minutes and 33 Lines
http://www.kenegozi.com/Blog/2008/01/17/its-my-turn-to-build-an-ioc-container-in-15-minutes-and-33-lines.aspx
Building an IoC container in 15 lines of code
http://ayende.com/Blog/archive/2007/10/20/Building-an-IoC-container-in-15-lines-of-code.aspx
http://msdn.microsoft.com/en-us/library/aa973811.aspx
Ознакомительная статья, раскрывающая основные концепции Inversion of Control и Dependency Injection, которую написал Oren Eini aka Ayende Rahien. Носит предельно практических характер. Достаточно много хорошего материала, все изложение идет в ключе разработки некоего приложения (или сервиса) по обработке заказов. Крайне рекомендую эту статью к прочтению.
Inversion of Control and Dependency Injection with Castle Windsor Container. Four Parts.
Цикл статей об использовании Inversion of Control и Dependency Injection с помощью популярного фреймверка Castle.Windsor.
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart1.aspx
Первая статья является вводной. Вначале статьи приводится пример кода в котором нарушается принцип разделения ответственности (Separation of concerns) и который написан без оглядки на Unit-тестирование. Затем приводится реализация кода с использованием принципа обращения зависимостей (Inversion of Control), а точнее с помощью Constuctor [Dependency] Injection. Вторая версия удобна с точки зрения тестирования, но не удобна в реальном использовании, так как клиент будет знать сразу о нескольких реальных типах. И заключительной части показывается использование IoC/DI контейнера, точнее его базовой части в виде Castle.MicroKernel API, а затем и в расширенной - Castle.Windsor.
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart2.aspx
Во второй части рассматриваются инъекция опциональных зависимостей (Property Injection), приводится пример инъекции конкретной реализации (имеет смысл, когда на один и тот же интерфейс может быть несколько реализаций). В конце статьи приводятся примеры декларативного Xml конфигурирования основных коллекций - Array, IList
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart3.aspx
В третьей части показывается пример вынесения части конфигурации в отдельные разделы Xml конфигурации Castle.Windsor и включение этих параметров при декларировании сервисов. По простым примерам видно, насколько просто и одновременно мощно можно конфигурировать сервисы Castle.Windsor с помощью конфигурационного файла. Если нужно задать значение параметра, который имеет сложный пользовательский тип, то это можно сделать с помощью TypeConverter'а. Приводится, не совсем полезный пример реализации декоратора и его регистрации. Возможно это сделано для того чтобы потом можно было привести пример с define и if/else прямо внутри конфигурационного файла.
Всех описанных возможностей конфигруации хватит за глаза любому, даже самому энтерпрайзному приложению :)
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart4.aspx
В четвертой части описывается крайне важный материал - управление жизненным циклом сервисов внутри Castle.Windsor контейнера.
Любому, кто собирается работать с Caslte.Windsor стоит обязательно разобраться в том, что такое Lifestyle, Lifecycle, Commision/Decomission и Release Policy. Чтобы не было неожиданно неприятных ситуаций как со мной и Web-приложением на production сервере :)
Информация по Facility довольно полезна, но не так критична.
Building the Policy Injection in 40 Minutes with Windsor
http://ayende.com/Blog/archive/2007/03/07/Building-the-Policy-Injection-in-40-Minutes-with-Windsor.aspx
Реализация Policy Injection в виде Facility для Castle.Windsor. Типичный пример аспект-ориентированного программирования. Не знаю кто придумал термин Policy Injection, и что конкретно он обозначает, но когда мне говорят реализация аспекта (AOP), то я сразу понимаю о чем идет речь.
Caching with Castle Windsor
http://consultingblogs.emc.com/owainwragg/archive/2008/10/31/caching-with-castle-windsor.aspx
Реализация Facility, которая обеспечивает кеширование данных используя аспект-ориентированный подход. Очевидно, что с помощью IoC и AOP-подхода можно достаточно удобно решать такие вещи как Security, Logging, Caching.
The joys of Castle.Services.Transaction
http://www.jroller.com/hammett/entry/the_joys_of_castle_services
Описывается использование AutomaticTransactionFacility. Просто апофеоз декларативной attribute-driven разработки. Выглядит настолько необычно что я даже не знаю, стоит ли пытаться повторить это дома :) В любом случае идея невероятно креативная.
Hidden jewels in the Castle stack: Transaction Services
http://blogs.taiga.nl/martijn/2008/12/03/hidden-jewels-in-the-castle-stack-transaction-services
Прошу меня простить, но эта ссылка уже реальный оффтопик основной темы. В посте развивается идея сервиса транзакций из проекта Castle, только теперь транзакционность пытаются прикрутить уже к файловой системе...
List of .NET Dependency Injection Containers (IOC)
http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
Достаточно обширная подборка IoC контейнеров на платформе .NET от Scott Hanselman'а.
BitterCoder's Wiki. Container Tutorials
http://wiki.bittercoder.com/Default.aspx?Page=ContainerTutorials&AspxAutoDetectCookieSupport=1
Коллекция ссылок на туториалы по Castle.Windsor, в настоящее время представлено четырнадцать частей. Специфика этих туториалов заключается в том, что там в каждой части раскрывается только одна функциональная возможность библиотеки. Возможно для кого-то такой дробный формат изложения покажется удобным.
Внизу страницы приведена целая коллекция ссылок по рассматриваемой тематике на различные сторонние ресурсы.
Inject Some Life into Your Applications—Getting to Know the Unity Application Block
http://msdn.microsoft.com/en-us/library/cc816062.aspx
Вводная статья по Unity, IoC контейнеру, который разрабатывался силами Microsoft и затем был выпущен с открытым исходным кодом. Рассматриваются основные аспекты IoC контейнера. Все примеры кода приведены сразу на двух языках - C# и VB.NET.
IoC libraries compared
http://elegantcode.com/2009/01/07/ioc-libraries-compared/
Сравнение API у различных IoC контейнеров: Ninject, StructureMap, Unity, Spring.net, Castle.Windsor, Autofac. Следует принять во внимание что статья написана в январе 2009 года, а API каждого из перечисленный фреймверков постоянно совершенствуется.
Две простейшие реализации IoC контейнеров. По их реализации можно сделать вывод о том, какая основная задача ставится перед таким контейнером.
It's My Turn To Build An IoC Container In 15 Minutes and 33 Lines
http://www.kenegozi.com/Blog/2008/01/17/its-my-turn-to-build-an-ioc-container-in-15-minutes-and-33-lines.aspx
Building an IoC container in 15 lines of code
http://ayende.com/Blog/archive/2007/10/20/Building-an-IoC-container-in-15-lines-of-code.aspx
четверг, 11 марта 2010 г.
WatiN и ASP.NET integration tests
Не так давно пробовал библиотеку WatiN в работе, впечатления очень положительные.
На мой взгляд эту библиотеку очень выгодно отличает ее API. Он очень domain specific и его удобно использовать и читать.
Так же очень логично использовать так называемый "Page-based API", когда каждая страница в сценарии инкапсулирована в отдельный класс, унаследованный от класса WatiN.Core.Page. В этом классе описывается мэппинг контролов страницы на определенные свойста класса с помощью атрибутов, а так же реализуется логика взаимодействия со страницей в методах класса.
Реализованные классы страниц могут быть повторно использованы во множестве тестов с разными входными данными и с разными наборами страниц.
Таким образом, при чтении теста тестировщик или разработчик концентрируется не на полях ввода и кнопках, а на бизнес-логике и логике взаимодействия с веб приложением.
Классический API можно увидеть на главной странице сайта WatiN, я же приведу пример "Page-based API":
Надеюсь что весь приведенный код не нуждается в комментариях. Если вы его сразу же поняли, значит этот API можно считать действительно удачным.
Пример реального кода на WatiN:
В коде выше описан верхний уровень сценария взаимодействия с сайтом FedEx. Глядя на код можно получить четкое представление о том, что нужно сделать пользователю для того чтобы скачать некий репорт с сайта. При этом все ньюансы разметки страницы и ввода данных сгруппированы и изолированы :)
WatiN даже умеет взаимодействовать со скрытым окном браузера, что позволяет запускать integration тесты на локальной машине прямо во время работы.
Стоит отметить, что в работе со скрытым окном браузера есть несколько ньюансов:
1. Если понадобится сделать скриншот страницы, то окно браузера необходимо сделать видимым, но не активным, иначе вместо скриншота у нас будет снимок черного экрана. Окно можно делать не активным, чтобы оно не мешало работе. После снятия скриншота окно можно будет сразу же спрятать:
2. Обработка диалоговых окон часто завершается неудачей без видимых на то причин. К сожалению у меня не было достаточно времени чтобы четко вычислить закономерность поведения, поэтому я проблему решил приведением окна браузера в видимый + активный режим. Понятно что побочным эффектом будет периодические появления диалоговых окон в самый неудачный для вас момент, но как правило таких ситуаций не так уж и много. Буду очень признателен, если кто-нибудь подскажет решение данной проблемы.
3. На моем копьютере WatiN отказывается работать в режиме Windows Service без доступа к рабочему столу, несмотря на то что на официальном сайте утверждается обратное.
...случайно заметил что в IE8 все вставки кода выглядят просто ужасно. Что интересно, FF и iPhone показывают правильно.
На мой взгляд эту библиотеку очень выгодно отличает ее API. Он очень domain specific и его удобно использовать и читать.
Так же очень логично использовать так называемый "Page-based API", когда каждая страница в сценарии инкапсулирована в отдельный класс, унаследованный от класса WatiN.Core.Page. В этом классе описывается мэппинг контролов страницы на определенные свойста класса с помощью атрибутов, а так же реализуется логика взаимодействия со страницей в методах класса.
Реализованные классы страниц могут быть повторно использованы во множестве тестов с разными входными данными и с разными наборами страниц.
Таким образом, при чтении теста тестировщик или разработчик концентрируется не на полях ввода и кнопках, а на бизнес-логике и логике взаимодействия с веб приложением.
Классический API можно увидеть на главной странице сайта WatiN, я же приведу пример "Page-based API":
using (var ie = new IE("http://www.google.com"))
{
var page = ie.Page<GoogleSearchPage>();
page.SearchFor("WatiN");
}
...
[Page(UrlRegex="www.google.*")]
public class GoogleSearchPage : Page
{
[FindBy(Name="btnG")]
public Button SearchButton;
[FindBy(Name="q")]
public TextField SearchCriteria;
public void SearchFor(string searchCriteria)
{
this.SearchCriteria.TypeText(searchCriteria);
this.SearchButton.Click();
}
}
Надеюсь что весь приведенный код не нуждается в комментариях. Если вы его сразу же поняли, значит этот API можно считать действительно удачным.
Пример реального кода на WatiN:
browser = new IE(fedExHomePageUrl);
browser.Page<FedExLoginPage>().LogIn(login, password);
browser.GoTo(fedExSearchPageUrl);
browser.Page<FedExSearchPage>().Search(dateFrom, dateTo);
browser.Page<FedExSearchResultPage>().SaveAs(reportPath);
browser.Page<FedExDownloadPage>().Download(browser, reportPath);
...
В коде выше описан верхний уровень сценария взаимодействия с сайтом FedEx. Глядя на код можно получить четкое представление о том, что нужно сделать пользователю для того чтобы скачать некий репорт с сайта. При этом все ньюансы разметки страницы и ввода данных сгруппированы и изолированы :)
WatiN даже умеет взаимодействовать со скрытым окном браузера, что позволяет запускать integration тесты на локальной машине прямо во время работы.
Стоит отметить, что в работе со скрытым окном браузера есть несколько ньюансов:
1. Если понадобится сделать скриншот страницы, то окно браузера необходимо сделать видимым, но не активным, иначе вместо скриншота у нас будет снимок черного экрана. Окно можно делать не активным, чтобы оно не мешало работе. После снятия скриншота окно можно будет сразу же спрятать:
browser.ShowWindow(NativeMethods.WindowShowStyle.ShowNormalNoActivate);
browser.CaptureWebPageToFile(debugImagePath);
browser.ShowWindow(NativeMethods.WindowShowStyle.Hide);
2. Обработка диалоговых окон часто завершается неудачей без видимых на то причин. К сожалению у меня не было достаточно времени чтобы четко вычислить закономерность поведения, поэтому я проблему решил приведением окна браузера в видимый + активный режим. Понятно что побочным эффектом будет периодические появления диалоговых окон в самый неудачный для вас момент, но как правило таких ситуаций не так уж и много. Буду очень признателен, если кто-нибудь подскажет решение данной проблемы.
3. На моем копьютере WatiN отказывается работать в режиме Windows Service без доступа к рабочему столу, несмотря на то что на официальном сайте утверждается обратное.
...случайно заметил что в IE8 все вставки кода выглядят просто ужасно. Что интересно, FF и iPhone показывают правильно.
воскресенье, 31 января 2010 г.
Парсинг Html документов с целью извлечения данных
Ехал я как-то с работы вместе со своим коллегой Валерой Щербининым и заговорили о теме парсинга HTML.
Большую часть времени на работе я занимаюсь поддержкой и активным развитием биллинговой подсистемы одной большой системы которая занимается записью компакт дисков. Название компании опускаю, так как я подписывал договор о неразглашении нечитая, посему не знаю что можно разглашать, а что нет :).
Учитывая специфику проекта и интеграцию всего со всем я трижды сталкивался с задачей импорта данных из HTML документов в биллинговую систему.
Три раза я использовал один и тот же подход - Regular Expression.
Причем один из документов имел такую нетривиальную структуру, что мне пришлось использовать аж два регулярных выражения. В один проход я выделял все данные вместе с частью HTML разметки, а во второй уже выкусывал сами данные. Мне пришлось так поступить, потому как я уважаю мэйнтейнеров и не хочу писать код, после которого меня будут долго вспоминать.
Кроме того, мне даже приходилось пережить один эпизод обновления разметки документа и обновлять свое же регулярные выражения...
Не могу пожаловаться на плохие знания языка регулярных выражений, но этот процесс доставлял мало удовольствия, был очень и очень медленным. Но самое главное - если код парсера хоть и был легко читаем и сопровождаем, то сами регулярные выражения были настоящей занозой в заднице.
Возможно Валера подумал что я полоумный, но тем не менее вежливо поделился своей идеей - использовать HTML Tidy для нормализации HTML до well formed XHTML, а потом наворачивать на это дело Xslt-преобразование которое извлекает все данные.
Идея мне сразу же понравилась. Но меня смутило то, что мне придется вызывать unmanaged HTML Tidy, плюс я практически незнаком с Xslt хотя и знаю XPath.
И вот, сегодня, совершенно случайно наткнулся на замечательное во всех отношениях решение - SGMLReader:
SGMLReader - Converting almost any HTML to valid XML
SGMLReader это pure C# .NET 2.0 библиотека, центральный класс которой это SgmlReader унаследованный от XmlReader со всем вытекающими отсюда преимуществами.
Есть даже примеры, которые запускаются на лету на живом коде из trunk:
HTML-to-XML Conversion Examples
Благодаря это библиотеке мне не придется погружаться в жестокий unmanaged мир и я смогу использовать Linq to Xml / Xslt / XPath на выбор.
В нагрузку ссылка на статью в которой описывается интеграция HTML Tidy и .NET. Если в двух словах то это либо P/Invoke либо COM Iterop. Брр...
Fix Up Your HTML with HTML Tidy and .NET
Ну и раз уж я удосужился написать пост, то упомяну что я завел себе твиттер :)
http://twitter.com/alexey_diyan
В твиттер я делаю посты очень часто. Всех интересующихся заверяю, что посты в твиттер буду делать только на техническую тематику.
Посты обычно касаются либо каких-то актуальных для меня вещей, изредка бывают 140-символьные размышлизмы.
Большую часть времени на работе я занимаюсь поддержкой и активным развитием биллинговой подсистемы одной большой системы которая занимается записью компакт дисков. Название компании опускаю, так как я подписывал договор о неразглашении нечитая, посему не знаю что можно разглашать, а что нет :).
Учитывая специфику проекта и интеграцию всего со всем я трижды сталкивался с задачей импорта данных из HTML документов в биллинговую систему.
Три раза я использовал один и тот же подход - Regular Expression.
Причем один из документов имел такую нетривиальную структуру, что мне пришлось использовать аж два регулярных выражения. В один проход я выделял все данные вместе с частью HTML разметки, а во второй уже выкусывал сами данные. Мне пришлось так поступить, потому как я уважаю мэйнтейнеров и не хочу писать код, после которого меня будут долго вспоминать.
Кроме того, мне даже приходилось пережить один эпизод обновления разметки документа и обновлять свое же регулярные выражения...
Не могу пожаловаться на плохие знания языка регулярных выражений, но этот процесс доставлял мало удовольствия, был очень и очень медленным. Но самое главное - если код парсера хоть и был легко читаем и сопровождаем, то сами регулярные выражения были настоящей занозой в заднице.
Возможно Валера подумал что я полоумный, но тем не менее вежливо поделился своей идеей - использовать HTML Tidy для нормализации HTML до well formed XHTML, а потом наворачивать на это дело Xslt-преобразование которое извлекает все данные.
Идея мне сразу же понравилась. Но меня смутило то, что мне придется вызывать unmanaged HTML Tidy, плюс я практически незнаком с Xslt хотя и знаю XPath.
И вот, сегодня, совершенно случайно наткнулся на замечательное во всех отношениях решение - SGMLReader:
SGMLReader - Converting almost any HTML to valid XML
SGMLReader это pure C# .NET 2.0 библиотека, центральный класс которой это SgmlReader унаследованный от XmlReader со всем вытекающими отсюда преимуществами.
Есть даже примеры, которые запускаются на лету на живом коде из trunk:
HTML-to-XML Conversion Examples
Благодаря это библиотеке мне не придется погружаться в жестокий unmanaged мир и я смогу использовать Linq to Xml / Xslt / XPath на выбор.
В нагрузку ссылка на статью в которой описывается интеграция HTML Tidy и .NET. Если в двух словах то это либо P/Invoke либо COM Iterop. Брр...
Fix Up Your HTML with HTML Tidy and .NET
Ну и раз уж я удосужился написать пост, то упомяну что я завел себе твиттер :)
http://twitter.com/alexey_diyan
В твиттер я делаю посты очень часто. Всех интересующихся заверяю, что посты в твиттер буду делать только на техническую тематику.
Посты обычно касаются либо каких-то актуальных для меня вещей, изредка бывают 140-символьные размышлизмы.
воскресенье, 22 ноября 2009 г.
NHibernate. Fluent NHibernate. Первые впечатления
Не так давно я слушал доклад на тему ADO.NET Entity Framework 4.0, который читал на собрании Uneta Александр Кондуфоров. До недавнего времени мой опыт использования Entity Framework (1.0) можно было смело назвать более чем скромным. Вдохновленный услышанным докладом, я решил все таки заполнить пробелы своих знаний в области ORM.
Причем решил пойти по не самому простому пути. Вначале я решил как можно ближе ознакомится с более зрелой ORM, которая широко признана в ALT.NET сообществе - NHibernate.
В своем багаже знаний хочется иметь понимание того как строится уровень доступа к данным в наших приложениях при использовании как минимум двух ORM - NHibernate и Entity Framework. Это позволит, в случае необходимости, более взвешенно принимать решение в пользу того или иного ORM. Более того, каждый из этих ORM предполагает несколько вариантов их использования.
Например у Entity Framework 4.0 существуют как минимум три подхода: Database first, Model first, Code only. Причем можно использовать либо не использовать POCO объекты.
Довольно много информации, включая ссылки, можно почерпнуть из поста Саши Entity Framework 4.0: выходим на зрелый уровень.
В различных блогах я довольно часто встречал мнение о том, что порог вхождения в NHibernate выше чем в Entity Framework. Так же довольно часто противопоставляют Anemic Data Model у Entity Framework и Rich Data Model у NHibernate. Например в посте Ivan'а Старые песни о главном: роль ООП при работе с данными... количество комментариев перевалило за 90. :)
Что же я хотел получить от NHibernate? Вот список важных для меня моментов:
В начале я пробовал описать конфигурацию NHibernate в Application configuration file, потом описывал конфигурацию императивно в коде и в конечном счете остановился императивной конфигурации в коде с помощью библиотеки Fluent NHibernate.
Конфигурация выглядит достаточно просто и очень легко читается:
Так же, по мере изучения configuraion API у NHibernate, я обнаружил возможность трассировки всех SQL-запросов в лог с помощью конфигурирования трассировщика в log4net. Пока это не опробовал, но планирую это сделать. Это довольно удобно для отладки и этого очень сильно не хватало при работе с Entity Framework. Там была возможность написать свой механизм трассировки, но такого готового решения, как у NHibernate я у EF не обнаружил. Буду очень рад, если узнаю что EF это умеет и что я просто недостаточно хорошо искал.
Далее я пришел к выводу, что у NHibernate-решения существует по крайней мере три подхода для работы с данными:
Кроме того, у Fluent NHibernate есть две killer-фичи - это Auto Mapping + Conventions и Persistence specification testing.
Auto Mapping я пока не использовал и пошел по пути “медленно но верно”. В качестве исходной БД я взял базу Northwind. По мере описания меппинга, я удивился насколько мощными возможностями обладает NHibernate. Например, NHibernate умеет круто меппить иерархии классов - table per class hierarchy, table per subclass, table per concrete class. Не знаю, насколько Fluent NHibernate покрывает возможности, заложенные в hbm.xml-меппинге, но он помог мне описать все нужные мне правила, не смотря на то, что я ни в коем случае не пытался прогнуть доменную модель под схему базы. Весь API по меппингу у Fluent NHibernate можно посмотреть по этой ссылке.
Вот например как у меня выглядит класс Customer:
Соответственно, меппинг этого класса выглядит вот так:
Учитывая, что меппинг описывается вручную, то для того чтобы быть 100% уверенным в его корректности, необходимы тесты. Команда Fluent NHibernate подумала и над этой проблемой и предложила решение в виде Persistence specification testing, который моем случае выглядит следующим образом:
Этот тест делает следующее:
На этом пожалуй хватит для одного поста. Буду очень благодарен за любой feedback, как положительный так и отрицательный.
[UPDATE]
Поменял тему в блоге на более нейтральную. Подключил google-code-prettify для подсветки синтаксиса. Надеюсь теперь будет удобне читать.
Причем решил пойти по не самому простому пути. Вначале я решил как можно ближе ознакомится с более зрелой ORM, которая широко признана в ALT.NET сообществе - NHibernate.
В своем багаже знаний хочется иметь понимание того как строится уровень доступа к данным в наших приложениях при использовании как минимум двух ORM - NHibernate и Entity Framework. Это позволит, в случае необходимости, более взвешенно принимать решение в пользу того или иного ORM. Более того, каждый из этих ORM предполагает несколько вариантов их использования.
Например у Entity Framework 4.0 существуют как минимум три подхода: Database first, Model first, Code only. Причем можно использовать либо не использовать POCO объекты.
Довольно много информации, включая ссылки, можно почерпнуть из поста Саши Entity Framework 4.0: выходим на зрелый уровень.
В различных блогах я довольно часто встречал мнение о том, что порог вхождения в NHibernate выше чем в Entity Framework. Так же довольно часто противопоставляют Anemic Data Model у Entity Framework и Rich Data Model у NHibernate. Например в посте Ivan'а Старые песни о главном: роль ООП при работе с данными... количество комментариев перевалило за 90. :)
Что же я хотел получить от NHibernate? Вот список важных для меня моментов:
- полная изоляция от базы данных во всех юнит-тестах. В первую очередь рассматривал mockинг DAO/Repository. Еще витали мысли об использовании предварительно подготовленной SQLite базы, но я отказался от этой идеи;
- покрытие тестами уровня доступа к данным. Возможность написания интеграционных тестов на живую БД, которые покрывают все DAO/Repository;
- хотел получить Persistance Ignorance как можно меньшей кровью;
- иметь возможность использовать Linq для написания запросов, а так же какой-нибудь API для вызова хранимых процедур.
В начале я пробовал описать конфигурацию NHibernate в Application configuration file, потом описывал конфигурацию императивно в коде и в конечном счете остановился императивной конфигурации в коде с помощью библиотеки Fluent NHibernate.
Конфигурация выглядит достаточно просто и очень легко читается:
var session = Fluently.Configure()
.Database(SQLiteConfiguration.Standard
.ShowSql()
.UsingFile(@"D:\projects\DotNET\NHibernatePlayground\DB\northwindEF.db"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf())
.BuildSessionFactory()
.OpenSession();
Так же, по мере изучения configuraion API у NHibernate, я обнаружил возможность трассировки всех SQL-запросов в лог с помощью конфигурирования трассировщика в log4net. Пока это не опробовал, но планирую это сделать. Это довольно удобно для отладки и этого очень сильно не хватало при работе с Entity Framework. Там была возможность написать свой механизм трассировки, но такого готового решения, как у NHibernate я у EF не обнаружил. Буду очень рад, если узнаю что EF это умеет и что я просто недостаточно хорошо искал.
Далее я пришел к выводу, что у NHibernate-решения существует по крайней мере три подхода для работы с данными:
- “канонический” подход, который пришел с Hibernate. Программист описывает объектную модель в виде набора POCO-объектов. Если со стороны БД у нас есть связи, то со стороны .NET у нас будут navigation-свойства с типизированными коллециями. Меппинг между .NET и БД описывается в специальных *.hbm.xml-файлах. Вполне возможно, этот подход можно было бы назвать удобным, если бы у него была мощная поддержка в Visual Studio в виде визуального дизайнера;
- проект Castle ActiveRecord. Однако я эти проекты не рассматривал, т.к. ActiveRecord влияет на мою доменную модель. При его использовании мы должны помечать свои классы и свойства атрибутами, которые описывают меппинг к БД, а это нарушает Persistence Ignorance. В любом случае, этот подход вполне имеет право на жизнь в небольших проектах;
- описание меппинга с помощью Fluent NHibernate. Мне этот вариант понравился больше всего.
Кроме того, у Fluent NHibernate есть две killer-фичи - это Auto Mapping + Conventions и Persistence specification testing.
Auto Mapping я пока не использовал и пошел по пути “медленно но верно”. В качестве исходной БД я взял базу Northwind. По мере описания меппинга, я удивился насколько мощными возможностями обладает NHibernate. Например, NHibernate умеет круто меппить иерархии классов - table per class hierarchy, table per subclass, table per concrete class. Не знаю, насколько Fluent NHibernate покрывает возможности, заложенные в hbm.xml-меппинге, но он помог мне описать все нужные мне правила, не смотря на то, что я ни в коем случае не пытался прогнуть доменную модель под схему базы. Весь API по меппингу у Fluent NHibernate можно посмотреть по этой ссылке.
Вот например как у меня выглядит класс Customer:
public class Customer
{
public virtual string ID { get; set; }
public virtual string CompanyName { get; set; }
public virtual string ContactName { get; set; }
public virtual string ContactTitle { get; set; }
public virtual string Address { get; set; }
public virtual string City { get; set; }
public virtual string Region { get; set; }
public virtual string PostalCode { get; set; }
public virtual string Country { get; set; }
public virtual string Phone { get; set; }
public virtual string Fax { get; set; }
public virtual IListOrders { get; private set; }
}
Соответственно, меппинг этого класса выглядит вот так:
public class CustomerMap : ClassMap
{
public CustomerMap()
{
Table("Customers");
Id(x => x.ID).Column("CustomerID").Length(5);
Map(x => x.CompanyName).Length(40).Not.Nullable();
Map(x => x.ContactName).Length(30);
Map(x => x.ContactTitle).Length(30);
Map(x => x.Address).Length(60);
Map(x => x.City).Length(15);
Map(x => x.Region).Length(15);
Map(x => x.PostalCode).Length(10);
Map(x => x.Country).Length(15);
Map(x => x.Phone).Length(24);
Map(x => x.Fax).Length(24);
HasMany(x => x.Orders).KeyColumn("CustomerID");
}
}
Учитывая, что меппинг описывается вручную, то для того чтобы быть 100% уверенным в его корректности, необходимы тесты. Команда Fluent NHibernate подумала и над этой проблемой и предложила решение в виде Persistence specification testing, который моем случае выглядит следующим образом:
[TestMethod]
public void Save_Customer_in_database()
{
RemoveCustomerIfExists("A");
new PersistenceSpecification(TestHelper.GetSession())
.CheckProperty(c => c.ID, "A")
.CheckProperty(c => c.CompanyName, "TestCompanyName")
.CheckProperty(c => c.ContactName, "TestContactName")
.CheckProperty(c => c.ContactTitle, "TestContactTitle")
.CheckProperty(c => c.Address, "TestAddress")
.CheckProperty(c => c.City, "TestCity")
.CheckProperty(c => c.Region, "TestRegion")
.CheckProperty(c => c.PostalCode, "TestPostalCode")
.CheckProperty(c => c.Country, "TestCountry")
.CheckProperty(c => c.Phone, "TestPhone")
.CheckProperty(c => c.Fax, "TestFax")
.VerifyTheMappings();
}
Этот тест делает следующее:
- приводит БД в предсостояние для теста (удаляет кастомера, если он уже существует);
- создает экземпляр Customer с заданными параметрами;
- вставляет данные по этому кастомеру в базу данных;
- извлекает из базы данных запись в другой экземпляр класса Customer;
- проверяет что полученный Customer соответствует оригинальному.
На этом пожалуй хватит для одного поста. Буду очень благодарен за любой feedback, как положительный так и отрицательный.
[UPDATE]
Поменял тему в блоге на более нейтральную. Подключил google-code-prettify для подсветки синтаксиса. Надеюсь теперь будет удобне читать.
понедельник, 19 октября 2009 г.
Библиотека для объектно-объектного маппинга
Вы подготовились к приходу AutoMapper?
http://blogs.gotdotnet.ru/personal/butaji/PermaLink.aspx?guid=9d2469ee-7c12-4551-8f15-6acdc155f5c6
http://blogs.gotdotnet.ru/personal/butaji/PermaLink.aspx?guid=9d2469ee-7c12-4551-8f15-6acdc155f5c6
Прикольная штучка. Позволяет избегать тупых методов проекций DataEntity to DomainEntity, DomainEntity to ServiceEntity...
Вроде как сама все волшебно перекладывает. Естественно, вы скажете что побочный эффект - runtime errors.
Но там для раннего выявления таких проблем сделали какой-то механизм самотестирования. Типа можно при старте приложения дернуть метод и он конфигурацию протестирует.
В общем сплошное волшебство... интересно сколько мозговой маны потребует это волшебство при наложении заклинаний. :)
Вроде как сама все волшебно перекладывает. Естественно, вы скажете что побочный эффект - runtime errors.
Но там для раннего выявления таких проблем сделали какой-то механизм самотестирования. Типа можно при старте приложения дернуть метод и он конфигурацию протестирует.
В общем сплошное волшебство... интересно сколько мозговой маны потребует это волшебство при наложении заклинаний. :)
пятница, 10 июля 2009 г.
Parallel Extensions для .NET. Ссылки
Хочу предупредить, что ссылки достаточно старые. Уверен, что на данный момент есть масса свежего материала. Насколько я знаю, эту библиотеку включат в .NET 4.0.
Parallel Extensions для .net 3.5
http://habrahabr.ru/blogs/net/45732/
На мой взгляд самая удачная статья для ознакомления с библиотекой Parallel Extensions. Описывается структура библиотеки и введение в Task Parallel Library.
Оптимизация управляемого кода для многоядерных компьютеров
http://msdn.microsoft.com/ru-ru/magazine/cc163340.aspx
Достаточно объемная статья. Интересен пример, в котором показывается три варианта реализации алгоритма: однопоточный, многопоточный с использованием стандартного API в .NET, многопоточный с использованием Parallel Extensions.
Несколько полнее описан Task Parallel Library. Описываются задания (Task) и диспетчер заданий (TaskManager), правда с момента написания статьи произошли небольшие изменения в API.
Блог команды, которая занимается разработкой Parallel Extensions
http://blogs.msdn.com/pfxteam/default.aspx
В блоге доступна обширная информация по API библиотеки и описаны типовые сценарии.
Multiple thread-local state elements in a loop
http://blogs.msdn.com/pfxteam/archive/2008/05/28/8556655.aspx
Описывается работа с типом ParallelState - контейнер для объектов которые "зашарены" на поток. В принципе API относительно удобный. Я использовал этот класс на проекте, но потом от него отказался. Перешел на кеширование объектов на уровне потока, которое предоставляет IoC контейнер (в моем случае это Castle.Windsor). Объекты запрашиваются у ServiceLocator'а, который я реализовал как фасад к Castle.Windsor.
Coordination Data Structures Overview
http://blogs.msdn.com/pfxteam/archive/2008/06/18/8620615.aspx
Coordination Data Structures – LazyInit
http://blogs.msdn.com/pedram/archive/2008/06/02/coordination-data-structures-lazyinit-t.aspx
По двум ссылкам выше, описываются структуры, которые можно использовать в многопоточных сценариях. Как правило эти структуры достаточно слабо описывают в статьях, которые посвящены библиотеке Parallel Extensions.
Waltzing Through the Parallel Extensions June CTP: Synchronization Primitives
http://blogs.microsoft.co.il/blogs/sasha/archive/2008/06/11/waltzing-through-the-parallel-extensions-june-ctp-synchronization-primitives.aspx
Есть элементы синхронизации в .NET, а есть и в Parallel Extensions. :)
Да, я знаю что это такое и зачем это нужно, но мне лень это описывать :)
TaskManager – The Range Rover of the .Net 4 Parallel Extensions
http://www.lovethedot.net/2009/03/taskmanager-range-rover-of-net-4.html
Очень хорошо описывается интерфейс класса TaskManager. Этот класс нужно использовать, если вам необходимо явно указать сколько процессоров/потоков вы готовы отдать планировщику. По-умолчанию планировщик использует все доступные ресурсы CPU.
Parallel Extensions для .net 3.5
http://habrahabr.ru/blogs/net/45732/
На мой взгляд самая удачная статья для ознакомления с библиотекой Parallel Extensions. Описывается структура библиотеки и введение в Task Parallel Library.
Оптимизация управляемого кода для многоядерных компьютеров
http://msdn.microsoft.com/ru-ru/magazine/cc163340.aspx
Достаточно объемная статья. Интересен пример, в котором показывается три варианта реализации алгоритма: однопоточный, многопоточный с использованием стандартного API в .NET, многопоточный с использованием Parallel Extensions.
Несколько полнее описан Task Parallel Library. Описываются задания (Task) и диспетчер заданий (TaskManager), правда с момента написания статьи произошли небольшие изменения в API.
Блог команды, которая занимается разработкой Parallel Extensions
http://blogs.msdn.com/pfxteam/default.aspx
В блоге доступна обширная информация по API библиотеки и описаны типовые сценарии.
Multiple thread-local state elements in a loop
http://blogs.msdn.com/pfxteam/archive/2008/05/28/8556655.aspx
Описывается работа с типом ParallelState
Coordination Data Structures Overview
http://blogs.msdn.com/pfxteam/archive/2008/06/18/8620615.aspx
Coordination Data Structures – LazyInit
http://blogs.msdn.com/pedram/archive/2008/06/02/coordination-data-structures-lazyinit-t.aspx
По двум ссылкам выше, описываются структуры, которые можно использовать в многопоточных сценариях. Как правило эти структуры достаточно слабо описывают в статьях, которые посвящены библиотеке Parallel Extensions.
Waltzing Through the Parallel Extensions June CTP: Synchronization Primitives
http://blogs.microsoft.co.il/blogs/sasha/archive/2008/06/11/waltzing-through-the-parallel-extensions-june-ctp-synchronization-primitives.aspx
Есть элементы синхронизации в .NET, а есть и в Parallel Extensions. :)
Да, я знаю что это такое и зачем это нужно, но мне лень это описывать :)
TaskManager – The Range Rover of the .Net 4 Parallel Extensions
http://www.lovethedot.net/2009/03/taskmanager-range-rover-of-net-4.html
Очень хорошо описывается интерфейс класса TaskManager. Этот класс нужно использовать, если вам необходимо явно указать сколько процессоров/потоков вы готовы отдать планировщику. По-умолчанию планировщик использует все доступные ресурсы CPU.
среда, 3 июня 2009 г.
Сравнение 72 реализаций языков программирования
Сравнение 72 реализаций языков программирования:
http://www.opennet.ru/opennews/art.shtml?num=21974
Прямая ссылка на картинку с визуальным отчетом:
http://gmarceau.qc.ca/blog/uploaded_images/size-vs-speed-vs-depandability.png
Легенда к визуальному отчету из которой видно что нижний левый угол это идеальные языки программирования:
http://gmarceau.qc.ca/blog/uploaded_images/size-vs-speed-vs-depandability--context-3.png
Субъективные выводы по визульному отчету:
- Java существенно медленнее и несколько менее удобный язык чем C#
- Perl по скорости быстрее чем Python, а Python практически такой же по скорости как и PHP
- OCaml и luajit выглядят как идеальные языки. Я только не пойму luajit это Lua + Jit Compiler или как? :)
http://www.opennet.ru/opennews/art.shtml?num=21974
Прямая ссылка на картинку с визуальным отчетом:
http://gmarceau.qc.ca/blog/uploaded_images/size-vs-speed-vs-depandability.png
Легенда к визуальному отчету из которой видно что нижний левый угол это идеальные языки программирования:
http://gmarceau.qc.ca/blog/uploaded_images/size-vs-speed-vs-depandability--context-3.png
Субъективные выводы по визульному отчету:
- Java существенно медленнее и несколько менее удобный язык чем C#
- Perl по скорости быстрее чем Python, а Python практически такой же по скорости как и PHP
- OCaml и luajit выглядят как идеальные языки. Я только не пойму luajit это Lua + Jit Compiler или как? :)
суббота, 25 апреля 2009 г.
Каким должен быть правильный BL и DAL?
Не так давно нашел на ряд постов, которые сформировали у меня определенное видение решения классической задачки по передачи данных через ряд уровней - Data access layer -> Business layer -> Presentation layer.
Первым был пост Repository is the new Singleton от Oren Eini aka Ayende Rahien.
В этом посте Ayende говорит что ему не очень нравится непосредственно сам паттерн Repository, более того от отмечает что в большистве случаев этот паттерн еще и не совсем правильно используют.
Дествительно, с появлением LINQ и NHibernate/LinqToSql/ADO.NET Entity Framework подход к получению данных довольно сильно изменился.
И я придерживаюсь того мнения что нужно постепенно уходить от практики написания огромного количества методов вида GetCustomer(id), GetCustomerWithAddresses(id) и начинать использовать механизм запросов даже на верхних уровнях.
Если этого не делать, то мы очень быстро прийдем к достаточно некрасивому Data access layer'у - Kobe – Data Access done wrong.
В своем следующем посте - "The DAL should go all the way to UI" Ayende развивает идею и очень наглядно показывает какую цену приходится платить за неудачную реализацию Data access layer'а.
Действительно, если делать sorting и paging по-честному, через Business Layer, то приходится вручную писать кучу методов, которые похожи друг на друга как близнецы браться, что как раз нарушает принцип DRY (Don't Repeat Yourself).
Подход Ayende мне показался очень уместным, однако меня смутило отсутствие ограничений по извлечению даных на UI-уровне. Возможно, я параноик, но я бы хотел все вызовы по извлечению данных прокидывать через Business Layer. Как минимум это даст возможность прикрутить Caching/Logging/Security на query-методы.
В ответ на пост Ayende, другой блоггер Justin Etheredge сделал пост в котором привел достаточно удачную на мой взгляд реализацию paging'а и сортировки.
В результате, однозначно для себя я решил несколько моментов:
- Классы IRepository должны быть максимально небольшими и простыми
- При получении данных необходимо иметь возможность строить цепочку из filtering, paging, sorting, поскольку это дает намного больше гибкости
- Presentation Layer не должен работать с чрезмерно богатым интерфейсом, этот уровень должен использовать только то, что предоставляет ему Business Layer
- Все большие либо нетривиальные запросы стоит инкапсулировать в отдельные Query-объекты
Интересно, насколько удобно будет использовать это решение когда у нас пользовательский интерфейс написан на Silverlight? Ведь в таких случаях мы Business Layer не видим напрямую в своем Silverlight-приложении, а работаем с удаленными WCF-сервисами.
Первым был пост Repository is the new Singleton от Oren Eini aka Ayende Rahien.
В этом посте Ayende говорит что ему не очень нравится непосредственно сам паттерн Repository, более того от отмечает что в большистве случаев этот паттерн еще и не совсем правильно используют.
Дествительно, с появлением LINQ и NHibernate/LinqToSql/ADO.NET Entity Framework подход к получению данных довольно сильно изменился.
И я придерживаюсь того мнения что нужно постепенно уходить от практики написания огромного количества методов вида GetCustomer(id), GetCustomerWithAddresses(id) и начинать использовать механизм запросов даже на верхних уровнях.
Если этого не делать, то мы очень быстро прийдем к достаточно некрасивому Data access layer'у - Kobe – Data Access done wrong.
В своем следующем посте - "The DAL should go all the way to UI" Ayende развивает идею и очень наглядно показывает какую цену приходится платить за неудачную реализацию Data access layer'а.
Действительно, если делать sorting и paging по-честному, через Business Layer, то приходится вручную писать кучу методов, которые похожи друг на друга как близнецы браться, что как раз нарушает принцип DRY (Don't Repeat Yourself).
Подход Ayende мне показался очень уместным, однако меня смутило отсутствие ограничений по извлечению даных на UI-уровне. Возможно, я параноик, но я бы хотел все вызовы по извлечению данных прокидывать через Business Layer. Как минимум это даст возможность прикрутить Caching/Logging/Security на query-методы.
В ответ на пост Ayende, другой блоггер Justin Etheredge сделал пост в котором привел достаточно удачную на мой взгляд реализацию paging'а и сортировки.
В результате, однозначно для себя я решил несколько моментов:
- Классы IRepository должны быть максимально небольшими и простыми
- При получении данных необходимо иметь возможность строить цепочку из filtering, paging, sorting, поскольку это дает намного больше гибкости
- Presentation Layer не должен работать с чрезмерно богатым интерфейсом, этот уровень должен использовать только то, что предоставляет ему Business Layer
- Все большие либо нетривиальные запросы стоит инкапсулировать в отдельные Query-объекты
Интересно, насколько удобно будет использовать это решение когда у нас пользовательский интерфейс написан на Silverlight? Ведь в таких случаях мы Business Layer не видим напрямую в своем Silverlight-приложении, а работаем с удаленными WCF-сервисами.
вторник, 14 апреля 2009 г.
SQLite для .NET разработчика. Ссылки.
Краткое описание на Wikipedia:
http://ru.wikipedia.org/wiki/SQLite
Обычная энциклопедическая статья, которая в общих чертах описывает функциональность этой встроенной СУБД. Очень радует лицензия продукта, которая Public Domain.
Официальный сайт SQLite
http://www.sqlite.org/
.NET программисту особенно тут делать нечего. Однако стоит прочитать две статьи в разделе Documentation - "Appropriate Uses For SQLite" и "Distinctive Features" чтобы иметь четкое понимание того, как именно позиционируется данный продукт.
SQLite Management Tools
http://www.sqlite.org/cvstrac/wiki?p=ManagementTools
Утилиты, которые позволяют управлять и выполнять запросы к базе SQLite
SQLite Converter Tools
http://www.sqlite.org/cvstrac/wiki?p=ConverterTools
Утилиты для конвертирования форматов других баз данных в формат SQLite и, наоборот.
SQLite Wrappers
http://www.sqlite.org/cvstrac/wiki?p=SqliteWrappers
Библиотеки, которые позволяют обращаться к базе SQLite из различных языков программирования.
System.Data.SQLite
http://sqlite.phxsoftware.com/
Наиболее развитый на мой взглять ADO.NET Data Provider для SQLite.
На официальном сайте можно отметить следующие интересные возможности этого проекта:
- Полная поддержка стека ADO.NET 2.0
- Поддержка .NET, .NET Compact Framework, Mono
- Поддержка ADO.NET Entity Framework, который доступен в .NET 3.5
- Design-Time поддержка в Visual Studio 2008
- Есть возможность шифрования базы данных
Для того чтобы распространять .NET проект, в котором используется база данных SQLite достаточно включить в него сборку System.Data.SQLite.dll, которая сама уже содержит оригинальную библиотеку.
Кроме того, можно использовать альтернативный вариант распространения - включать в дистрибутив приложения сборку System.Data.SQLite.dll из каталога ManagedOnly + оригинальную sqlite3.dll.
[UPDATE 2009-11-26]
Пост вызвыл активную реакцию, чему я безмерно рад. Большое спасибо за фидбек, я получил целый ряд полезных "зацепок", которые в последствии могут пригодится.
Насчет ссылочной целостности в SQLite. Действительно, неделю назад обнаружил в документации что по-умолчанию в SQLite не включены FK Constraints. Да, не фонтан. Пусть даже это и встроенная СУБД, но я бы не отказался от такого полезного механизма контроля.
По ссылке ниже описывается как можно проверить включены ли они или нет и что нужно сделать чтобы их таки включить:
http://www.sqlite.org/foreignkeys.html
Из документации видно, что в будущих релизах FK Constraints могут быть включены.
Плюс еще довольно полезная информация по поводу того, чего SQLite не умеет из SQL92 стандарта:
http://www.sqlite.org/omitted.html
Пока для себя расставил такие приоритеты:
- если размер дистрибутива важен, и можно принебречь остутствием ряда продвинутых фич, то я предпочту SQLite;
- требовать уж очень высокой скорости работы от встроенной СУБД думаю что не стоит;
- Embedded Firebird выгодно отличается от SQLite возможностью с нее "соскочить" на полновесную Firebird. Предполагаю что это будет максимально безполезненно;
- Еще подумываю об необходимости использовании ORM + встроенная БД. Тогда и поставщиков БД можно будет менять как перчатки. Ну или почти...
http://ru.wikipedia.org/wiki/SQLite
Обычная энциклопедическая статья, которая в общих чертах описывает функциональность этой встроенной СУБД. Очень радует лицензия продукта, которая Public Domain.
Официальный сайт SQLite
http://www.sqlite.org/
.NET программисту особенно тут делать нечего. Однако стоит прочитать две статьи в разделе Documentation - "Appropriate Uses For SQLite" и "Distinctive Features" чтобы иметь четкое понимание того, как именно позиционируется данный продукт.
SQLite Management Tools
http://www.sqlite.org/cvstrac/wiki?p=ManagementTools
Утилиты, которые позволяют управлять и выполнять запросы к базе SQLite
SQLite Converter Tools
http://www.sqlite.org/cvstrac/wiki?p=ConverterTools
Утилиты для конвертирования форматов других баз данных в формат SQLite и, наоборот.
SQLite Wrappers
http://www.sqlite.org/cvstrac/wiki?p=SqliteWrappers
Библиотеки, которые позволяют обращаться к базе SQLite из различных языков программирования.
System.Data.SQLite
http://sqlite.phxsoftware.com/
Наиболее развитый на мой взглять ADO.NET Data Provider для SQLite.
На официальном сайте можно отметить следующие интересные возможности этого проекта:
- Полная поддержка стека ADO.NET 2.0
- Поддержка .NET, .NET Compact Framework, Mono
- Поддержка ADO.NET Entity Framework, который доступен в .NET 3.5
- Design-Time поддержка в Visual Studio 2008
- Есть возможность шифрования базы данных
Для того чтобы распространять .NET проект, в котором используется база данных SQLite достаточно включить в него сборку System.Data.SQLite.dll, которая сама уже содержит оригинальную библиотеку.
Кроме того, можно использовать альтернативный вариант распространения - включать в дистрибутив приложения сборку System.Data.SQLite.dll из каталога ManagedOnly + оригинальную sqlite3.dll.
[UPDATE 2009-11-26]
Пост вызвыл активную реакцию, чему я безмерно рад. Большое спасибо за фидбек, я получил целый ряд полезных "зацепок", которые в последствии могут пригодится.
Насчет ссылочной целостности в SQLite. Действительно, неделю назад обнаружил в документации что по-умолчанию в SQLite не включены FK Constraints. Да, не фонтан. Пусть даже это и встроенная СУБД, но я бы не отказался от такого полезного механизма контроля.
По ссылке ниже описывается как можно проверить включены ли они или нет и что нужно сделать чтобы их таки включить:
http://www.sqlite.org/foreignkeys.html
Из документации видно, что в будущих релизах FK Constraints могут быть включены.
Плюс еще довольно полезная информация по поводу того, чего SQLite не умеет из SQL92 стандарта:
http://www.sqlite.org/omitted.html
Пока для себя расставил такие приоритеты:
- если размер дистрибутива важен, и можно принебречь остутствием ряда продвинутых фич, то я предпочту SQLite;
- требовать уж очень высокой скорости работы от встроенной СУБД думаю что не стоит;
- Embedded Firebird выгодно отличается от SQLite возможностью с нее "соскочить" на полновесную Firebird. Предполагаю что это будет максимально безполезненно;
- Еще подумываю об необходимости использовании ORM + встроенная БД. Тогда и поставщиков БД можно будет менять как перчатки. Ну или почти...
среда, 18 марта 2009 г.
Доступ к DreamSpark по студенческому билету для украинских студентов и аспирантов
Если ты студент и у тебя есть студенческий билет, то ты можешь получить ряд продуктов бесплатно:
Visual Studio 2008
Visual Studio 2005
XNA Game Studio 3
SQL Server 2008 Developer
Windows Server 2003
Windows Server 2008 Standard
Expression Studio 2
Подробности тут:
Доступ к DreamSpark по студенческому билету для украинских студентов и аспирантов
Visual Studio 2008
Visual Studio 2005
XNA Game Studio 3
SQL Server 2008 Developer
Windows Server 2003
Windows Server 2008 Standard
Expression Studio 2
Подробности тут:
Доступ к DreamSpark по студенческому билету для украинских студентов и аспирантов
Подписаться на:
Сообщения (Atom)