До перехода в Octopus Deploy на полную ставку я провёл год за написанием на WPF системы оценки рисков для трейдеров в инвестиционном банке. До того я работал консультантом, по большей части фокусируясь на WPF. Последние шесть лет я жил и дышал технологией, и в этом посте я хочу поделиться некоторыми мыслями о прошлом и будущем WPF и XAML.
Шесть лет назад я написал статью про валидацию в WPF на Code Project. Ещё я написал свой error provider, который поддерживает IDataErrorInfo, потому что — вы не поверите! — WPF 3.0 не поддерживал IDataErrorInfo. Позже я работал над несколькими опенсорсными WPF проектами вроде Bindable LINQ (первоначального реактивного программирования для WPF, ещё до изобретения Rx) и Magellan (MVC для WPF а-ля ASP.NET). Я даже некоторое время состоял в клубе, посвящённому превозносению MVVM и киданию ссылок на Code Project, известном как WPF Disciples («Приверженцы WPF»).
Когда я оглядываюсь на WPF, я вижу технологию с отличным фундаментом, которая была испорчена плохой реализацией и, что более важно, отсутствием финансовых вложений. Я рад, что для меня это в прошлом.
Вот как в далёком 2006-м году выглядела разметка относительно простого окошка (код позаимствован из проекта, над которым я тогда работал):
<Window x:Class="PaulStovell.TrialBalance.UserInterface.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tb="clr-namespace:PaulStovell.TrialBalance.UserInterface" xmlns:tbp="clr-namespace:PaulStovell.TrialBalance.UserInterface.Providers" xmlns:system="clr-namespace:System;assembly=mscorlib" Title="TrialBalance" WindowState="Maximized" Width="1000" Height="700" Icon="{StaticResource Image_ApplicationIcon}" Background="{StaticResource Brush_DefaultWindowBackground}" x:Name="_this">
Только взгляните на все церемонии! x:Class! Пространства имён XML! Почему бы не объявить всё это в одном месте, почему бы стандартные пространства имён не включать неявно?
К счастью, сейчас 2013-й год, и WPF был проделан огромный путь. Вот как код будет выглядеть сейчас:
<Window x:Class="PaulStovell.TrialBalance.UserInterface.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tb="clr-namespace:PaulStovell.TrialBalance.UserInterface" xmlns:tbp="clr-namespace:PaulStovell.TrialBalance.UserInterface.Providers" xmlns:system="clr-namespace:System;assembly=mscorlib" Title="TrialBalance" WindowState="Maximized" Width="1000" Height="700" Icon="{StaticResource Image_ApplicationIcon}" Background="{StaticResource Brush_DefaultWindowBackground}" x:Name="_this">
Видите разницу? Я тоже не вижу. Да, за шесть прошедших лет никто пальцем не шевельнул, чтобы избавиться от избыточности кода.
Давайте для сравнения взглянем на код странички ASP.NET 2006-го года (тоже из проекта тех лет):
<%@ Page Language="C#" MasterPageFile="~/TrialBalance.Master" AutoEventWireup="true" EnableViewState="false" CodeBehind="Builds.aspx.cs" Inherits="PaulStovell.TrialBalance.MainWebsite.Builds" Title="Downloads - TrialBalance" %> <asp:Content ID="Content1" ContentPlaceHolderID="MainContentPlaceholder" runat="server"> <asp:PlaceHolder runat="server" Visible="false" ID="_downloadAreaPlaceholder"> <h1>Download</h1>
Как эта разметка выглядит сегодня?
@model BuildsViewModel @section Main { <h1>Download</h1> }
Изначально я стал разработчиком WPF, потому что мне были не по душе ASP.NET Web Forms и модели вроде View State. Но сейчас, когда я оглядываюсь на проделанный ASP.NET путь, я вижу огромные изменения. От модели Web Forms до модели MVC, от синтаксиса ASPX до Razor — в лагере ASP.NET действительно занимались инновациями.
Вот неполный список того, что сделано в ASP.NET и не сделано в WPF:
- Создан новый, дружественный человеку язык разметки (Razor). Когда пишешь на Razor, получаешь удовольствие. Написание XAML никогда не доставляло удовольствия. Более того, до того, как в ReSharper’е появился «Импорт пространства имён», оно было сущим кошмаром.
- Приняты дизайн-паттерны. И не говорите, что в WPF есть MVVM — да, WPF поддерживает байндинги, но в ядре WPF нет ни единой фичи, сколь-нибудь помогающей с MVVM. Это всё прилеплено сбоку через Blend Behaviors и сторонние фреймворки. В ASP.NET же весь стэк построен на MVC.
- Попал в пропасть успеха. Вы реально можете написать поддерживаемое приложение на ASP.NET MVC, используя стандартный шаблон проекта. А стандартный шаблон WPF без сторонних фреймворков — это путь мучений и невзгод.
- Принята расширяемость. Практически всё в ASP.NET MVC основано на интерфейсах и абстрактных классах, которые вы можете расширить, изменив тем самым поведение фреймворка. Готов поклясться, команда WPF слыхом не слыхивала про интерфейсы, а немногие абстрактные классы имеют internal конструкторы.
- Принят опен-сорс. ASP.NET включает jQuery и JSON.NET, и прекрасно совмещается с бесчисленными опен-сорсными инструментами. WPF, несмотря на нескончаемый список MVVM фреймворков, и несмотря на полную невозможность разработки поддерживаемого приложения без такового, до сих пор их не включает.
- Стал опен-сорсом. Исходники ASP.NET MVC были открыты с самого начала, но сейчас вообще весь стек ASP.NET стал опен-сорсным и принимает исправления. WPF — нет, и, откровенно говоря, вы бы и не захотели смотреть на код WPF: он ужасен (прим. перев.: можно оценить VirtualizingStackPanel).
Кроме того, сам Веб меняется и развивается на глазах. Не нравится CSS? Попробуйте Less или SASS. Не нравится JavaScript? Попробуйте CoffeeScript или Dart. Сейчас в Вебе богатая экосистема инноваций; инноваций, которых в WPF не было с 2006-го года.
Яблоки против апельсинов и всё такое
Я противопоставляю ASP.NET и WPF не для того, чтобы сказать, что ASP.NET лучше — было бы глупо говорить такое, потому что у них разные цели. Я просто хочу показать, как один за прошедшие шесть лет прошёл огромный путь, а другой практически не изменился. Думаю, всё дело в недостатке инвестиций.
Что обидно, это то, что WPF в своё время начал весьма бодро. Такие понятия как зависимые свойства, стили, шаблоны, концентрация на байндингах звучали революционно, когда был обнародован Авалон (прим. перев. кодовое имя WPF).
К сожалению, когда начинается практика, реализация оказывается посредственной. Зависимые свойства невыносимо многословны, им не помешала бы поддержка на уровне языка. Стили и шаблоны тоже многословны, и значительно ограниченнее CSS (когда WPF только вышел, я ожидал мириады вебсайтов, предлагающих высококачественные темы WPF, как сейчас предлагаются темы HTML; но их нет, потому что это очень сложно).
Связи между данными (bindings) обычно Просто Работают (Just Works), кроме случаев, когда не работают. Реализация INotifyPropertyChanged тоже занимает слишком много кода. Дата-контексты (data contexts) — отличная идея, правда она перестаёт работать для элементов вроде ContextMenu. Интерфейс ICommand был создан для службы двум хозяевам: команда WPF предпочитает routed commands, а команда Blend — паттерн command; в результате ICommand не подходит хорошо ни для того, ни для другого.
XAML
И этот провал — XAML. Язык XAML так избыточен, что сложно представить, что людям предлагается на нём писать. Да потому что не предполагается! В мире розовых пони и радуг дизайнеры используют Blend, а разработчики используют дизайнер Visual Studio, и никто никогда не видит XAML. Однако на дворе 2013-й, и несмотря на прогресс Blend, большинство до сих пор вручную пишет XAML. Visual Studio 2012 этого не изменит.
Однако самая большая проблема XAML не в плохих инструментах. Просто язык не исправили, чтобы справиться с проблемами в инструментарии. И в отличие от HTML, XAML не семантичен. Он не интерпретируется, он компилируется. Это формат сериализации, поэтому нет разделения между разметкой и реализацией.
Вот лишь небольшой список того, что приходит мне на ум для улучшения работы с XAML:
- Позволить определять импорты пространств имён на уровне проекта, а не заставлять повторять в каждом файле.
- Позволить байндить события напрямую к методам, а не через команды.
- Сделать синтаксис байндинга короче и более запоминаемым.
- Позволить использовать выражения на C# и булеву логику вместо написания конвертеров на каждый чих.
- Позволить булево значение неявно конвертировать в трёхзначное Visibility без конвертера.
- Избавиться от префиксов для невстроенных контролов.
Команда ASP.NET смогла написать совершенно новый парсер (Razor), почему нельзя сделать даже простейшие изменения в WPF?
MVVM
Словами не передать, как устал я слышать про этот паттерн, особенно от бывших разработчиков на WinForms, которые решили, что MVVM — самый смак, потому что они прочитали Silverlight Unleashed и были поражены MVVM Light.
На самом деле на каждом проекте WPF, который мне довелось видеть, находился шибко умный чувак, который думал, что он достаточно умён, чтобы написать свой собственный MVVM фреймворк, который в результате оказывался криво переписанным кодом из какой-нибудь статьи на Code Project. В конечном итоге во всех проектах WPF возникает класс ViewModelBase, набитый до отказа наследуемыми методами для управления потоками, прогресс-барами и INotifyPropertyChanged. Показ диалога занимает в 20 раз больше кода, чем если просто написать код в Button1_Click, и это в результате будет в той же мере хорошо протестировано — большинство людей, использующих MVVM, утверждает, что делает это ради лучшей тестируемости, но на самом деле никто не пишет юнит-тесты для вью-моделей, кроме архитекторов, которые и изобретают MVVM фреймворки.
Про MVVM слышно на каждом углу, но отсутствие поддержки на уровне платформы означает, что каждый WPF разработчик обречён написать несколько плохих, плохо поддерживаемых WPF приложений, прежде чем поймёт, как делать это правильно. Это досадно.
Заключение
В итоге, когда я оглядываюсь на шесть лет работы с WPF, я понимаю, что он основан на нескольких хороших идеях, которые были не очень хорошо реализованы. То же самое можно сказать и про первые версии ASP.NET (кто-нибудь помнит про Web Parts в ASP.NET 2.0?)
Но есть одно большое отличие: ASP.NET эволюционировал. Веб-стек эволюционировал. Изменился не только код, но и философия команды. WPF же не увидел ни одного серьёзного изменения с 2006-го года.
Больше всего огорчает то, что нет альтернативы. В мире Веба ASP.NET конкурирует с Ruby и PHP — если не нравится один, то можно выбрать другой. На Windows десктопе я по сути прикован к WPF.
Вы можете получать удовольствие от работы с WPF. Вы можете думать, что XAML — прекрасный, чёткий, удобный язык. Я тоже так думал в 2006-м, и если платформа до сих пор вам в радость, это хорошо. Она с нами надолго, потому что настоящей альтернативы нет. Но что же касается меня, то я рад, что дни WPF для меня позади, и что моя работа основана на ASP.NET.
Примечание переводчика
Во многом я разделяю точку зрения автора, однако десктоп всё ещё остаётся мне ближе Веба, и поэтому я верен WPF. Но смотрю я иногда на код, и хочется чего-то лучшего… А когда глядишь на примерчики конкурента в лице Qt, то понимаешь, что скоро они в C++ будут иметь то, о чём в мы в C# и мечтать не могли. Почему в ядрёном нативном языке есть элегантный JSON, приправленный JavaScript’ом, а в управляемом языке — этот монструозный и нечитаемый XAML с портянками из мультитриггеров с мультибайндингами и элементом Setter.Value?
Как происходит разработка на WPF у вас? У вас есть свой MVVM фреймворк? У вас есть ViewModelBase? У вас есть BoolToVisibilityConverter и IsNotNullConverter?
Эх, только бы конкурент у WPF появился. Серьёзный, популярный. Тогда, быть может, Microsoft забеспокоилась бы о развитии WPF…
ссылка на оригинал статьи http://habrahabr.ru/post/165273/
Добавить комментарий