воскресенье, 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? Вот список важных для меня моментов:
  • полная изоляция от базы данных во всех юнит-тестах. В первую очередь рассматривал mockинг DAO/Repository. Еще витали мысли об использовании предварительно подготовленной SQLite базы, но я отказался от этой идеи;

  • покрытие тестами уровня доступа к данным. Возможность написания интеграционных тестов на живую БД, которые покрывают все DAO/Repository;

  • хотел получить Persistance Ignorance как можно меньшей кровью;

  • иметь возможность использовать Linq для написания запросов, а так же какой-нибудь API для вызова хранимых процедур.
В качестве полигона для своих проб я выбрал SQLite, т.к. меня интересовал в первую очередь ORM, к тому же я не хотел устанавливать на свой домашний ноутбук никаких полновесных СУБД.

В начале я пробовал описать конфигурацию 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 меппинг описывается на C# языке, что упрощает рефакторинг, предполагает наличие IntelliSense, а так же минимальную проверку грубых оплошностей в виде compile-time errors.

Кроме того, у 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 IList Orders { 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 соответствует оригинальному.
Еще стоило бы немного рассказать о HQL, Criteria API, NHibernate.Linq, Query Batcher и о случае “вау! какой же умный этот NHibernate”, но это не сейчас.

На этом пожалуй хватит для одного поста. Буду очень благодарен за любой feedback, как положительный так и отрицательный.

[UPDATE]
Поменял тему в блоге на более нейтральную. Подключил google-code-prettify для подсветки синтаксиса. Надеюсь теперь будет удобне читать.

понедельник, 19 октября 2009 г.

Библиотека для объектно-объектного маппинга

Прикольная штучка. Позволяет избегать тупых методов проекций DataEntity to DomainEntity, DomainEntity to ServiceEntity...
Вроде как сама все волшебно перекладывает. Естественно, вы скажете что побочный эффект - 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.

среда, 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 или как? :)

суббота, 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-сервисами.

вторник, 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 + встроенная БД. Тогда и поставщиков БД можно будет менять как перчатки. Ну или почти...

среда, 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 по студенческому билету для украинских студентов и аспирантов

понедельник, 16 марта 2009 г.

Необычный подход к написанию юнит тестов

Обнаружил довольно необычный подход к написанию юнит тестов у автора вот этого поста:
Test Driven Design и Test First Development -- в чем разница?

Меня привлекло то, что тест класс представляет из себя наследник тестируемого класса.

Приведу пример классического и альтернативного подхода (пример из документации NUnit).

Тестируемый класс:
namespace bank
{
public class Account
{
private float balance;
public void Deposit(float amount)
{
balance+=amount;
}

public void Withdraw(float amount)
{
balance-=amount;
}

public void TransferFunds(Account destination, float amount)
{
}

public float Balance
{
get{ return balance;}
}
}
}
Тест, написаный при помощи "классического" подхода:
namespace bank
{
using NUnit.Framework;

[TestFixture]
public class AccountTest
{
[Test]
public void TransferFunds()
{
Account source = new Account();
source.Deposit(200.00F);
Account destination = new Account();
destination.Deposit(150.00F);

source.TransferFunds(destination, 100.00F);
Assert.AreEqual(250.00F, destination.Balance);
Assert.AreEqual(100.00F, source.Balance);

}
}
}
Тест, написанный с помощью альтернативного подхода с наследованием:
namespace bank
{
using NUnit.Framework;

[TestFixture]
public class AccountTest : Account
{
[Test]
public void TestTransferFunds()
{
this.Deposit(200.00F);
Account destination = new Account();
destination.Deposit(150.00F);

this.TransferFunds(destination, 100.00F);
Assert.AreEqual(250.00F, destination.Balance);
Assert.AreEqual(100.00F, this.Balance);
}
}
}

Сразу отмечу, что конкретно в этом примере второй вариант, вероятно, выглядит неудачно. Скорее всего в каких-то случаях наследование, возможно, выглядит более привлекательно.


Лично у меня возникает вопрос. А стоит ли вообще так писать тесты?

У меня сходу возникли следующие мысли насчет альтернативного подхода:
+ Наследование позволяет протестировать protected методы
+ Я могу написать helper-методы в тест классе, который будет активно работать с protected методами и свойствами
- Наследование дает бОльшую связность между тестовым и тестируемым классом
- Наследование скорее всего завяжет мне руки в SetUp/TearDown методах
- Если класс sealed, то о подходе с наследованием можно забыть
- Когда я пишу классический тест-метод, то я получаю лаконичную документацию к своему коду в виде маленьких примеров
- Когда я пишу классический тест-метод, то я использую класс точно так же как это делает production-код
- У класса Account будет аж два клиента - production code and unit tests, что как правило будет положительно отражаться на его интерфейсе


Очень интересны ваши мнения на этот счет.

среда, 11 марта 2009 г.

Тест. Какой вы ученый?

Очередное баловство на тему тестов.

Да, действительно, я всегда стараюсь копнуть глубоко в тех вещах, которыми занимаюсь, которые считаю важными для себя.

Как правило это играет мне на руку, хотя иногда все-же делает меня занудой. :)


О, да вы - физик.
image Вы дотошны и предпочитаете во всем докапываться до самой сути вещей. Перед покупкой сложной техники вы обязательно потратите кучу времени на сравнение всех возможных моделей пока не узнаете про них все. Порой вы иронично посмеиваетесь над серьезностью этого мира, но мало кто так же хорошо, как и вы, понимает, насколько хрупкая и сложная игрушка этот самый мир.
Пройти тест

четверг, 19 февраля 2009 г.

IronPython. Ссылки.

Начинаем работать с IronPython.
http://blogs.gotdotnet.ru/personal/AlexanderByndyu/PermaLink.aspx?guid=71d5dcff-7833-4242-ac06-5388ad993acf

Entry point для того чтобы начать работать с IronPython в Visual Studio 2008.


Блог автора языка IronPython:
http://blogs.msdn.com/haibo_luo/default.aspx


IronPython: Grab the .NET Type
http://blogs.msdn.com/haibo_luo/archive/2007/09/25/5130087.aspx

Можно сказать entry point по IronPython/.NET interop. Очень мало, но наглядно :)


IronPython: Keyword Argument to Set .NET Property/Field
http://blogs.msdn.com/haibo_luo/archive/2007/10/02/5246577.aspx

Если кто-нибудь любит свеженькие конструкции C# вроде Object Initializer, то стоит просмотреть этот пост.


IronPython: Passing Arguments for a Call
http://blogs.msdn.com/haibo_luo/archive/2007/10/01/5230964.aspx

Примеры использования разных способов передачи параметров в функцию - позиционные параметры, параметры со значением по-умолчанию, опциональные параметры, передача параметра по имени.


IronPython: Provide (or not) Argument for by-ref Parameter
http://blogs.msdn.com/haibo_luo/archive/2007/10/04/5284947.aspx

Вызов методов с ref-параметрами.


IronPython Cookbook
http://www.ironpython.info/index.php/Main_Page

Собрание материалов по IronPython.


SimplePrograms
http://wiki.python.org/moin/SimplePrograms

Своеобразные подсказки для тех, кто не хочет держать все время языковые конструкции в голове ;)


DLR Hosting and related stuff...
http://blogs.msdn.com/seshadripv/default.aspx

Релизная версия IronPython 2.0 работает поверх Dynamic Language Runtime. Если вам (не дай бог :) ) придется интегрировать хостинг Python-скриптов с вашим .NET-приложением, то тут можно почерпнуть максимум возможной информации.

понедельник, 9 февраля 2009 г.

Тест. Какая культура вам ближе?

Решил расслабить мозги после тяжелого трудового понедельника очередным тестом :)

Поздравляем!!! Вам ближе американская культура
Вас зовет земля свободы! Вам импонируют американское видение жизни и ценности "нового света". image
Пройти тест

пятница, 30 января 2009 г.

KDE 4.2. Релиз для всех.

Выпущен релиз KDE 4.2, который, как утверждают разработчики, уже готов для конечного пользователя.

До этого было два релиза, которые опционально включались в дистрибутивы, однако не были готовы к повседневному использованию простыми смертными.


Обзор. Можно ограничиться просмотром картинок :)
http://adymo.blogspot.com/2009/01/kde4-review-from-inside-out-part-1.html
http://adymo.blogspot.com/2009/01/kde-42-review-from-inside-out-part-2.html

Я с большим интересом наблюдаю за развитием ветки 4.x. Было даже несколько попыток установить его на свой дистрибутив Ubunut. Однако каждый раз я возвращался на стабильный Gnome. Хотя во многих моментах KDE 4.x мне нравится больше чем Gnome.

Отмечу так же что стабильный релиз KDE 3.5 мне вообще не нравился.