Вопросы к UI. Шаблон компонента. Введение

в 10:14, , рубрики: пользовательские интерфейсы, синтаксис, фронтенд
Вопросы к UI. Шаблон компонента. Введение - 1

Не знаю как до вас донести это, и насколько осторожно следует подбирать слова.
Мне больно от того, как сейчас происходит создание пользовательских интерфейсов, а существующие подходы кажутся каким‑то недоразумением. И поймите, речь обо всех платформах — веб, мобилки, десктоп. Будучи разработчиком, и исследуя «новые» способы реализации UI, сквозь годы опыта смотришь на все это дело с тяжелым вздохом, мотаешь головой из стороны в сторону, и все что хочется — захлопнуть крышку ноутбука и заняться чем‑то другим. А сталкиваясь с этим изо дня в день на работе — не знаю, как мы не кричим от этого, правда не знаю.

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

Простите за банальнейший пример с молотком, но взяв вместо него плоскогубцы или кирпич, расправиться с гвоздем в целом тоже не проблема. Да, пока вы будете орудовать этим, придется отбиваться от других, выкрикивая — «ну забивается же, че вы?!».
Но, по итогу свою задачу вы выполните.

Вопрос все тот же — насколько это было целесообразно, удобно, эффективно и безопасно?
(говорить будем преимущественно за веб)

Да, вероятно если зарыться куда‑то глубоко, в исходники любой из платформ, можно попытаться найти какой‑то базовый архитектурный изъян, некое аппаратное ограничение, несовместимость, или выявить изначально неверный подход. Даже если вы отыщете подобное, начинать лечение системы с такого несколько глупо, — на это, по сути, нельзя повлиять. Нельзя просто взять и внести изменения во что‑то фундаментальное, особенно когда на нем держится почти весь интернет, и когда оно не принадлежит вам. И точно также не имея за спиной достаточной поддержки сообщества, ресурсов корпорации, или феи на плече — нельзя просто взять и написать весь веб с 0.

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

Позвольте напомнить, что на дворе уже почти 2025ый. Всесторонняя цифровизация, повсеместные нейросети, 5g, блокчейн, роботы, электрокары, спутники, Илон Маск в конце концов.

Тому же вебу уже сколько? 35 лет? А сколько длится борьба ui‑фреймворков? лет 20?
А сколько их было, в том числе непопулярных? Сотня, две?

Ну довольно, вернемся к нашей теме.

Начнем с кусочков кода — освежим картинку в голове.
Просто бегло посмотрите на это. У меня ощущение что можно вообще ничего не говорить.

React

 <div>
  <h1>Todo List</h1>
  <input 
	type="text" value={newTodo} 
	onChange={(e) => setNewTodo(e.target.value)} placeholder="Add a new task" 
  />
  <button onClick={addTodo}>Add Todo</button>
  <ul>
	{todos.map(todo => (
	  <li key={todo.id}>
		{todo.text} 
		<button onClick={() => removeTodo(todo.id)}>Delete</button>
	  </li>
	))}
  </ul>
</div>

Vue

<div>
	<h1>Todo List</h1>
	<input v-model="newTodo" type="text" placeholder="Add a new task" />
	<button @click="addTodo">Add Todo</button>
	<ul>
	  <li v-for="todo in todos" :key="todo.id">
		{{ todo.text }} 
		<button @click="removeTodo(todo.id)">Delete</button>
	  </li>
	</ul>
</div>

Angular

<div>
  <h1>Todo List</h1>
  <input [(ngModel)]="newTodo" placeholder="Add a new task" />
  <button (click)="addTodo()">Add Todo</button>
  <ul>
	<li *ngFor="let todo of todos">
	  {{ todo.text }} 
	  <button (click)="removeTodo(todo.id)">Delete</button>
	</li>
  </ul>
</div>

Svelte

<div>
  <h1>Todo List</h1>
  <input bind:value={newTodo} placeholder="Add a new task" />
  <button on:click={addTodo}>Add Todo</button>
  <ul>
    {#each todos as todo (todo.id)}
      <li>
        {todo.text}
        <button on:click={() => removeTodo(todo.id)}>Delete</button>
      </li>
    {/each}
  </ul>
</div>

Верно, это просто синтаксис шаблонов основных фронтовых фреймворков и библиотек.
(верстка ToDoList)

Что объединяет все примеры?
HTML и схожие конструкции? Возможно, но нет. Суть в том что все это лишь синтаксический сахар.
Напомню, синтаксический сахар — способ написания кода, с целью сделать его более понятным, уместным и удобным для программиста. Еще раз, суть синтаксического сахара — упростить код, сделать его более выразительным, при этом не изменяя базовую функциональность языка. Если посмотреть на это обывательски — он может быть абсолютно любым, — вы можете пихнуть в него всего пару букв, или матерное слово, или даже вставить эмоджи, а на выходе все это дело будет преобразовываться в реальный код. Таким образом вы можете скрыть вызов одной маленькой функции, или целую портянку длиной в несколько модулей всего за одну букву.
Что это дает? Как минимум — возможность реализовать это иначе.

Забудьте на минуту о своем прошлом опыте, нюансах реализации фронтенда, веба, о тех.наследии, о том как работает святая троица и как происходит рендеринг, про общепринятость и нормы. С учетом абзаца выше, ответьте себе — разрабатывая синтаксис для описания пользовательских интерфейсов, имея абсолютно развязанные руки, вы бы тоже сделали его таким? Тоже бы проектировали его похожим на старую разметку, использовали бы теги, угловые скобки для них? Также маскировали бы название компонента под тег? Слепили бы в нелепую кашу html css и js? Реализовали бы основные конструкции рендеринга именно так?

Добрая половина интернета уже давно не просто странички в браузере, это полноценные приложения, некоторые из которых столь огромны что с их объемом не справляются современные IDE (да, монолиты исчезают, но их по‑прежнему много).
Меняются потребности, мы в поисках новых подходов — к реактивности, к способу задания стилей, к организации кода, к стандартизации. Так почему не сделать некоторую небольшую «революцию» в сторону иного синтаксиса.
Почему бы не сделать его более приятным, более простым, чистым, и читаемым, более нативным в конце концов.

Как мы знаем, интерфейсы, это далеко не только веб.
Так что давайте посмотрим — что там у других.

Небольшая историческая справка:

android

  • до 2017 - Интерфейс создавался через XML, основной язык — Java

  • 2017 - Основным языком для разработки становится Kotlin

  • 2020 - Jetpack Compose позволяет разрабатывать UI без XML, используя Kotlin

ios

  • до 2014 - UI строится на Objective-C с XML-подобной разметкой

  • 2014 - Появление Swift с простым синтаксисом

  • 2019 - SwiftUI заменяет XML-разметку на декларативный синтаксис

ios/android

  • 2018 - выход первой версии Flutter

Посмотрим, как это все выглядит

Java, Kotlin (до появления Jetpack Compose)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter new task"
        android:inputType="text" />

    <Button
        android:id="@+id/addButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add Todo" />

    <RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Kotlin + Jetpack Compose

Column(modifier = Modifier.padding(16.dp)) {
	Text(text = "Todo List", style = MaterialTheme.typography.h5)

	TextField(
		value = newTodo,
		onValueChange = { newTodo = it },
		label = { Text("Add a new task") },
		modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp)
	)

	Button(onClick = {
		if (newTodo.isNotBlank()) {
			todos = todos + Todo(newTodo, Random.nextInt())
			newTodo = ""
		}
	}) {
		Text(text = "Add Todo")
	}

	Spacer(modifier = Modifier.height(16.dp))

	LazyColumn(modifier = Modifier.fillMaxWidth()) {
		items(todos) { todo ->
			TodoItem(todo = todo, onDelete = { id ->
				todos = todos.filter { it.id != id }
			})
		}
	}
}

SwiftUI

some View {
	VStack {
		TextField("Add a new task", text: $newTodo)
			.padding()
			.textFieldStyle(RoundedBorderTextFieldStyle())
		
		Button(action: {
			if !newTodo.isEmpty {
				todos.append(newTodo)
				newTodo = ""
			}
		}) {
			Text("Add Todo")
				.padding()
				.background(Color.blue)
				.foregroundColor(.white)
				.cornerRadius(5)
		}
		
		List(todos, id: .self) { todo in
			Text(todo)
		}
		.padding()
	}
	.padding()
}

Flutter

Scaffold(
  appBar: AppBar(
	title: Text('Todo List'),
  ),
  body: Padding(
	padding: const EdgeInsets.all(8.0),
	child: Column(
	  children: [
		TextField(
		  controller: _controller,
		  decoration: InputDecoration(labelText: 'Add a new task'),
		),
		SizedBox(height: 10),
		ElevatedButton(
		  onPressed: _addTodo,
		  child: Text('Add Todo'),
		),
		SizedBox(height: 20),
		Expanded(
		  child: ListView.builder(
			itemCount: _todos.length,
			itemBuilder: (ctx, index) {
			  final todo = _todos[index];
			  return ListTile(
				title: Text(todo['text']),
				trailing: IconButton(
				  icon: Icon(Icons.delete),
				  onPressed: () => _removeTodo(todo['id']),
				),
			  );
			},
		  ),
		),
	  ],
	),
  ),
);

Если отбросить сложный анализ с уклонном на особенность платформ, реактивность и прочие нюансы, глядя на любой из примеров можно увидеть следующие. У нас есть теги/компоненты, наша задача — выстроить из них некую композицию, передать в них необходимые пропс, связать их с данными, навесить на них слушатели, и прописать некоторую минимальную логику.

Это, пожалуй, все основные составляющие шаблона. Где остальное? где‑то выше или ниже, в теле компонента. А шаблон должен быть чистым. Иначе как вы его потом читать будете?

Да, я не шибко в восторге от реализаций на мобилках, их шаблоны по‑прежнему полны излишеств, и поэтому выглядят крайне грязно. Но то, что они сделали в свое время и впрямь революция. Думаю, не трудно догадаться что я предвзят к html/xml, и поэтому рад что подобный синтаксис, хотя бы на этих платформах ушел в прошлое, или преимущественно был спрятан под капот. Также не поддерживаю подход с полным отделением верстки от логики, не вижу, как это возможно в современных реалиях (про xml).

Ну что, у вас есть: tagName, props и children.
Осталось только объединить их. Ну, почти)
И на этом все? Пока да

Разумеется, дело не только в шаблоне.
Да и данная работа — лишь вступление, в одну статью все разом не впихнуть.
Ее цель только в том, чтобы спросить вас — вам правда нравится описывать шаблоны компонентов подобными способами? Не видите ли в этом чего-то отталкивающего, чего-то что можно качественно улучшишь? Скажите, вас правда не тошнит с текущих подходов веба, с существующих фреймворков, и той же верстки?
И нет — не призываю вас идти на баррикады, или бросать любимое дело, фреймворк, или работу.

Просто хочу чтобы вы осознали — рано или поздно это случится, мы уйдем от старых подходов, какими бы фундаментальными и устоявшимися они не казались.
Год, два, пять... Все это произойдет, вот увидите

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

Посмотрим, как пойдет, и возможно все это будет и на ютубе, а возможно и нет, в общем напишите что‑нибудь нехорошее снизу, спасибо!

Автор: fcrng

Источник


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js