Pull to refresh

Семь лет WPF: что изменилось?

Programming.NETC#
Translation
Original author: Paul Stovell
Прим. перев.: это перевод статьи Six years of WPF; what's changed?, написанной 3 августа 2012 года. Сейчас WPF уже не шесть, а семь лет, однако ничего не изменилось.

До перехода в 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:
  1. Создан новый, дружественный человеку язык разметки (Razor). Когда пишешь на Razor, получаешь удовольствие. Написание XAML никогда не доставляло удовольствия. Более того, до того, как в ReSharper'е появился «Импорт пространства имён», оно было сущим кошмаром.
  2. Избраны дизайн-паттерны. И не говорите, что в WPF есть MVVM — да, WPF поддерживает байндинги, но в ядре WPF нет ни единой фичи, сколь-нибудь помогающей с MVVM. Это всё прилеплено сбоку через Blend Behaviors и сторонние фреймворки. В ASP.NET же весь стек построен на MVC.
  3. Попал в пропасть успеха. Вы реально можете написать поддерживаемое приложение на ASP.NET MVC, используя стандартный шаблон проекта. А стандартный шаблон WPF без сторонних фреймворков — это путь мучений и невзгод.
  4. Избрана расширяемость. Практически всё в ASP.NET MVC основано на интерфейсах и абстрактных классах, которые вы можете расширить, изменив тем самым поведение фреймворка. Готов поклясться, команда WPF слыхом не слыхивала про интерфейсы, а немногие абстрактные классы имеют internal конструкторы.
  5. Избран опен-сорс. ASP.NET включает jQuery и JSON.NET, и прекрасно совмещается с бесчисленными опен-сорсными инструментами. WPF, несмотря на нескончаемый список MVVM фреймворков, и несмотря на полную невозможность разработки поддерживаемого приложения без такового, до сих пор их не включает.
  6. Стал опен-сорсом. Исходники 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:
  1. Позволить определять импорты пространств имён на уровне проекта, а не заставлять повторять в каждом файле.
  2. Позволить байндить события напрямую к методам, а не через команды.
  3. Сделать синтаксис байндинга короче и более запоминаемым.
  4. Позволить использовать выражения на C# и булеву логику вместо написания конвертеров на каждый чих.
  5. Позволить булево значение неявно конвертировать в трёхзначное Visibility без конвертера.
  6. Избавиться от префиксов для невстроенных контролов.

Команда 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...
Only registered users can participate in poll. Log in, please.
Вы используете WPF?
26.72% Да, активно разрабатываю на WPF/Silverlight 544
20.14% Попробовал(а) пару раз, понравилось 410
21.46% Попробовал(а) пару раз, больше не хочется 437
15.82% Нет 322
15.86% Кто мне наконец объяснит, что такое WPF? 323
2036 users voted. 306 users abstained.
Only registered users can participate in poll. Log in, please.
Как вы пишете на WPF?
20.6% Имею MVVM фреймворк собственного приготовления 228
31.8% Использую сторонний MVVM фреймворк (MVVM Light, Prism, Caliburn и т.п.) 352
45.98% Какие к чёрту фреймворки? Только Button1_Click, только хардкор! 509
12.38% Чтобы не писать много, использую Blend и/или ручного дизайнера, в XAML лезу только при острой необходимости 137
2.53% Чтобы не писать много, использую кодогенерацию (T4, Python и т.п.) 28
8.4% Чтобы не писать много, совершаю финты ушами с markup extensions, потомками binding и т.п. 93
2.44% Использую другой способ сокращения писанины (опишу в комментариях) 27
19.06% А мне нравится писать много! Меньше понимающих мой код — меньше шансов быть уволенным(ой)! 211
1107 users voted. 747 users abstained.
Tags:.netwpfmvvmxamlпечальгрустьретроспектива
Hubs: Programming .NET C#
Total votes 76: ↑63 and ↓13 +50
Views68.9K

Comments 225

Only those users with full accounts are able to leave comments. Log in, please.

Popular right now