161.79K
Category: programmingprogramming

Fluent — стиль организации публичных интерфейсов библиотек

1.

FLUENT API
https://github.com/kontur-courses/fluent-api

2.

FLUENT — ЭТО СТИЛЬ ОРГАНИЗАЦИИ
ПУБЛИЧНЫХ ИНТЕРФЕЙСОВ
БИБЛИОТЕК

3.

FLUENT API – КАК?
Концентрируется на удобстве трех сценариев:
1. Изучение API с нуля
2. Чтение чужого кода, использующего API
3. Написание кода, использующего API
Как это достигается?
1. Подсказки IDE помогают изучать API
2. Код читается как документация на него
3. Method chaining позволяет не отвлекаться на
навигацию и подглядывание в документацию

4.

ПРИМЕРЫ FLUENT API?
//LINQ
points
.Select(p => p.X)
.ToList();
// NUnit
Assert.That(myOwnObject,
Is.GreaterThan(42).Using(myComparer));
// jQuery
$(".menu-item")
.click(function (item) {
$(item)
.addClass("active")
.find(".content")
.fadeIn("fast")
.css("margin-right", "10px");
});

5.

ПРИМЕРОВ НАМНОГО БОЛЬШЕ!
• LINQ
• NUnit
• FluentAssertions
• StatePrinter
• AutoFixture
• DeepEquals
• Ninject
• FakeItEasy
• EntityFramework
• ...

6.

СВЯЗЬ МЕЖДУ FLUENT И IMMUTABLE?
// Immutable → Fluent
var numbers =
ImmutableSortedSet<int>.Empty
.Add(1).Add(2).Add(3)
.Intersect(new[]{ 2, 3, 4 })
.Union(new[] { 42 });
// Fluent → Immutable
var greet = new Spectacle()
.Say("Привет мир!");
var greetAndAsk = greet.Say("Как дела?");
var greetAndBye = greet.Say("Чао!");
greetAndBye.Play(); // ?

7.

КОГДА СТОИТ СОЗДАВАТЬ?
• Сложный API, много взаимосвязанных методов
• Много пользователей: важно, чтобы было легко
освоиться
• Будут активно пользоваться
Почему не использовать всегда?
• Долго разрабатывать

8.

EMBEDDED DSL
Fluent API – своего рода встроенный DSL
Вы выражаете мысли в рамках синтаксиса
основного языка (C#), но не пишите компилятор

9.

С ЧЕГО НАЧАТЬ СОЗДАНИЕ API?
Сначала придумайте синтаксис - потом уже
пишите реализацию!
А синтаксис хорош?
• Напишите Acceptance-тесты
• Покажите примеры синтаксиса коллегам

10.

КАКИЕ ТЕХНИКИ ИСПОЛЬЗУЮТСЯ?
var spectacle = new Spectacle()
.Say("Привет мир!")
.Delay(TimeSpan.FromSeconds(1))
.UntilKeyPressed(s => s
.Say("Тра-ля-ля")
.Say("Тру-лю-лю")
.Delay(TimeSpan.FromSeconds(1))
)
.Say("Пока-пока!")
.Say("До встречи!");
1. Method chaining
2. Делегат с параметром-контекстом
3. Extension methods при наличии Shedule

11.

ПРОДВИНУТЫЕ ТЕХНИКИ

12.

КОНТЕКСТЫ
IEnumerable<Person>
IEnumerable<Person>
IOrderedEnumerable<Person>
IOrderedEnumerable<Person>
IEnumerable<Person>
var result = list
.Where(person => person.Age > 18)
.OrderBy(person => person.Age)
.ThenBy(person => person.Name)
.Take(10)
.ToArray();

13.

КОНТЕКСТЫ
var spectacle = new Spectacle()
.Say("Привет мир!")
.Delay(TimeSpan.FromSeconds(1))
.UntilKeyPressed(s => s
.Say("Тра-ля-ля")
.Say("Тру-лю-лю")
.Delay(TimeSpan.FromSeconds(1))
)
.Say("Пока-пока!")
.Say("До встречи!");

14.

КОНТЕКСТЫ
• void-контекст
• Ограниченный контекст
• Расширенный контекст
• Новый контекст
• Вложенный контекст

15.

ГРАФ КОНТЕКСТОВ
Начальный
контекст
void

16.

EXPRESSION<FUNC<...>>
A.CallTo(() => p.Method()).Returns(42);
CallContext<T> CallTo<T>(Expression<Func<T>> e)
{
var propInfo =
((MemberExpression)memberSelector.Body)
.Member as PropertyInfo
}

17.

ЗАДАЧА OBJECTPRINTING
Разработать библиотеку для преобразования любого
объекта в строку, перечисляя значения публичных
свойств и полей объекта.
Все должно гибко настраиваться. А именно:
1. Исключить из сериализации свойства определенного типа
2. Указать альтернативный способ сериализации для
определенного типа
3. Для числовых типов указать культуру
4. Настроить сериализацию конкретного свойства
5. Настроить обрезание значений строковых свойств
6. Исключить из сериализации конкретное свойство

18.

РАЗБОР ЗАДАЧИ OBJECTPRINTING
Difficulty level Nightmare
Доделайте ObjectPrinter

19.

ПРАВИЛА ХОРОШЕГО FLUENT API

20.

ВЕДИТЕ
• Разрабатывайте API так, чтобы им нельзя было
воспользоваться неправильно
• Если это не получается, кидайте диагностические
ошибки
• Делайте тексты ошибок понятными! Иначе вас
проклянут коллеги
• В XML-документации можно написать то, что не
очевидно из имен и сигнатур

21.

ТЕСТИРУЙТЕ
• Пишите Acceptance-тесты — они отлично
работают как документация
• Тестируйте понятность API, показывая
Acceptance-тесты коллегам

22.

СКРЫВАЙТЕ ДЕТАЛИ
Скрывайте детали реализации из подсказок
Intellisense
public class SomeFluentContext : IContextProperties
{
IEnumerable<string> IContextProperties.SomeState { get; }
}

23.

ОБРАТНАЯ СВЯЗЬ
Заполни форму обратной связи по ссылке
http://bit.ly/kontur-courses-feedback
или
по ярлыку feedback в корне репозитория
English     Русский Rules