Flutter and chill – Telegram
Flutter and chill
124 subscribers
34 photos
1 video
21 links
Разработка и жизнь
Download Telegram
В Русском музее, оказывается, одновременно несколько интересных выставок проходит 😳

Очень сложный выбор, хочется сходить на все и сразу 🥲

UPD: в выходные узнаете, что я в итоге выбрала 👩‍🍳
Please open Telegram to view this post
VIEW IN TELEGRAM
11
Крутая новость, команда Яндекса обновила Хэндбук по Flutter 😳

В нем и так была база для подготовки к собеседованиям и обновлению знаний, так еще и добавили разделы про архитектуру, тестирование и взаимодействие с нативом 😎

Мне в свое время очень помог раздел про рендеринг, наконец смогла сложить в голове концепции того, как это происходит под капотом 🧑‍💻
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍5🔥2
Осень - мое любимое время для посещения музеев

Приобщились к прекрасному, посетив сразу две временные выставки в Русском музее 🤠

Узнали о тенденциях русского искусства начала 20 века на выставке Наш Авангард, из зала в зал прослеживался творческий поиск авторов в разных направлениях, от импрессионизма до кубизма.

И конечно не могли пройти мимо выставки работ Архипа Куинджи, мастера по работе со светом. Впервые с его творчеством я познакомилась, впервые посетив Третьяковскую галерею. Помню, что зависла на несколько минут перед "Ночью на Днепре", казалось что отражение луны в ночном пейзаже светится изнутри.
В Русский музей ее конечно тоже привезли, но мне показалось странным решение выделить под нее отдельный зал с тусклым освещением и установленными прожекторами по бокам. 💪

А вы находите время ходить на выставки? Если да, какая последняя вас реально зацепила? ☺️
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍5💅4💘2
Спонсор моих ранних подъемов ❤️
Please open Telegram to view this post
VIEW IN TELEGRAM
10💅3💘2
🧑‍💻 Поговорим про тестирование?

В последнее время плотно занималась увеличением показателя покрытия тестами, поэтому хочу поделиться своими мыслями на этот счет.

Зачем вообще писать тесты? 😊

Провокационный вопрос, но я знаю что среди моих дорогих подписчиков есть те, кто их не пишет. 0 осуждения, 100% понимания ❤️
Для себя выделила базовые причины, по которым стоит покрывать тестами код:

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

🔵документирование кода - написанные тесты по сути выступают описанием фичи: что происходит и какой результат ожидаем.

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

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

А вы как относитесь к тестам? Пишете их или обходитесь ручным тестированием? Может, есть свои лайфхаки? Делитесь в комментариях 🍿
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥1
Поздравляю всех с пятницей 💜

Знаю, что у кого-то и на выходных работа не заканчивается, но стоит иногда взять паузу и похвалить себя за хорошую работу 🐈
Please open Telegram to view this post
VIEW IN TELEGRAM
💘64💅3🔥1
В Pinterest появилась настройка видеть меньше AI слопа 😳

Сразу же все отключила, т.к частенько захожу на Pinterest в поисках вдохновения, но количество нейронных картинок угнетало 🥺
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥73💅3👍1
Как упростить себе жизнь при тестировании

В предыдущем посте про тестирование я упомянула про хорошую структуру кода для написания тестов, хочу сегодня раскрыть эту тему 😮

👩‍💻 Тестируемый код - это код, в котором внешние зависимости и влияния среды выполнения (например, текущее время, состояние файловой системы, ответы сети) изолированы от основной бизнес-логики и могут быть подменены при тестировании.

🤕 Антипаттерн - создание зависимостей внутри метода:

class UserService {
String getUserName() {
final api = ApiClient(); // каждый раз создается новый инстанс 🥲
final user = api.fetchUser();

return user.name;
}
}


Проблема в том, что такой объект не получится замокать, поэтому решением будет вынос зависимости через конструктор и регистрация в Dependency Injection.

✔️ Теперь можно замокать наш ApiClient, используя mocktail:

class UserService {
final ApiClient api;

UserService(this.api);

String getUserName() {
final user = api.fetchUser();
return user.name;
}
}

// Это упрощенная версия теста, в обычном случае создаем мок, доступный внутри группы тестов
test('getUserName возвращает имя', () {
final mockApi = MockApiClient(); // моковый апи клиент
when(() => mockApi.fetchUser())
.thenReturn(User(name: 'user')); // пишем нужную заглушку для тестируемого метода

final service = UserService(mockApi); // прокидываем мок в конструктор
final result = service.getUserName();

expect(result, 'user');
});


😠 Коварные статические методы, например DateTime.now(), SharedPreferences.getInstance().

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

String getGreeting() {
final hour = DateTime.now().hour; // зависит от реального времени
return hour < 12 ? 'Доброе утро!' : 'Добрый день!';
}


В этом примере зависимость на конкретный час, не позволяющая протестировать все возможные варианты.

✔️ Для решения этой проблемы существует пакет clock - это провайдер текущего времени, позволяющий зафиксировать время в тестах.

String getGreeting() {
final hour = clock.now().hour; // заменили DateTime на clock
return hour < 12 ? 'Доброе утро!' : 'Добрый день!';
}

// В тесте фиксируем время на 9 утра
test('В 9 утра возвращается верный результат', () {
final fixedClock = Clock.fixed(DateTime(2025, 1, 1, 9));

withClock(fixedClock, () {
final greeting = getGreeting();
expect(greeting, 'Доброе утро!');
});
});


🤥 В SharedPreferences есть встроенный метод setMockInitialValues для инициализации с заданным набором значений для тестирования:

test('Получение значения темы из Preferences', () async {
SharedPreferences.setMockInitialValues({'theme': 'dark'});

expect(await getTheme(), 'dark');
});


🙄 Работа с асинхронными операциями (например, Future.delayed, Timer, Stream.periodic)

Можно использовать либу FakeAsync , которая позволяет контролировать время их выполнения и сократить время на выполнение тестов.

В ней также есть интеграция с пакетом clock и при его использовании не требуется дополнительных действий, так как FakeAsync автоматически оверрайдит его на том же уровне, что и классы dart:async.

Например:

Future<DataModel> loadData() async {
await Future.delayed(const Duration(minutes: 2));
return DataModel(status: 'loaded');
}

test('данные загружаются корректно', () {
fakeAsync((async) {
final future = loadData();

expect(future, completion(equals(DataModel(status: 'loaded'))));

// пропускаем 2 минуты
async.elapse(const Duration(minutes: 2));
});
});


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

Интересно узнать, с какими проблемами вы сталкивались при тестировании. Делитесь в комментариях (кто смог дочитать до конца) 🍿
Please open Telegram to view this post
VIEW IN TELEGRAM
10🔥12👍6💘42
Когда тревога перед новым делом берёт верх, задайте себе вопрос: а что интересного я могу узнать в процессе?

Такой подход помогает почувствовать интерес и любопытство, а не давление от ожидания идеального результата
7🔥3💘2💅1
Объединение потоков во Flutter

👀 Недавно вышло видео с интригующим названием The great thread merge, где мистер Craig рассказывает о прошлом и будущем флаттера в контексте потоков (threads).

🔜 Как было: Раньше между платформенным потоком и UI существовал разрыв, из-за чего все обращения к апи нативной платформы с использованием Platform Channels были асинхронными. Каждый вызов сопровождался сериализацией данных, переключением контекста и ожиданием ответа - даже если нативная функция возвращала результат мгновенно.

🔥 С версии 3.29 ситуация изменилась: Dart-код теперь исполняется в том же потоке, что и платформенный UI. Это означает, что вызовы нативных функций могут быть синхронными, без необходимости оборачивать их в Future. Типобезопасность теперь обеспечивается механизмом FFI (Foreign Function Interface) и инструментом ffigen, который генерирует Dart-биндинги к C-API.

⚡️ На практике это открывает новые возможности: плагины могут быть переписаны так, чтобы вызовы типа получения уровня батареи, статуса сети или доступа к датчикам возвращали значение сразу. Виджеты становятся проще - вместо StatefulWidget можно обойтись обычным StatelessWidget, если данные доступны синхронно.

🧑‍💻 Сейчас возможно отключить объединение потоков на Windows и macOS используя флаг:

project.set_ui_thread_policy(flutter::UIThreadPolicy::RunOnSeparateThread)

Попыталась найти аналогичный для мобильных платформ, но оказалось что он уже выпилен 🥹

🧑‍💻 Это серьезное архитектурное изменение, которое позволит писать больше Dart кода, но не стоит забывать о производительности: тяжёлые операции должны выноситься в изоляты, иначе они заблокируют UI 🔪
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥11👍3💅31💘1
Сегодня хочу поделиться полезным видео по асинхронному программированию в Dart 😦

Затронуты практически все основные темы, которые, к тому же, часто спрашивают на собеседовании:

🟣Что такое async/await

🟡Виды Future и можно ли его отменить, обработка ошибок

🔵Принцип работы Event loop

🟢Очень много базы про стримы (Stream), работа с StreamController и Zone

Да, видео с таким количеством информации не может быть коротким, но подача хорошая и довольно много наглядных примеров 😱
Please open Telegram to view this post
VIEW IN TELEGRAM
17🔥5
Небольшая задача на асинхронность 👍

В каком порядке выполнятся функции? В следующем посте будет опрос с правильным вариантом ответа 🧑‍💻


void testEventLoop() {
print(1);

scheduleMicrotask(() => print(2));

Future(() => print(3))
.then((_) => print(4));

Future.microtask(() => print(5));

Timer.run(() => print(6));

Future.delayed(Duration.zero, () => print(7));

Future(() async {
print(8);
await Future.delayed(Duration(milliseconds: 1));
print(9);
});

Future.sync(() => print(10));

print(11);
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8💅4
Update Dart Spec 🍿

В репозиторий спецификации языка добавили сразу несколько черновиков новых фич 🔫

1️⃣ Implied Parameter/Record Field Names
Позволяет в момент вызова метода, функции или конструктора опускать имя аргументов, если у передаваемой ему на вход переменной (функции) аналогичное имя:

Пример с функциями/методами:
// before
var subnoscription = stream.listen(
onData,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);

// after
var subnoscription = stream.listen(
onData,
:onError,
:onDone,
:cancelOnError,
);


Пример с переменными:
typedef Color = ({int red, int green, int blue, int alpha});

// before
Color colorWithAlpha(Color color, int newAlpha) {
var (:red, :green, :blue, alpha: _) = color;
return (red: red, green: green, blue: blue, alpha: newAlpha);
}

// after
Color colorWithAlpha(Color color, int alpha) {
var (:red, :green, :blue, alpha: _) = color;
return (:red, :green, :blue, :alpha);
}


2️⃣ Anonymous Methods (AM)

А вот это уже зверь из области функциональщины, который позволяет добавлять объекту анонимные методы и выстраивать цепочки из них, передавая результат одного анонимного метода в вызов другого 😏
Допустим, у нас есть блок кода, который ну никак не представить в виде цепочки последовательных вызовов с помощью каскадного оператора ..
void main() {
final String halfDone, result;
final sb = StringBuffer('Hello');
sb.write(',');
halfDone = sb.function toString() { [native code] }();
sb.write(' ');
sb.write('world!');
result = sb.function toString() { [native code] }();
print('Creating an important string: $halfDone then $result');
}


С добавлением одной из вариаций анонимного метода (=>) и использованием каскадного оператора его можно преобразить следующим образом:
void main() {
final String halfDone, result;
final sb = StringBuffer('Hello')
..write(',')
..=> halfDone = function toString() { [native code] }() // AM
..write(' ')
..write('world!')
..=> result = function toString() { [native code] }(); // AM
print('Creating an important string: $halfDone then $result');
}


Другая вариация подразумевает конструкции типа O.{что-то делаем} или O.{что-то делаем}.{получаем результат предыдущей АМ и снова что-то делаем}.{и т.д.}. Благодаря ней мы можем переписать код так:
// применяем AM к StringBuffer('Hello').
void main() => StringBuffer('Hello').{
final String halfDone, result;
write(',');
halfDone = function toString() { [native code] }();
write(' ');
write('world!');
result = function toString() { [native code] }();
print('Creating an important string: $halfDone then $result');
};


или так
void main() {
// применяем AM к StringBuffer('Hello').
StringBuffer('Hello').{
write(', world!');
return function toString() { [native code] }();
}.{ // определяем следующий анонимный метод
// `this` is the string returned by
`toString()`.print(length); // Prints '13'.
return length > 10;
}.=> print('That was a ${this ? 'very' : '') long string!');
}


Если же мы хотим избежать конфликта имен или явно работать захваченным ранее объектом, который передаем в анонимный метод можно использовать конструкции типа O.(имя и тип арг1, [арг 2, арг3, ...]){что-то делаем} и выстраивать с ними цепочки различной длины:
class A {
void bar() {}
void foo() {
StringBuffer('Hello').(sb) { // sb -> StringBuffer('Hello')
sb.write(', world!');
this.bar(); // `this` refers to the current instance of `A`.
return sb.function toString() { [native code] }();
}.(s) { // снова АМ
print(s.length);
bar(); // An implicit `this` also refers to the current `A`.
return s.length > 10;
}.(cond) => print('That was a ${cond ? 'very' : '') long string!'); // АМ
}
}


Как вам новые фичи Dart?

👍 – О, да, детка!!!
👌 – Сомнительно, но Окей
👎 – Отстой!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍2👎1
Октябрь 2025: первые посты, впечатления от посещения конференции, тесты, асинхронка

Нас уже 85 🥳
Планирую продолжать делиться новостями, полезными материалами и темами, которые считаю важными в разработке 🧑‍💻

Очень радуюсь вашему интересу к контенту и активности под постами, кого-то даже получилось вдохновить на написание тестов ❤️

А вот посты за прошедший месяц:

🟣Вводный пост
рефлексия по созданию этого канала, возможно в будущем дополню

🟣Впечатления от конференции Стачка 2025 впервые посетила такую большую конфу, перечислила новые и интересные для меня темы

🟣Долгожданное обновления хэндбука по Flutter
добавили много новых тем, советую ознакомиться

🟣Сходила на выставки в Русском музее
мои впечатления о выставках искусства начала 20 века

🟣Когда стоит покрывать тестами код
размышления о тестировании, подчеркнула важность написания тестируемого кода

🟣Как упростить себе жизнь при тестировании
практические советы по неочевидным моментам, примеры использования пакетов для стабильных тестов

🟣Архитектурные изменения во Flutter - The great thread merge
важная новость о будущем Flutter, новый способ взаимодействия с платформой

🟣Видео с базой по асинхронному программированию в Dart
поделилась полезным видео с базой по асинхронке

🟣Задача на асинхронность
проверили знание порядка выполнения операций
Please open Telegram to view this post
VIEW IN TELEGRAM
107🔥5💅2
Уровень моей удачи - слечь с температурой на выходные и праздники 🤧
Восприняла это как сигнал о необходимости передохнуть, скоро вернусь с новыми силами и постами 😶
Please open Telegram to view this post
VIEW IN TELEGRAM
115👎2