<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Yet another developer's blog</title><generator>teletype.in</generator><description><![CDATA[Обезличенный личный блог начинающего программиста, не упускающего возможности научиться чему-то новому]]></description><image><url>https://teletype.in/files/cc/8b/cc8b5e8a-7527-4d16-b742-06011358b1c9.png</url><title>Yet another developer's blog</title><link>https://teletype.in/@yadevblog</link></image><link>https://teletype.in/@yadevblog?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/yadevblog?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/yadevblog?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Sat, 11 Apr 2026 16:19:35 GMT</pubDate><lastBuildDate>Sat, 11 Apr 2026 16:19:35 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@yadevblog/typed-config-dotnet-6</guid><link>https://teletype.in/@yadevblog/typed-config-dotnet-6?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/typed-config-dotnet-6?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>Подключение валидации к строго типизированной конфигурации в .NET 6+</title><pubDate>Thu, 02 Feb 2023 11:49:06 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/42/96/4296eca6-5217-4ff4-a69a-eb673dfee332.png"></media:content><category>dotnet</category><description><![CDATA[<img src="https://andrewlock.net/content/images/2018/06/unhandled_exception_configuration_validation.png"></img>Эта статья — перевод статьи Эндрю Лока.]]></description><content:encoded><![CDATA[
  <p id="eB0f"><strong>Эта статья — перевод <a href="https://andrewlock.net/adding-validation-to-strongly-typed-configuration-objects-in-dotnet-6/" target="_blank">статьи Эндрю Лока</a>.</strong></p>
  <h2 id="EESt">Строго типизированная конфигурация в ASP.NET Core</h2>
  <p id="K5iH">Система конфигурации в .NET очень гибкая. Она позволяет загружать параметры из разных мест: <a href="https://docs.microsoft.com/en-gb/aspnet/core/fundamentals/configuration/index?view=aspnetcore-2.1&tabs=basicconfiguration#json-configuration" target="_blank">JSON файлы</a>, <a href="https://andrewlock.net/creating-a-custom-iconfigurationprovider-in-asp-net-core-to-parse-yaml/" target="_blank">YAML файлы</a>, <a href="https://docs.microsoft.com/en-gb/aspnet/core/security/app-secrets?view=aspnetcore-2.1&tabs=windows#environment-variables" target="_blank">переменные окружения</a>, <a href="https://docs.microsoft.com/en-gb/aspnet/core/security/key-vault-configuration?view=aspnetcore-2.1&tabs=aspnetcore2x" target="_blank">Azure Key Vault</a> и многое другое. В статье предлагается использовать конечный объект <code>IConfiguration</code> в приложении чтобы настроить строгую типизацию.</p>
  <p id="Csj9">Строго типизированная конфигурация с помощью простых объектов описывает часть вашей конфигурации вместо обычного хранения пар &quot;ключ-значение&quot; в <code>IConfiguration</code>.</p>
  <p id="WgJw">Допустим, вы настраиваете интеграцию со Slack, и для <a href="https://api.slack.com/incoming-webhooks" target="_blank">отправки сообщений  в канал используете вебхуки</a>. Вам понадобится URL вебхука, и какие-нибудь дополнительные параметры, например имя приложения, которое будет использоваться для отправки сообщений в канал:</p>
  <pre id="NMer" data-lang="clike">public class SlackApiSettings {
    public string WebhookUrl { get; set; }
    public string DisplayName { get; set; }
    public bool ShouldNotify { get; set; }
}</pre>
  <p id="2gdv">Этот объект можно привязать к вашей конфигурации в <em>Program.cs </em>используя метод расширения <code>Configure&lt;T&gt;()</code>. Когда вам понадобится этот объект в контроллере, вы можете внедрить зависимость <code>IOptions&lt;SlackApiSettings&gt;</code> в его контроллер. Например, чтобы внедрить конфиги в Minimal API эндпоинт и вернуть JSON с ними можно сделать так:</p>
  <pre id="M4SR" data-lang="clike">using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

// связка конфигурации с секцией SlackApi
// например SlackApi:WebhookUrl и SlackApi:DisplayName 
builder.Services.Configure&lt;SlackApiSettings&gt;(
    builder.Configuration.GetSection(&quot;SlackApi&quot;)); 

var app = builder.Build();

// вернуть объект конфига
app.MapGet(&quot;/&quot;, (IOptions&lt;SlackApiSettings&gt; options) =&gt; options.Value);

app.Run();</pre>
  <p id="UOYk">Под капотом система конфигурации ASP.NET Core создаёт новый объект <code>SlackApiConfiguration</code> и пытается сопоставить каждое свойство в объекте со значениями в секции <code>IConfiguration</code>.</p>
  <p id="Ruym">Чтобы получить объект конфигурации, обратитесь к <code>IOptions&lt;T&gt;.Value</code>, как показано в обработчике эндпоинта.</p>
  <h2 id="PBQC">Избегание зависимости IOptions</h2>
  <p id="b09j">Некоторым людям (мне в том числе) не нравится зависимость эндпоинтов от IOptions вместо объекта конфигурации напрямую. Вы можете избежать зависимости от <code>IOptions&lt;T&gt;</code> сопоставив объект конфигурации вручную, <a href="https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/" target="_blank">как описано здесь</a>, вместо использования метода расширения <code>Configure&lt;T&gt;</code>. Более простой подход (по моему мнению) это явно зарегистрировать объект <code>SlackApiSettings </code>в приложении и делегировать его определение на объект <code>IOptions</code>. Например:</p>
  <pre id="kB4n" data-lang="clike">using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

// Регистрируем объект IOptions
builder.Services.Configure&lt;SlackApiSettings&gt;(
    builder.Configuration.GetSection(&quot;SlackApi&quot;));

// Явно регистрируем объект конфигурации, делегируя определение на IOptions
builder.Services.AddSingleton(resolver =&gt; 
        resolver.GetRequiredService&lt;IOptions&lt;SlackApiSettings&gt;&gt;().Value);

var app = builder.Build();</pre>
  <p id="UP47">Теперь в контроллеры можно внедрять &quot;сырой&quot; объект настроек, без зависимости от пакета Microsoft.Extensions.Options. Я думаю, что это более предпочтительный способ, потому что в этом случае интерфейс <code>IOptions&lt;T&gt;</code> не нужен.</p>
  <pre id="xOgp" data-lang="clike">app.MapGet(&quot;/&quot;, (SlackApiSettings options) =&gt; options);

app.Run();</pre>
  <p id="q5DB">Обычно это работает хорошо, хотя тут есть пара нюансов:</p>
  <ul id="C35U">
    <li id="dSW6">В примере выше не будет работать &quot;перезагрузка файла&quot; для конфигурации, так как я использовал Singleton (можно использовать Scoped, если вам нужна эта функция)</li>
    <li id="CArw">При регистрации IOption появляется дополнительный уровень косвенности, вместо регистрации объекта SlackApiSettings напрямую в механизме внедрения зависимостей. Лично мне нравится такой подход, но вы можете использовать IOptions. Есть еще один подход, описанный в этом <a href="https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/" target="_blank">посте</a>.</li>
  </ul>
  <p id="yfFP">Наличие отличной поддержки загрузки конфигурации из разных источников это хорошо, но что будет, если вы ошибётесь в конфигурации, например допустите опечатку в JSON файле?</p>
  <p id="W9wL">Чаще всего я сталкивался с проблемой, возникающей из-за того, что секреты необходимо хранить вне системы контроля версий. В таком случае я <em>ожидаю</em>, что секреты будут доступны на продакшн-сервере, но если они не были корректно настроены, в приложении конфигурация получит значения типа &quot;по умолчанию&quot;. Ошибки конфигурации сложно отловить, ведь их можно воспроизвести только на сервере.</p>
  <h2 id="7Wxb">Что случится, если сопоставление проваливается?</h2>
  <p id="1DeP">Есть несколько случаев, когда что-то может пойти не так при сопоставлении строго типизированных объектов с конфигурацией. Я покажу несколько примеров ошибок в JSON конфигурации, используя пример обработчика, написанный выше.</p>
  <h3 id="DfZU">Опечатка в названии секции</h3>
  <p id="u5qc">При сопоставлении конфигурации вы указываете имя секции, откуда брать значения. Если думать в терминах файла <em>appsettings.json</em>, секция — это название ключа объекта в JSON. <code>&quot;Logging&quot;</code> и <code>&quot;SlackApi&quot;</code> это секции в приведённом ниже <em>.json</em> файле:</p>
  <pre id="EROG" data-lang="javascript">{
 &quot;Logging&quot;: {
    &quot;LogLevel&quot;: {
      &quot;Default&quot;: &quot;Warning&quot;
    }
  },
  &quot;AllowedHosts&quot;: &quot;*&quot;,
  &quot;SlackApi&quot;: {
    &quot;WebhookUrl&quot;: &quot;http://example.com/test/url&quot;,
    &quot;DisplayName&quot;: &quot;My fancy bot&quot;,
    &quot;ShouldNotify&quot;: true
  }
}</pre>
  <p id="ggyJ">Чтобы связать <code>SlackApiSettings</code> с секцией <code>&quot;SlackApi&quot;</code>, можно сделать:</p>
  <pre id="owUZ" data-lang="clike">builder.Services.Configure&lt;SlackApiSettings&gt;(
    Configuration.GetSection(&quot;SlackApi&quot;)
); </pre>
  <p id="WPT1">Но что если в названии секции будет допущена опечатка? Например вместо SlackApi укажем SlackApiSettings:</p>
  <pre id="u1aM" data-lang="clike">builder.Services.Configure&lt;SlackApiSettings&gt;(
    Configuration.GetSection(&quot;SlackApiSettings&quot;)
); </pre>
  <p id="mSRj">Вызов эндпоинта даст:</p>
  <pre id="eNVB" data-lang="clike">{&quot;webhookUrl&quot;:null,&quot;displayName&quot;:null,&quot;shouldNotify&quot;:false}</pre>
  <p id="dyRH">Все ключи получили значение по умолчанию, но никаких ошибок не произошло. Сопоставление произошло, но с пустой секцией конфигурации. Наверное, это плохо, потому что ваш код ожидает, что в <code>webhookUrl</code> будет валидный <code>Uri</code>.</p>
  <blockquote id="K93q">Примечание переводчика: Вообще, чтобы решить эту проблему можно вместо <code>Configuration.GetSection</code> использовать <code>Configuration.GetRequiredSection</code>. Тогда при попытке сопоставить объект с несуществующей секцией возникнет исключение.</blockquote>
  <h3 id="EoiE">Опечатка в названии свойства</h3>
  <p id="cxMq">Что произойдёт, если название секции верно, но неверно название свойства?<br />Например, что если <code>WebhookUrl</code> будет записан в файле как <code>Url</code>?</p>
  <pre id="wsjo" data-lang="javascript">{
  &quot;SlackApi&quot;: {
    &quot;Url&quot;: &quot;http://example.com/test/url&quot;,
    &quot;DisplayName&quot;: &quot;My fancy bot&quot;,
    &quot;ShouldNotify&quot;: true
  }
}</pre>
  <p id="xCt1">Посмотрим на результат:</p>
  <pre id="sp78" data-lang="clike">{&quot;webhookUrl&quot;:null,&quot;displayName&quot;:&quot;My fancy bot&quot;,&quot;shouldNotify&quot;:true}</pre>
  <p id="L1Yz">Так как название секции правильное, <code>DisplayName</code> и <code>ShouldNotify</code> попали в объект конфигурации правильно. Но <code>WebhookUrl</code> равен <code>null</code>, так как в конфигурации нет такого поля (<code>Url</code> вместо него). И снова никаких сообщений о том, что поле не обработалось корректно.</p>
  <h3 id="w1jS">Несвязываемые поля</h3>
  <p id="o6SY">Эта ошибка встречается не слишком часто, но о ней всё же стоит знать. Если вы используете в объекте конфигурации поля без сеттера, они не свяжутся. Например, если мы изменим объект следующим образом:</p>
  <pre id="qm3I" data-lang="clike">public class SlackApiSettings
{
    public string WebhookUrl { get; }
    public string DisplayName { get; }
    public bool ShouldNotify { get; }
}</pre>
  <p id="797M">и снова посмотрим на ответ эндпоинта, мы получим объект со значениями по умолчанию так как парсер не сможет установить значение в объект:</p>
  <pre id="Owz7" data-lang="clike">{&quot;webhookUrl&quot;:null,&quot;displayName&quot;:null,&quot;shouldNotify&quot;:false}</pre>
  <h3 id="RFR9">Несовместимые типы данных</h3>
  <p id="B41T">И последняя ошибка в этом посте происходит, когда парсер пытается связать поля с несовместимыми типами данных. В конфигурации всё представлено в виде строк, но парсер может преобразовывать простые типы. Например <code>&quot;true&quot;</code> или <code>&quot;FALSE&quot;</code> нормально преобразуется в поле <code>bool ShouldNotify</code>, но если вы попытаетесь запихать туда что-нибудь ещё, например <code>&quot;THE VALUE&quot;</code>, вы получите исключение, когда будете дёргать эндпоинт и парсер попытается собрать объект <code>IOptions&lt;T&gt;</code>:</p>
  <figure id="r67p" class="m_retina">
    <img src="https://andrewlock.net/content/images/2018/06/unhandled_exception_configuration_validation.png" width="667.5" />
    <figcaption>Скриншот (c) Andrew Lock</figcaption>
  </figure>
  <p id="6iEF">Факт получения ошибки не очень хороший, но хотя бы парсер вообще кидает исключение, которое чётко даёт понять в чём проблема! Я слишком много раз попадал в ситуации, когда вызовы к внешнему API не отрабатывали только потому, что в объект конфигурации не попадала строка подключения или базовый URL из-за ошибки связывания.</p>
  <p id="4VXm">Об ошибках конфигурации вроде этой лучше всего сообщать как можно раньше. Лучше всего во время компиляции, но и при запуске тоже неплохо. Поэтому нам нужна валидация.</p>
  <h2 id="TSyB">Валидация значений <code>IOptions</code></h2>
  <p id="BMVZ">Валидация значений в <code>IOptions</code> появилась еще в .NET Core 2.2 с методами <code>Validate&lt;&gt;</code> и <code>ValidateDataAnnotations()</code>. Их проблема в том, что они не запускаются со стартом приложения, только в момент получения доступа к <code>IOptions</code>. Это было частичным решением проблемы, поэтому я создал <a href="https://www.nuget.org/packages/NetEscapades.Configuration.Validation/" target="_blank">NuGet пакет</a>, который запускал валидацию на старте приложения.</p>
  <p id="JmFi">К счастью, в .NET 6 <a href="https://github.com/dotnet/runtime/issues/36391" target="_blank">появился метод</a> <code>ValidateOnStart()</code>, который делает в точности то, что нам нужно — запускает валидацию при старте приложения!</p>
  <blockquote id="miA3">Если вам интересно, как это реализовано: Фишка в использовании <code>IHostedService</code> для валидации. Реализацию можно посмотреть в <a href="https://github.com/dotnet/runtime/pull/47821/files" target="_blank">этом PR</a>.</blockquote>
  <p id="iujj">Чтобы использовать такую валидацию, нужно сделать четыре вещи:</p>
  <ul id="7r2N">
    <li id="ko9q">Переключиться на <code>services.AddOptions&lt;T&gt;().Bind()</code> вместо <code>services.Configure&lt;T&gt;()</code></li>
    <li id="GnyE">Добавить атрибуты валидации к объекту конфигурации</li>
    <li id="r4wi">Вызвать <code>ValidateDateAnnotations()</code> <code>OptionsBuilder</code>&#x27;а, возвращённого из <code>AddOptions&lt;T&gt;()</code></li>
    <li id="RtLi">Вызвать <code>ValidateOnStart() OptionsBuilder</code>&#x27;а.</li>
  </ul>
  <p id="4rUW">Метод расширения <code>IServiceCollection.AddOptions&lt;T&gt;()</code> ведёт себя как альтернативная версия <code>Configure&lt;T&gt;()</code>: </p>
  <ul id="1G80">
    <li id="mvQe"><code>AddOptions&lt;T&gt;()</code> возвращает объект <code>OptionsBuilder&lt;T&gt;</code> вместо <code>IServiceCollection</code></li>
    <li id="25ig">Нужно вызвать <code>Bind()</code> объекта <code>OptionsBuilder&lt;T&gt;</code> чтобы связать конфиг с объектом.</li>
  </ul>
  <p id="ideG">Использование объекта <code>OptionsBuilder&lt;T&gt;</code> открывает новые возможности для добавления нового функционала вроде валидации.</p>
  <blockquote id="NKJy">Вспомогательное расширение BindConfiguration() было добавлено в OptionsBuilder, чтобы упростить связывание секций конфигураций. В следующем блоке будет показано, как это сделать.</blockquote>
  <p id="HH0R">Добавим атрибуты валидации к SlackApiSettings и настроим валидацию в приложении:</p>
  <pre id="rrxj" data-lang="clike">using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOptions&lt;SlackApiSettings&gt;()
    .BindConfiguration(&quot;SlackApi&quot;) // 👈 Связать секцию SlackApi
    .ValidateDataAnnotations() // 👈 Включить валидацию
    .ValidateOnStart(); // 👈 Валидировать при старте

// Явно зарегистрируем объект конфигурации,
// делегировав его объекту IOptions
builder.Services.AddSingleton(resolver =&gt; 
        resolver.GetRequiredService&lt;IOptions&lt;SlackApiSettings&gt;&gt;().Value);

var app = builder.Build();

app.MapGet(&quot;/&quot;, (SlackApiSettings options) =&gt; options);

app.Run();

public class SlackApiSettings
{
    [Required, Url]
    public string WebhookUrl { get; set; }
    [Required]
    public string DisplayName { get; set; }
    public bool ShouldNotify { get; set; }
}</pre>
  <blockquote id="oi9g">Обратите внимание, что здесь я использовал DataAnnotations, но можно использовать другие фреймворки для валидации [п/п: У автора есть <a href="https://andrewlock.net/adding-validation-to-strongly-typed-configuration-objects-using-flentvalidation/" target="_blank">статья</a> про подключение FluentValidation к этому механизму, её перевод выйдет следующим]</blockquote>
  <h2 id="mJtG">Тестирование конфигурации на старте приложения</h2>
  <p id="KfSX">Мы можем проверить валидацию, использовав любой из примеров с ошибками <a href="#7Wxb">выше</a>.  Например, если мы допустим опечатку в названии поля, то при запуске приложения до обработки любых запросов получим исключение:</p>
  <pre id="WF0y" data-lang="clike">Unhandled exception. Microsoft.Extensions.Options.OptionsValidationException: 
  DataAnnotation validation failed for &#x27;SlackApiSettings&#x27; members: 
    &#x27;DisplayName&#x27; with the error: &#x27;The DisplayName field is required.&#x27;.
   at Microsoft.Extensions.Options.OptionsFactory&#x60;1.Create(String name)
   at Microsoft.Extensions.Options.OptionsMonitor&#x60;1.&lt;&gt;c__DisplayClass10_0.&lt;Get&gt;b__0()</pre>
  <p id="xSsp">Теперь, если в конфиге встретится ошибка, вы узнаете об этом сразу, не дожидаясь того, что приложение упадёт в рантайме. Оно просто не запустится, а если вы используете окружение вроде Kubernetes, проверки состояния не пройдут и на боевом сервере останется рабочая версия, пока вы не почините ошибки конфигурации.</p>
  <h2 id="9MvG">Вывод</h2>
  <p id="qOtL">Система конфигурации в ASP.NET Core очень гибкая и позволяет использовать строгую типизацию. Кроме того, из-за этой гибкости, некоторые ошибки могут возникать только в определённых окружениях. По умолчанию эти ошибки будут появляться только при попытке получить доступ к объекту конфигурации.</p>
  <p id="frte">В этом посте я показал как использовать <code>ValidateOnStart()</code> метод, появившийся в .NET 6 для того, чтобы проверять конфигурацию на старте приложения. Это позволит как можно раньше убедиться в том, что приложение получило правильную конфигурацию.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@yadevblog/developer-windows</guid><link>https://teletype.in/@yadevblog/developer-windows?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/developer-windows?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>Windows для разработчика</title><pubDate>Sat, 07 Jan 2023 19:24:13 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/52/1c/521c698a-4a79-45cb-aab2-4cb0d9f75743.png"></media:content><category>it</category><description><![CDATA[Хэй! Новый год, новая статья на спорную тему! Так вышло, что обретя новый ноут с видеокартой Nvidia при использовании Linux я получил больше страданий, чем удовольствия. То перегрев словлю, то тиринг выбесит. В общем, я решил дать винде шанс и перебраться на неё на постоянку (до этого у меня был дуалбут, потому что периодически мне нужен Windows-специфичный софт)]]></description><content:encoded><![CDATA[
  <p id="HEZ2">Хэй! Новый год, новая статья на спорную тему! Так вышло, что обретя новый ноут с видеокартой Nvidia при использовании Linux я получил больше страданий, чем удовольствия. То перегрев словлю, то тиринг выбесит. В общем, я решил дать винде шанс и перебраться на неё на постоянку (до этого у меня был дуалбут, потому что периодически мне нужен Windows-специфичный софт)</p>
  <p id="GUcl">Сейчас я сижу на Windows 11, Beta Channel, мой стек технологий это .NET и React.js. Да, я из тех людей, что пишут на .NET на линуксе, и им норм. Хотя казалось бы, технология майков, бла-бла-бла... Но на самом деле, когда майки выпустили .NET официально на все платформы и открыли исходники, отпала необходимость в Mono и стало вообще хорошо.</p>
  <h2 id="0yKf">IDE</h2>
  <p id="xFLG">Я человек простой. Обожаю всё, что выпускаетJetbrains, поэтому в этом плане переезд затруднений не вызвал. Rider и Webstorm как работали на линуксе, так и работают здесь.</p>
  <p id="i49i">Искренне презираю Visual Studio. По моему мнению, у нее перегруженный интерфейс, неинтуитивное управление вкладками, убогие комбинации клавиш и паршивый редактор.</p>
  <p id="Nupx">К сожалению, Rider не всесилен и не имеет всех возможностей студии + не сразу получает поддержку новых версий платформы, так что иногда приходится-таки включать студию. Но разрабы молодцы и достаточно быстро вносят нужные изменения.</p>
  <h2 id="z9Nj">CLI</h2>
  <p id="dRLY">Люблю консольные приложения в линуксе за их простоту и очевидность. Вообще мне близка философия Unix &quot;всё есть файл&quot;. Это очень удобно, когда конфиг любого приложения находится там, где ты его ожидаешь увидеть и это просто текстовый файл, который можно открыть чем угодно и прочитать его глазами.</p>
  <p id="xEcu">В винде всё не так. У тебя есть стопицот папок, где приложения оставляют свой мусор, а конфиги порой хранятся в бинарных файлах, которые и открыть-то нечем. А еще есть великий и ужасный реестр, в котором в каком-то только системе понятном формате хранятся килотонны значений. А как это чистить? А как бэкапить? Загадка...</p>
  <p id="Oscv">А как вам синтаксис Powershell?</p>
  <p id="5cN3">Например для того, чтобы в линуксе получить путь до бинарника (иногда бывает нужен в скриптах) используется программа <code>which</code> (или <code>where</code>, зависит от дистрибутива). В Powershell для этого нужен целый <code>(get-command binary).Path</code></p>
  <p id="cjeF">Или вот еще — достаточно частая встречаемая штука — поиск в текстовом файле. Типичный линуксовый <code>cat</code> + <code>grep</code>: <code>cat textfile.txt | grep &#x27;searchquery&#x27;</code>. Что же нам нужно сделать для того же в Powershell? <code>Select-String -Path &quot;textfile.txt&quot; -Pattern &quot;searchquery&quot;.</code> Очень удобно, и писать немного нужно...</p>
  <p id="Ivko">Кто-то может сказать мол &quot;Используй WSL&quot;. Если коротко, то я считаю, что это очен странная попытка майков залезть на территорию линя. По факту, это нативная виртуалка с по умолчанию подмонтированным системным диском. Я пользовался этим исключительно в связке с докером (м-м-м, супер, виртуалка в виртуалке) и думаю, что всё это достаточно ненадёжно. Так, например, у меня так и не вышло заставить вебшторм запускать npm&#x27;овские скрипты в WSL, хотя там такая фича есть. Точнее не просто npm&#x27;овские, а еще с системными командами в комплекте (<code>mv</code>, <code>rm</code> и вот это всё)</p>
  <h2 id="ABcC">&quot;Горе от ума&quot;</h2>
  <p id="YMbg">Это моя старая шутка про то, что винда считает, что знает, что нужно пользователю, больше чем пользователь. Например, я закрыл студию и проект, который в ней был открыт, иду в проводник, пытаюсь удалить этот проект, а мне говорят, что папка используется каким-то процессом. Хм, странно. Смотрю в &quot;Мониторе ресурсов&quot; — и правда, папка проекта на кой-то чёрт занята процессом System. WTF?! Естественно, это не тот процесс, который можно просто взять и остановить. Спустя несколько выходов из спящего режима, система эту папку так и не отпустила. И зачем она ей нужна, вопрос...</p>
  <h2 id="uAK0">Вместо вывода</h2>
  <p id="PSvN">В целом, винда вполне подходит для разработки, но не для любого стека и с кучей нюансов. Как дотнетщику, мне в принципе без разницы.</p>
  <p id="gBQr">Но вот скоро мне нужно будет писать большой проект на джаве, там я вернусь обратно на линь. Нафиг мне это не сдалось страдать здесь.</p>
  <p id="kN08">Тот же докер лучше работает под линуксом (если это не так, тогда почему авторы докера не стали воротить своих костылей с виртуализацией винды и просто завернулись под WSL?). Поэтому для обучения DevOps я тоже буду использовать линь.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@yadevblog/how-i-hated-java</guid><link>https://teletype.in/@yadevblog/how-i-hated-java?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/how-i-hated-java?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>Как я возненавидел Java</title><pubDate>Sat, 27 Aug 2022 09:38:02 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/f5/19/f519a9c2-e6eb-4ee0-95eb-9ee60d086b94.png"></media:content><category>it</category><description><![CDATA[Весьма претенциозный заголовок, не находите? Впрочем, после недавнего проекта для меня он стал близок к истине. Я, если не возненавидел, то точно сильно разочаровался в Java и её экосистеме.]]></description><content:encoded><![CDATA[
  <p id="QSpR">Весьма претенциозный заголовок, не находите? Впрочем, после недавнего проекта для меня он стал близок к истине. Я, если не возненавидел, то точно сильно разочаровался в Java и её экосистеме.</p>
  <p id="GKUf">С Java я и мои <s>ленивые распиз</s> бравые коллеги познакомились по долгу учёбы. Небольшой проект, размером в семестр, казалось бы, что может пойти не так? Оказалось что многое, и даже очень. </p>
  <p id="deV8">Моя аудитория знает, что до этого проекта я писал по большей части на Python, и, за неимением другого опыта, подсознательно сравнивал Java именно с ним. Но языки эти достаточно разные, чтобы сравнивать их напрямую. Поэтому эта статья выходит лишь сейчас, а не в начале лета, когда проект был только завершён, а эмоции, возникавшие при разработке ещё свежи. Я чувствую, что за лето вырос как разработчик, набрался кое-какого опыта с более &quot;серьёзными&quot; технологиями и подостыл.</p>
  <p id="XXWV">Поэтому здесь не будет громких заявлений в духе &quot;Java — говно, Python — лучше всех!&quot;. Я всё ещё считаю Python — лучшим второстепенным языком, который прекрасно решает многие задачи, но не любые, иногда его лучше заменить на что-то более производительное. Java же, наверняка хороша чем-то по-своему, но просто не для меня.</p>
  <p id="Gpin">В этой статье я постараюсь обстоятельно и безэмоционально описать как мы/я писали этот проект, с какими проблемами столкнулись, и какими костылями в спешке затыкали возникающие дыры в преддверии дедлайна, поэтому заваривайте чашку пельменей и приготовьтесь слушать, нам предстоит долгая история.</p>
  <h2 id="YQU4">А что за проект-то собственно?</h2>
  <p id="ChHb">И правда, что я заладил &quot;проект&quot; да &quot;проект&quot;? Прошу любить, жаловать и не жаловаться — &quot;Student Archive&quot;. Мде, полное название оригинальностью не блещет... &quot;STAR&quot; — во, так-то лучше. Это наша первая попытка в EdTech.</p>
  <p id="LyT5">Мы попытались автоматизировать то, что у нас не получилось сделать вручную — собрать архив лабораторных работ, методических материалов и прочих полезностей студента. Не, ну а что? Оно всё равно годами не устаревает.</p>
  <p id="oLaZ">На этот семестр стояла задача написать бэкенд. Для этого был выбран классический REST API, без всякого хипстерского выпендрёжа вроде GraphQL или gRPC.</p>
  <p id="fWW1">Через семестр к этому мракобесию ещё предстоит вернуться, чтобы написать к нему графический интерфейс.</p>
  <p id="FPEm">Почему Java? Честно, я бы с радостью туда вообще не лез, но предмет &quot;Платформонезависимое программирование &quot; к этому обязывал.</p>
  <h2 id="x0bK">Отвратительная документация</h2>
  <p id="RRoH">Для начала — маленькое лирическое отступление: что я считаю <strong>хорошей </strong>технической документацией?</p>
  <ul id="iEpq">
    <li id="zN2J">Хорошо структурирована</li>
    <li id="2sRt">Снабжена примерами кода (но не состоит из них полностью)</li>
    <li id="mHXj">Отдельные страницы индексируются поисковиками</li>
    <li id="ZLla">Желательно содержит мануал по старту работы с технологией</li>
    <li id="OGWt">Не сгенерирована из комментариев к коду</li>
  </ul>
  <p id="1etN">Если брать мир Python, то там отличная документация написана к <a href="https://docs.djangoproject.com/en/4.1/" target="_blank">Django</a>. Несмотря на объемность фреймворка, всё очень хорошо расписано, отлично гуглится, и даже есть несколько пошаговых инструкций по созданию небольших проектов.</p>
  <p id="1Nh6">Что же мы видим, например у Hibernate-ORM?</p>
  <p id="TyyZ">Во-первых: с её помощью можно настраивать подключение к базе данных и описывать таблицы и связи между ними двумя кардинально разными способами</p>
  <ol id="pcu1">
    <li id="19gW">Через XML-файл, в котором вручную описываются все таблицы, типы данных  и связи между таблицами, затем поверх этого пишутся POJO (или &quot;простые старые Java-объекты&quot;). По мне, так этот способ дикость. Как минимум потому, что приходится одну и ту же работу выполнять дважды. По неясной причине документация фокусируется именно на этом способе, фактически игнорируя второй, более &quot;новый&quot; способ (мне кажется забавным употреблять слово &quot;новый&quot;, говоря о Java-мире. Сложилось впечатление, что инновации там происходят раз в 15 лет, но существующий софт совершенно игнорирует их чтобы избежать рефактора)</li>
    <li id="n5Lb">&quot;Новый&quot; же способ заключается в описании моделей через обычные классы, на поля которых навешиваются аннотации, обозначающие обязательность, связи и пр. И никакого XML! Увы, но по этой штуке документации практически нет.</li>
  </ol>
  <p id="tIZT">И тут возникает один вопрос — какого чёрта одна библиотека реализует настолько разные способы описания моделей? В смысле, почему бы не разбить её на две части?</p>
  <p id="UmnT">Во-вторых документация отвратительно структурирована, а страницы совершенно не гуглятся.</p>
  <p id="eKgA">Не знаю, может я один такой ленивый, но когда я работаю с какой-то технологией, я предпочитаю ничего не запоминать, а по мере необходимости гуглить необходимые части библиотеки. Так вот оказывается в Java-мире это так не работает. Гугля что-то, ты попадаешь на список богом забытых форумов, с вопросами, заданными в начале нулевых, ответ на которые даже со свойственной   Java <s>ленью вычищать технический долг</s> &quot;обратной совместимостью&quot; попросту не работает. Или вопрос настолько специфичный, что даже относительно современный ответ на него не решит твоей проблемы. Ну а желания и времени вызубривать всю документацию ради проекта, который я сделаю один раз и забуду напрочь, у меня нет. Так что прощай Hibernate.</p>
  <h2 id="k8vW">Нерабочие туториалы</h2>
  <p id="N2wy">В моём мире, когда ты заходишь на сайт библиотеки, генерируешь там из их шаблона свой проект, затем по их же туториалу редактируешь его под себя, он должен хотя бы запуститься, а не валиться с непонятным исключением в духе &quot;какая-то моя кишка не умеет работать с какой-то реализацией кишки моей зависимости&quot;. Причём оно даже не гуглится. Вот тебе и сгенерированные шаблоны...</p>
  <p id="R7iq">Напоминает времена, когда я несколько лет назад пытался изучить Vue.js. Там скрипт инициализации проекта начал кидаться ошибками несовместимости версий в ответ на попытки подключить линтер. В общем Spring Boot тоже пошёл лесом.</p>
  <h2 id="aPVk">Платный софт и пакеты </h2>
  <p id="tvxc">Возвращаясь к Hibernate. Одно время я подумывал о том, чтобы писать модели, используя XML.</p>
  <p id="EGyY">Естественно, поскольку я человек <s>крайне ленивый</s> стремящийся оптимизировать противные задачи, я стал искать хоть какие-то инструменты, которые избавят меня от необходимости писать XML вручную. Что поделать, меня на физическом уровне отворачивает от этого формата. И почему в Java мире его так любят? Весит относительно много, читается тяжело, парсить — больно.</p>
  <p id="3PSh">Подошло бы что угодно: GUI, DSL...</p>
  <p id="po6a">Как-то я наткнулся на одну программу, которая могла бы решить мою проблему (названия не помню, давно это было): С помощью графического интерфейса нужно было рисовать таблицы, соединять их линиями, чтобы на выходе получить Hibernate-совместимый XML файл. Окей, кажется это то, что нужно. Но вместо кнопки &quot;Скачать&quot; вижу лишь &quot;Купить&quot;. Какое разочарование... Не, я конечно не против платить за лицензионный софт, но не такой, который мне понадобится буквально один раз и который стоит две сотни долларов.</p>
  <p id="c39g">Может есть какие-то альтернативы Hibernate? Нахожу парочку каких-то решений с закрытым исходным кодом и опять же платных. Серьёзно? Кажется я слишком привык к Python-миру, который держится на куче энтузиастов, которые выкладывают свои, бесспорно, огромные труды, в открытый доступ. Мде, Даня, добро пожаловать в суровый мир Enterprise-разработки.</p>
  <h2 id="GIKU">Надо что-то делать</h2>
  <p id="Vtre">Пока я экспериментировал, пытаясь сделать &quot;хорошо&quot; неумолимо приближался дедлайн. Поэтому пришлось засунуть перфекционизм подальше и писать как придётся. В конечном счёте в основу лёг Spark, какой-то малоизвестный и минималистичный веб-фреймворк, достаточно неплохая документация которого поместилась на одну страницу. Ну а доступ к базе данных организовали с помощью JDBC, прямо в коде бросив сырые SQL-запросы. Умеем, практикуем!</p>
  <p id="zCOm">За нехваткой времени в итоге многие эндпоинты были брошены возвращать 501 Not Implemented. Только т-с-с-с!</p>
  <p id="MM52">Впрочем какая разница, если в итоге проект был сдан на &quot;отлично&quot;?</p>
  <h2 id="ggE6">Вместо вывода</h2>
  <p id="mRy7">За время разработки я понял одно: Java — это огромная кроличья нора с кучей легаси, в которую невозможно нырнуть с места. Понадобятся годы кропотливого ковыряния в паршивой документации, чтобы получить цельную картину хорошего приложения.</p>
  <p id="YOqP">Гудбай Java, нам с тобой не по пути. А я погнал учить C# для следущего гигантского проекта.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@yadevblog/react</guid><link>https://teletype.in/@yadevblog/react?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/react?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>React</title><pubDate>Sat, 13 Aug 2022 11:55:00 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/73/8d/738d1854-a9d9-4168-92ac-c69e223fdac3.png"></media:content><category>it</category><description><![CDATA[<img src="https://i1.sndcdn.com/artworks-000526769397-b2oq7x-t500x500.jpg"></img>Несколько лет назад я зарёкся лезть во фронтенд. И где я оказался?]]></description><content:encoded><![CDATA[
  <p id="Gt9M">Несколько лет назад я зарёкся лезть во фронтенд. И где я оказался?</p>
  <figure id="fcu2" class="m_original">
    <img src="https://i1.sndcdn.com/artworks-000526769397-b2oq7x-t500x500.jpg" width="500" />
    <figcaption>Картинка со звуком</figcaption>
  </figure>
  <p id="B6DT">Всему причиной моё стремление пробовать разные штуки.</p>
  <p id="xglE">Я давно хотел поднять свою экосистему сайтов с портфолио, резюме, возможно даже Git-хранилище (хотя не уверен, зачем оно может быть надо)</p>
  <p id="1WFC">Для начала я попробовал вспомнить молодость и написать что-то простенькое без всяких ваших новомодных фреймворков. Это было больно и очень неудобно.</p>
  <p id="3pAg">Тогда я пошёл в ютуб и наткнулся на очень ламповый <a href="https://www.youtube.com/watch?v=bSMZgXzC9AA" target="_blank">ролик</a> одного японца, который, используя только neovim написал красивый сайт-портфолио на react и next.js. Я взял его за основу и написал почти такой же сайт.</p>
  <p id="egqz">Попытался выгрузить его на Github Pages, где хостился мой предыдущий сайт, оказалось, что для анимации рендерятся бэкендом и на старом хостинге отображалась только шапка с кривой темой.</p>
  <p id="Fse4">Что ж. Значит пришло время строить экосистему. Я купил домен и прикрутил его к Vercel, хостингу от создателей Next.js. Что самое крутое, это интеграция с гитхабом — Vercel автоматически деплоит сайт на привязанные домены на каждый пуш в мастер.</p>
  <figure id="Vyy1" class="m_column">
    <img src="https://img1.teletype.in/files/07/49/0749cb9b-fc80-4deb-9329-26c77f102bce.png" width="1280" />
    <figcaption>Вот так <a href="https://dadyarri.ru" target="_blank">сайт</a> выглядит сейчас</figcaption>
  </figure>
  <p id="YPNw">Что я могу сказать по итогу трёх недель колупания в современном фронтенде. Честно говоря, впечатления очень смешанные. Местами удобно, местами неприятно.</p>
  <h3 id="i73L">Плюсы</h3>
  <ul id="kArw">
    <li id="vVNx">Низкий порог входа (я, практически не зная Javascript, начал понимать, что списываю из видео за два вечера)</li>
    <li id="VdCv">Live Reload (можно просто запустить сервер и писать код, не отвлекаясь на перекомпиляцию)</li>
    <li id="bHhL">Next.js берёт на себя весь геморрой со сборкой и запуском проекта, оптимизацией бандлов (даже вебпак работает под капотом, его конфиг не пишется напрямую)</li>
  </ul>
  <p id="qLgE">Пока я это всё писал, я осознал, что объективных-то минусов и нет. Думал, что разосру тут весь фронт, а оказалось, что всё это пустые придирки. <strong>Что ж, я поражён, господа.</strong></p>
  <p id="pQGU">Разве что сюда можно засунуть оверинжиниринг, когда у любого пакета есть туева хуча зависимостей, что приводит к dependency hell, когда разные зависимости зависят от разных версий одного и того же пакета и в итоге всё ломается, но это уже достаточно специфичная штука, которая происходит не всегда.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@yadevblog/nim</guid><link>https://teletype.in/@yadevblog/nim?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/nim?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>Nim</title><pubDate>Sun, 07 Aug 2022 22:12:21 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/d5/15/d5152d4d-01d0-49f8-a3a9-275fcb9b1432.png"></media:content><category>it</category><description><![CDATA[Nim — компилируемый, статически типизированный язык программирования… Ай, к чёрту википедию.]]></description><content:encoded><![CDATA[
  <p id="FKja">Nim — компилируемый, статически типизированный язык программирования… Ай, к чёрту википедию.</p>
  <p id="TeRW">Наткнулся я на него совершенно случайно, когда читал статью на realpython про ускорение кода на Python через си-инклюды. Ужаснулся, закрыл статью, ушёл искать что-то еще.</p>
  <p id="tzhS">В итоге наткнулся на эту <a href="https://habr.com/ru/company/otus/blog/543332/" target="_blank">статью</a>, в которой рассказывается про nimporter в связке с nimpy. Nimpy позволяет nimporter импортировать нимовские модули прямо в питонячий код и работать с ними как обычно. Ну не магия ли это?</p>
  <p id="nt2r">Самый кайф в том, что nim-код компилируется в статический бинарь, которому для запуска не нужны никакие зависимости, скорость на уровне Си, а синтаксис очень простой и сильно напоминает Python (и никаких указателей).</p>
  <p id="uZp9">Правда этим чудо-костылём я так и не воспользовался, потому что не нашёл, чтобы такого в моих микро-проектах можно было бы ускорить и благополучно про nim на какое-то время забыл.</p>
  <p id="MMIF">И тут недавно я переустановил себе Linux (недавно написал статью <a href="https://blog.dadyarri.ru/dotfiles" target="_blank">с обзором конфигов</a>) и как это у меня обычно бывает — начал смотреть “а чего бы такого автоматизировать?”. Листаю свой конфиг шелла и вижу громозкое описание переменной PATH (не нравится мне идея туеву хучу бинарей пихать в системные каталоги, поэтому кастомных путей у меня там полно).</p>
  <p id="tNZZ">Есть идея — запихать все пути из конфига шелла в отдельный файлик и оттуда его считывать в конфиг.</p>
  <p id="pMeL">Что обычно берут люди, когда нужно что-то заскриптовать в линуксе? Правильно — Bash. Bash это что? Попаболь. Возиться с ним не очень-то хочется, ибо синтаксис неочевидный, дебажить проблематично, один гемор короче.</p>
  <p id="2qc2">Попробовал сначала решить эту задачу на Python. Получилось чертовски медленно, а в конфиге шелла скорость очень важна, ведь пока не отработает скрипт конфига, промпт не отрисуется.</p>
  <p id="PINZ">Хорошо, питон отбрасываем. Что у нас еще есть? Раст? Как из пушки по воробьям стрелять… Нужно что-то простое и быстрое. Вспоминаю про Nim. За пару часов написал маленький скриптик. Получилось красиво, быстро, удобно.</p>
  <p id="Mnyc">Теперь вместо длиннющего <code>export PATH=&quot;$PATH:/home/dadyarri/.nimble/bin:/home/dadyarri/.npm/packages/bin:/home/dadyarri/bin:/home/dadyarri/scripts:/home/dadyarri/.local/bin&quot;</code></p>
  <p id="QzWt">стало <code>export PATH=&quot;$PATH:$(/home/dadyarri/bin/getpath)&quot;</code></p>
  <p id="fKc5">Ну не супер ли?</p>
  <p id="jzxc"><strong>Плюсы:</strong></p>
  <ul id="4yo5">
    <li id="8YHY">Красивый, питоноподобный синтаксис;</li>
    <li id="l1Ea">Статическая типизация;</li>
    <li id="TGXo">Высокая скорость запуска;</li>
    <li id="vUKu">Для запуска не нужны зависимости.</li>
    <li id="olvD">Удобный менеджер пакетов nimble (своего репозитория у nim нет, используется git)</li>
  </ul>
  <p id="oP1j"><strong>Минусы:</strong></p>
  <ul id="LjcV">
    <li id="strq">Бардак в стандартной библиотеке (<code>std/parsexml</code>, <code>std/xmlparser</code>, <code>std/xmltree</code>, например);</li>
    <li id="wkQQ">Опциональные круглые скобки при вызове фукнкций (это конечно больше придирка);</li>
    <li id="KRXj">Очень странное ООП. Допустим есть <code>let file: File = open(&quot;somefile.txt&quot;, fileMode.FmWrite)</code>. Можно прочесть его содержимое, вызвав (в моём понимании, как в прочих языках) метод объекта: <code>file.write(&quot;some text&quot;)</code>, а можно, вызвав функцию: <code>write(file, &quot;some text&quot;)</code>;</li>
    <li id="4xTt">Паршивая документация, которая обычно сводится к автоматически сгенерированным из кода спискам методов, перечислений и прочего, причём даже не у всех элементов есть описание;</li>
    <li id="1T73">Местами идиотские сообщения об ошибках, которые вообще не дают никаких подсказок о факапе и единственный способ их решить — лезть в код или в ишью.</li>
  </ul>
  <p id="75P5">Энивей, <a href="https://github.com/nim-lang/Nim" target="_blank">nim</a> классный, есть куда развиваться. Не думаю, что он может стать чем-то серьёзным вроде дотнета (по крайней мере не скоро), но как альтернатива башу для скриптинга вполне себе неплохо.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@yadevblog/dotfiles</guid><link>https://teletype.in/@yadevblog/dotfiles?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/dotfiles?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>Мои настройки Linux</title><pubDate>Thu, 04 Aug 2022 09:08:52 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/33/73/3373c7f1-5ed0-4d83-a7d1-4ec21ca0342b.png"></media:content><category>linux</category><description><![CDATA[<img src="https://img1.teletype.in/files/41/44/4144c77a-001b-4344-ba8b-a38f3a684a65.png"></img>Я в очередной раз сменил дистрибутив (на этот раз Fedora с KDE) и пересобрал с нуля конфигурационные файлы многих программ. Мне нравятся минималистичные интерфейсы, но жертвовать удобством ради этого я не хочу. О том, что в итоге получилось — под катом.]]></description><content:encoded><![CDATA[
  <h2 id="gord">Введение</h2>
  <p id="fja0">Я в очередной раз сменил дистрибутив (на этот раз Fedora с KDE) и пересобрал с нуля конфигурационные файлы многих программ. Мне нравятся минималистичные интерфейсы, но жертвовать удобством ради этого я не хочу. О том, что в итоге получилось — под катом.</p>
  <h2 id="P9XV">Шелл</h2>
  <p id="5Ect">В разное время я несколько раз прыгал от zsh к fish и обратно, но в текущей итерации вернулся на <a href="https://www.zsh.org/" target="_blank">z-shell</a>. Получилась ультимативная штука, которой очень удобно пользоваться. Вот такой набор плагинов я накидал:</p>
  <ul id="gE2A">
    <li id="SRlE"><a href="https://github.com/b4b4r07/enhancd" target="_blank">enhancd</a> — Плагин, который запоминает последние посещённые директории и позволяет переходить по ним по ключевым словам или с помощью <a href="https://github.com/junegunn/fzf" target="_blank">fzf</a></li>
  </ul>
  <figure id="acuD" class="m_original">
    <img src="https://img1.teletype.in/files/41/44/4144c77a-001b-4344-ba8b-a38f3a684a65.png" width="486" />
  </figure>
  <ul id="D1BP">
    <li id="q1gs"><a href="https://github.com/zdharma-continuum/fast-syntax-highlighting" target="_blank">fast-syntax-highlighting</a> — Быстрая подсветка синтаксиса. Альтернатива к решению от zsh-users, которым я пользовался долгое время, но лишённый его проблем. Уж не знаю, насколько быстрее, но точно красивее.</li>
  </ul>
  <figure id="YWAF" class="m_column">
    <img src="https://img3.teletype.in/files/e8/5d/e85dffdb-3b44-4570-b7d0-ad419d823095.png" width="889" />
  </figure>
  <ul id="1BwP">
    <li id="CcQD"><a href="https://github.com/zsh-users/zsh-history-substring-search" target="_blank">zsh-history-substring-search</a> — Плагин который добавляет виджет поиска по подстроке в истории команд. По факту это работает просто — вводится часть команды и стрелками вверх-вниз выбирается нужная команда из истории</li>
  </ul>
  <figure id="WNoj" class="m_original">
    <img src="https://img1.teletype.in/files/06/3b/063bad51-7833-4dbc-afd7-3efe934898cb.png" width="282" />
  </figure>
  <ul id="yjf5">
    <li id="bBBy"><a href="https://github.com/zsh-users/zsh-autosuggestions" target="_blank">zsh-autosuggestions</a> — Плагин, который генерирует подсказки автодополнения, основываясь на истории запущенных команд</li>
  </ul>
  <figure id="T57X" class="m_original">
    <img src="https://img3.teletype.in/files/28/c0/28c0b2ef-05d7-47cc-9c9a-b39dfa18b0c2.png" width="221" />
  </figure>
  <ul id="kvuz">
    <li id="MqQe"><a href="https://github.com/romkatv/powerlevel10k" target="_blank">powerlevel10k</a> — красивая тема с множеством настроек и подключаемых виджетов</li>
  </ul>
  <figure id="n5lQ" class="m_column">
    <img src="https://img2.teletype.in/files/de/dd/dedd2454-3795-4b97-9b64-4238d9d5972f.png" width="1116" />
    <figcaption>Так выглядит шелл в папке с моим сайтом-портфолио, написанном на Javascript — текущая папка, ветка в Git, версия node.js и количество активных задач в консольном таск-менеджере</figcaption>
  </figure>
  <ul id="hvUa">
    <li id="plFv"><a href="https://github.com/Aloxaf/fzf-tab" target="_blank">fzf-tab</a> — Плагин, заменяющий стандартный механизм отрисовки автоподсказок на fzf. Работает с огромным множеством команд, и даже может показать описание флагов некоторых команд</li>
  </ul>
  <figure id="P82F" class="m_original">
    <img src="https://img1.teletype.in/files/88/0f/880f3a10-d8a6-4b02-8fc4-50841fec6256.png" width="336" />
    <figcaption>Подскажет директории, куда можно перейти, если нажать &lt;Tab&gt; после команды &#x60;cd&#x60;</figcaption>
  </figure>
  <figure id="kl37" class="m_original">
    <img src="https://img2.teletype.in/files/d4/ba/d4bae62e-fc84-4c0f-a562-abf995e0b89f.png" width="1109" />
    <figcaption>Подскажет флаги команды &#x60;git branch&#x60;, если нажать &lt;Tab&gt; после команды и знака &quot;-&quot;</figcaption>
  </figure>
  <ul id="aaul">
    <li id="a0HV"><a href="https://github.com/hlissner/zsh-autopair" target="_blank">autopair</a> — Плагин, который автоматически закрывает парные скобки при вводе открывающей. Прямо как взрослые IDE!</li>
    <li id="R8FA"><a href="https://github.com/joshskidmore/zsh-fzf-history-search" target="_blank">fzf-history-search</a> — И еще один плагин для работы с историей. Этот открывает fzf со историей запуска команд. Благодаря ему можно быстро по неточному поиску найти нужную команду, вместо того, чтобы вечность тыкать стрелку вверх</li>
  </ul>
  <figure id="xw9W" class="m_original">
    <img src="https://img2.teletype.in/files/9f/b3/9fb35f3b-154a-4433-9a82-ea7b2de9fa7c.jpeg" width="500" />
  </figure>
  <figure id="yH4t" class="m_column">
    <img src="https://img2.teletype.in/files/95/73/95737b70-c4cc-413e-9231-cc8328a40d17.png" width="1121" />
  </figure>
  <p id="F2mP">Управляет всем этим великолепием <a href="https://github.com/rossmacarthur/sheldon" target="_blank">Sheldon</a> — универсальный менеджер плагинов, который работает как с bash, так и с zsh. Кстати, написан на Rust.</p>
  <h2 id="3v5n">Менеджер конфигов</h2>
  <p id="ksVU">Все конфиги у меня лежат на <a href="https://github.com/dadyarri/dotfiles" target="_blank">гитхабе</a>. Ими нужно как-то управлять, и чтобы не держать в домашней папке гитовый репозиторий (неудобно, есть риск добавить лишнее), я использую <a href="https://chezmoi.io" target="_blank">chezmoi</a>. Он даёт возможность в одну команду без установки сторонних программ быстро перенести все конфиги на новую машину (потому что распространяется маленьким бинарником, который легко скачать), запустить все скрипты и получить готовую систему.</p>
  <pre id="uH24">sh -c &quot;$(curl -fsLS https://chezmoi.io/get)&quot; -- init --apply dadyarri</pre>
  <p id="8xCb">(Сработает только на федоре, потому что там есть автоматически запускаемый скрипт, который устанавливает кучу пакетов через dnf)</p>
  <h2 id="npJ9">Скрипты</h2>
  <p id="lGk5">Последнее время пишу разные скриптики разной степени замороченности, чтобы упростить себе жизнь (и заодно не скиснуть от безделия).</p>
  <h3 id="crun">ex</h3>
  <p id="Cm8Q">Скрипт, изначально стыренный с реддита, но немного докрученный для повышения удобства. Автоматически определяет тип архива и распаковывывает его нужной программой. Опционально можно указать путь назначения, и, если программа поддерживает такое колдунство содержимое архива попадёт в указанную папку.</p>
  <figure id="y6l2" class="m_column">
    <img src="https://img2.teletype.in/files/16/58/165860c7-3173-4c20-825e-2c71d6930f3e.png" width="999" />
  </figure>
  <h3 id="SzMo">fdups</h3>
  <p id="31nq">Самописный скрипт, ищущий дубликаты файлов в указанной директории (имя не имеет значения, поиск ведётся по хеш-сумме)</p>
  <figure id="W27W" class="m_column">
    <img src="https://img4.teletype.in/files/fd/f8/fdf84ef1-de5f-47fa-9b00-d061ef62dab2.png" width="899" />
  </figure>
  <h3 id="uvyA">upd</h3>
  <p id="8uyH">Самописный скрипт, автоматизирующий обновление системы и всевозможных пакетов из кучи разных источников (сейчас доступен dnf, flatpak, neovim, мои бинарники и глобальные npm пакеты)</p>
  <figure id="9wnX" class="m_column">
    <img src="https://img2.teletype.in/files/91/15/91156543-77c1-4ef0-b149-7496abd12557.png" width="1265" />
  </figure>
  <h3 id="OBU4">addpath</h3>
  <p id="RO07">Переменную <code>$PATH</code> я не храню статически в конфиге, а держу все нужные мне пути в отдельном файлике и специальным скриптом читаю оттуда и передаю в <code>.zshrc</code>. Этот скрипт (в отличие от всех предыдущих, написанный на nim) записывает новый путь в указанный файл (примерно как <code>fish_add_path</code> только текущий шел не изменяется).</p>
  <figure id="S34b" class="m_column">
    <img src="https://img1.teletype.in/files/cf/3c/cf3cb98b-d3ba-4b4b-ad7d-ceec680ae645.png" width="893" />
  </figure>
  <h3 id="20Dy">getpath</h3>
  <p id="70rc">Тот скрипт, который собирает все пути из файла <code>.paths</code> и печатает их в формате, необходимом для <code>$PATH</code>, заодно проверяя, существует ли путь, чтобы лишнее не копилось в переменных окружения.</p>
  <figure id="2jRS" class="m_column">
    <img src="https://img3.teletype.in/files/25/b0/25b0554d-a75d-4bb4-bb4a-716f778ea14b.png" width="1136" />
  </figure>
  <h3 id="7MEi">dotversion</h3>
  <p id="09LX">Еще один самописный скрипт на nim. Я тут начал активно переходить на .NET и оказалось, что у них нет встроенного инструмента для управления версиями приложений (типа <code>npm version</code>). В итоге я потратил пару вечеров и написал свой такой инструмент, в чём-то даже превосходящий упомянутый джаваскриптовый.</p>
  <p id="CZb7">В основе находится <a href="https://semver.org" target="_blank">semver</a>, поддерживается генерация мажор, минор, патч, альфа, бета, релиз-кандидат, альфа-{мажор, минор, патч}, бета-{мажор, минор, патч}, релиз-кандидат-{мажор, минор, патч} версий. Приложение автоматически найдёт файл csproj возьмет оттуда версию и запишет новую (есть флаг, запускающий вычисление новой версии, без перезаписи файла)</p>
  <figure id="Hps2" class="m_column">
    <img src="https://img1.teletype.in/files/01/17/01177123-e79b-4645-9c32-b5dc6692ba5a.png" width="1132" />
  </figure>
  <figure id="C8TJ" class="m_original">
    <img src="https://img4.teletype.in/files/fd/1c/fd1c1a7e-3a05-43a4-9b06-309b4d5b580b.png" width="352" />
  </figure>
  <p id="ZT3A"><strong>Ну, вроде бы и всё. Stay in touch!</strong></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@yadevblog/control</guid><link>https://teletype.in/@yadevblog/control?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/control?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>Control</title><pubDate>Thu, 03 Mar 2022 19:02:44 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/72/2d/722da094-7bde-4b85-82c5-8c5a74ae80df.png"></media:content><category>games</category><description><![CDATA[Ну, раз у меня теперь есть мощности для запуска нормальных игр, значит теперь будут появляться обзоры всякого разного. Я не считаю себя игрожуром и всего лишь высказываю собственное мнение. Поэтому считаю, что имею право что-то говорить не допройдя игру до конца.]]></description><content:encoded><![CDATA[
  <p id="EvVR">Ну, раз у меня теперь есть мощности для запуска нормальных игр, значит теперь будут появляться обзоры всякого разного. Я не считаю себя игрожуром и всего лишь высказываю собственное мнение. Поэтому считаю, что имею право что-то говорить не допройдя игру до конца.</p>
  <p id="fynm">Ахтунг, много текста и нет картинок, потому что пишу я это, когда удалил игру, потому что она мне осточертела.</p>
  <p id="oYd3">Итак, Control. Шутер с элементами RPG от третьего лица, выпущенный несколько лет назад финской Remedy Entertainment (та, что создала Alan Wake и еще кучу неплохих игр).</p>
  <p id="vSXp">Всю игру мы находимся в одном огромном здании, называющимся Федеральное Бюро Контроля или же Старейший Дом. У меня огромные проблемы с ориентированием в играх, и Control не стал исключением. Большое количество связанных помещений, уйма бектрекинга и убогая карта явно не улучшают ситуацию.</p>
  <p id="tS5L">Проблема в навигации заключается в вертикальности уровней, но карта при этом всего одна и разные уровни высоты наложены друг на друга</p>
  <h2 id="VWTF">Сюжет</h2>
  <p id="Yy41">Концепция Старейшего Дома мне сильно напоминает фонд SCP (коллективный сборник статей про разнообразные паранормальные объекты). ФБК тоже изучает различные объекты, которые здесь называются Предметами Силы, по всему зданию разбросаны Исследования с пометками <em>[Данные засекречены].</em></p>
  <p id="J4Xl">Главная героиня Джесси Фейден приходит в Фонд искать своего брата, которого много лет назад забрали агенты Фонда и в процессе поиска хоть каких-то признаков живых людей натыкается на труп человека, застреленного из лежащего рядом пистолета, подбирает его, и становится Директором Фонда (да, в самом начале игры).</p>
  <p id="CyII">Джесси находит помощницу доктора Дарлинга, главного дядьки в Секторе Исследнований Эмили Поуп, которая порционно ей рассказывает о том, что произошло в Фонде и почему везде под потолком висят люди.</p>
  <p id="xm8x">Оказывается, здание и людей в нём заразили некие астральные существа (Джесси назвала их Шумами, и всё Бюро, включая людей, которые закрыты в других секторах, начали их так называть), из-за которых люди обретают красное свечение и некоторые спецспособности, вроде метания осколков стен и левитирования.</p>
  <p id="UKCn">Мы пробуем очистить одного человека от заражения, но похоже, что это необратимый процесс и человек просто растворяется в воздухе.</p>
  <p id="9KTT">Наша глобальная задача (помимо поиска брата), кто бы сомневался?, спасти Бюро от нашествия Шумов.</p>
  <h2 id="D2C6">Боёвка и способности</h2>
  <p id="gdpc">Было бы странно отправлять человека с одним лишь пистолетом сражаться с Шумами. Поэтому нам постепенно (как через основные, так и через побочные квесты) выдают новые способности.</p>
  <p id="w3pU">Я прошёл не всю игру (полагаю, что я даже не близко к середине), но уже получил Метание (способность хватать практически любые предметы и кидать их во врагов), Уклонение (быстрый рывок в любую сторону) и Щит (поднятие впереди себя кусков пола, которое даёт некоторую, но не абсолютную защиту героине).</p>
  <p id="iIcB">Использование любой способности тратит энергию, которая автоматически восполняется в периоды неактивности.</p>
  <p id="3kRC">Табельное оружие — пистолет, для которого можно открывать разные формы, благодаря которым он становится дробовиком, автоматом, и еще каким-то типами оружия, которые я еще не успел открыть. “Патроны” к табельному — это, видимо, какая-то энергия, которая тоже пополняется автоматически и ничего по локациям искать не нужно, она просто берётся из воздуха.</p>
  <p id="KV62">Стрельба приятная, казуальная, отдачи нет вообще.</p>
  <p id="RUQu">Оружие модифицируется через Моды, которые выпадают из противников или лежат в заныканных ящиках (их действительно приходится иногда поискать, потому что стоят они не на виду)</p>
  <h2 id="8Sqh">Квесты</h2>
  <p id="DxUP">Их в игре приличное количество, но все они сводятся к одному — сходи в далёкий сектор, перестреляй несколько волн спавнящихся из воздуха Шумов. Иногда нужно запитать какие-нибудь механизмы, с помощью Левитации кинув валяющиеся рядом &quot;батареи&quot; (понятия не имею что это) в предусмотренные слоты.</p>
  <p id="i6hD">Есть еще странная механика &quot;Уведомлений Бюро&quot;. Это квесты, время выполнения которых ограничено. За 20 минут нужно добраться в другой сектор и убить всех врагов. Cмерть сбрасывает такие квесты, а появляются они нечасто и обычно во время замеса, что сильно отвлекает от игрового процесса.</p>
  <p id="Mj3I">Даже побочные квесты здесь очень нудные (те, что выдают неписи по ходу развития сюжета) — собери несколько летающих по дурацкой траектории писем или уничтожь огромный якорь, за которые дают лишь несколько очков прокачки</p>
  <h2 id="Q8oL">Противники</h2>
  <p id="mzMR">Вот чего в игре с избытком, это видов противников. Тупые автоматчики, рейнджеры (вооружены автоматами, но походу у них есть какая-то тактика, и они её придерживаются), летающие, взрывающиеся, кидающие осколки окружения, снайперы и еще уйма видов.</p>
  <p id="KOq9">Это вносило бы неплохое разнообразие, если бы не отвратительная механика спавна. Ты просто проходишь по помещению, которое когда-то уже зачищал и игра тебе в случайном порядке может дать (а может и не дать) волну-другую мобов. Причем количество и их виды тоже рандомное. То есть могут кинуть парочку базовых врагов, с которыми легко разберешься за пару секунд, а могут — жирного пулемётчика и толпу летающих ублюдков, которые наврядли раскидаются так же легко. Но при этом с какой-то вероятностью просто никого не будет. И такая вариативность сильно раздражает.</p>
  <h2 id="oMZW">Сохранения</h2>
  <p id="7Yg8">В игре очень часто загорается иконка автосохранения (даже во время боя), но что  в это время сохраняется — для меня осталось загадкой, потому что смерть возрождает на последнем посещенном &quot;костре&quot; и все мобы, которых ты уничтожил до смерти появляются там же.  </p>
  <h2 id="zkqS">Итог</h2>
  <p id="UuAi">Ух, что-то я разогнался. В общем, Control  — это красивая игра, которую я бросил и никогда не вернусь, о чём вообще не жалею. Визуально — замечательная, музыка &quot;Старых богов Асгарда&quot; — потрясающая, локализация от GameVoice — отличная, но слишком много спорных геймдизайнерских решений, которые меня оттолкнули.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@yadevblog/second-mind-ed2</guid><link>https://teletype.in/@yadevblog/second-mind-ed2?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/second-mind-ed2?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>Второй мозг. Reinvented edition</title><pubDate>Sat, 01 Jan 2022 20:51:49 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/b7/e6/b7e6582e-af7c-473f-b15a-19f457ec7e94.png"></media:content><description><![CDATA[<img src="https://i.ytimg.com/vi/zdpVUvQpgw4/maxresdefault.jpg"></img>Прошел год с моего прошлого поста о том, как я использую Notion в своем рабочем процессе и с тех пор многое поменялось. Notion сильно изменился, появились классные плюшки, упрощающие автоматизацию workflow. Поменялось и мое окружение в нем. Подробное в меру моей лени описание с кучей скриншотов описание - под катом.  ]]></description><content:encoded><![CDATA[
  <p id="y4Uu">Прошел год с моего прошлого поста о том, как я использую Notion в своем рабочем процессе и с тех пор многое поменялось. Notion сильно изменился, появились классные плюшки, упрощающие автоматизацию workflow. Поменялось и мое окружение в нем. Подробное в меру моей лени описание с кучей скриншотов описание - под катом.  </p>
  <h2 id="4ln7">Модификация интерфейса</h2>
  <p id="w9yf">В последнее время я все чаще сижу на винде, ибо огромная куча работ в универе зависит от проприетарного софта (mathcad, visual studio, excel). Раньше я писал, что использую notion-enhancer, но когда я начал активно переезжать на винду, понял, что не так уж оно и необходимо, notion сам по себе неплох. (ага, мне просто лень было его ставить, потому что он зависит от node.js)</p>
  <p id="hq0L">Сегодня я попробовал обновившийся прямо перед новым годом notion-enhancer, и знаете, прям хорошо стало. Если раньше нужно было устанавливать node.js, notion-enhancer через терминал (мне в принципе пофиг, я привык работать в консоли, но представьте на месте меня обычного <s>хомячка</s> пользователя), то сейчас стало совсем хорошо. Они взяли официальную сборку Notion для Windows, запаковали в нее notion-enhancer со всеми зависимостями и сделали из этого маленький экзешник. Ну не красота ли?</p>
  <figure id="nAcF" class="m_column">
    <img src="https://i.ytimg.com/vi/zdpVUvQpgw4/maxresdefault.jpg" width="1280" />
    <figcaption>Красота-то какая... Ляпота...</figcaption>
  </figure>
  <figure id="laiL" class="m_column">
    <img src="https://img4.teletype.in/files/f2/d4/f2d46c4f-82e8-4d6d-a061-61ef948c7055.png" width="1243" />
    <figcaption>Интерфейс нового notion-enhancer</figcaption>
  </figure>
  <p id="y8BV">Я не буду рассказывать о том, какие твики выбрал (тем более что нынешний список практически не отличается от прошлого), просто дам ссылку на документацию: <a href="https://notion-enhancer.github.io/" target="_blank">https://notion-enhancer.github.io/</a></p>
  <h2 id="q9vr">Дашборд</h2>
  <figure id="krE8" class="m_column">
    <img src="https://img1.teletype.in/files/4e/21/4e21b416-8a8d-4802-b165-1e5d14bf63fc.png" width="785" />
    <figcaption>Главная воркспейса</figcaption>
  </figure>
  <p id="9Fe8">На этой странице просто содержатся ссылки на другие странице, тут нет ничего интересного</p>
  <h2 id="SmEj">Учебный дашборд</h2>
  <h3 id="6euK">Ссылки, недели, счётчик</h3>
  <figure id="m9MB" class="m_original">
    <img src="https://img3.teletype.in/files/2b/36/2b366eeb-719e-46af-b28d-ca972b195b4b.png" width="615" />
    <figcaption>Учебный дашборд. Тут содержится всякое разное, связанное с универом</figcaption>
  </figure>
  <p id="3XBo">Слева расположены ссылки на учебные ресурсы и таблица, в которой автоматически вычисляется текущая учебная неделя (какой же у Notion мерзкий синтаксис формул).</p>
  <figure id="ZuHg" class="m_original">
    <img src="https://img3.teletype.in/files/ea/07/ea071f2f-43d3-4082-a55a-69e8b56717e5.png" width="485" />
    <figcaption>Формула для вычисления учебной недели. Почему она работает именно так - не спрашивайте, я сам уже не знаю 😂</figcaption>
  </figure>
  <p id="0REg">Справа - счетчик дней до конца учебы, сделанный с помощью <a href="https://indify.co" target="_blank">https://indify.co</a> </p>
  <h3 id="Scfk">Информация о семестрах</h3>
  <figure id="wzgj" class="m_column">
    <img src="https://img2.teletype.in/files/99/66/9966ef2c-ffd9-4e3c-8c71-1404a565d22c.png" width="1000" />
    <figcaption>Блок со ссылками на информацию о семестрах</figcaption>
  </figure>
  <p id="2N38">В этом блоке находятся страницы с подробным описанием семестра (об этом ниже) и кнопка &quot;новый год&quot;, по которой можно продублировать страницы</p>
  <h3 id="frD4">Список заданий</h3>
  <figure id="DNe6" class="m_column">
    <img src="https://img3.teletype.in/files/62/cd/62cd65ef-f141-4dee-8cf5-08326d029313.png" width="1064" />
  </figure>
  <p id="YdWx">Слева перечислены актуальные задания (не выполненные, и с дедлайном меньше чем, две недели), справа - календарное представление всех созданных заданий.</p>
  <h3 id="6fn1">Страница семестра</h3>
  <figure id="Oz17" class="m_original">
    <img src="https://img2.teletype.in/files/5f/de/5fdeed0f-f231-43d8-b0a2-cae407c7dcce.png" width="382" />
  </figure>
  <p id="frDL">Вверху страницы дублируется блок со ссылками и учебной неделей (это встроенная функция Notion — Synced block, которая автоматически синхронизирует блоки между разными страницами).</p>
  <h3 id="Zf05">Расписание</h3>
  <figure id="CZmh" class="m_column">
    <img src="https://img2.teletype.in/files/17/ea/17ea933c-15f4-45d0-8db3-30019334e407.png" width="1275" />
  </figure>
  <p id="l9c4">Блок с расписанием (формируется вручную и не меняется в зависимости от учебной недели). Внизу под каждой колонкой находится кнопка &quot;Добавить пару&quot;, при нажатии на которую создается шаблон пары</p>
  <figure id="BJ36" class="m_original">
    <img src="https://img3.teletype.in/files/ef/67/ef672628-adbd-4a11-99f6-33e6606f98f9.png" width="197" />
    <figcaption>Шаблон пары</figcaption>
  </figure>
  <h3 id="EqMh">Предметы</h3>
  <figure id="3vok" class="m_original">
    <img src="https://img2.teletype.in/files/d9/93/d9932276-a765-4b81-8ff3-8713ecff64e4.png" width="566" />
  </figure>
  <p id="jBGF">Таблица со списком предметов в семестре. Кроме того здесь отображается количество заданий, которые осталось сделать по каждому предмету</p>
  <figure id="H1NP" class="m_original">
    <img src="https://img4.teletype.in/files/fc/b5/fcb5bed1-aa4d-448c-9e4b-02719a42fd8e.png" width="730" />
  </figure>
  <p id="Bh7l">Есть блок с возможностью добавить лекции по предметам (он пустой, потому что мне лень таскать ноут в универ)</p>
  <figure id="AgKW" class="m_column">
    <img src="https://img2.teletype.in/files/5e/f5/5ef56057-5c36-4e1c-8ada-04e851f82dcc.png" width="1319" />
  </figure>
  <p id="wwev">И блок, в который можно складировать полезные ссылки по семестру</p>
  <h2 id="brJ2">Предмет</h2>
  <figure id="mS14" class="m_column">
    <img src="https://img4.teletype.in/files/77/cc/77ccd9a4-4642-49ad-add5-f262ad931d15.png" width="1312" />
  </figure>
  <p id="PPzH">Вверху страницы с предметом указаны контакты преподавателя и вставлен документ с учебным планом по предмету</p>
  <figure id="k01m" class="m_column">
    <img src="https://img4.teletype.in/files/fb/89/fb89a31e-588e-483e-b03c-234e0b152cc9.png" width="1294" />
  </figure>
  <p id="rAaF">Затем список заданий по этому предмету и таблица с лекциями.</p>
  <h2 id="L4p6">Список фильмов/сериалов</h2>
  <p id="WJ9y">Этот шаблон я нашел на реддите (потрясающая штука для поиска <s>чего бы такого прихватизировать</s> вдохновения). <a href="https://www.reddit.com/user/flxp49/" target="_blank">u/flxp49</a> написал приложение, которое подключается к вашей базе данных, и автоматически подхватывает всю информацию о фильме/сериале из TMDB. Работает быстро, доступно бесплатно. Один минус - TMDB - англоязычный ресурс и поэтому искать иностранные фильмы на русском не получится, хотя русские фильмы по оригинальному названию находит и вставляет английское. В целом это не мешает использованию, так что и минусом назвать это не получается.</p>
  <figure id="RXqs" class="m_column">
    <img src="https://img3.teletype.in/files/e7/ff/e7ff82dc-95e9-4e9d-a64e-16d7ffdae69a.png" width="1309" />
  </figure>
  <p id="25KT">Все, что нужно сделать для того, чтобы получить информацию о фильме — просто написать его название и поставить точку с запятой. Интеграция автоматически подгрузит первый подходящий релиз и заполнит все поля. Магия!</p>
  <p id="5IjI">Конечно, есть фильтры, позволяющие указать год, выбрать между сериалом или фильмом и пр. Также можно искать по iMDB id.</p>
  <h2 id="sGYb">Итог</h2>
  <p id="tk3x">Это был краткий обзор моего рабочего процесса в Notion, надеюсь он поможет вам вдохновиться и сделать что-то свое. Думаю, у меня дойдут руки и я сделаю шаблон из своего учебного дашборда и расскажу о нём на реддите, но это уже совсем другая история...</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@yadevblog/nov21-news</guid><link>https://teletype.in/@yadevblog/nov21-news?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/nov21-news?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>Проекты и жизня (ноябрь 2021 edition)</title><pubDate>Tue, 26 Oct 2021 23:17:05 GMT</pubDate><description><![CDATA[Не так давно наткнулся на классный проект plashiki.su - сайт, агрегирующий разные озвучки аниме и позволяющий в один клик отмечать серии как просмотренные на Шикимори (огромная база знаний об аниме/манге/ранобэ).]]></description><content:encoded><![CDATA[
  <h2 id="8gXS">Истлевшие идеи...</h2>
  <p id="r4En">Не так давно наткнулся на классный проект <a href="http://plashiki.su" target="_blank">plashiki.su</a> - сайт, агрегирующий разные озвучки аниме и позволяющий в один клик отмечать серии как просмотренные на Шикимори (огромная база знаний об аниме/манге/ранобэ).</p>
  <p id="UKKJ">Увы, автор объявил о его закрытии, объяснив это тем, что сама перестала им пользоваться, да и есть полно альтернатив. Исходный код сайта уже выложен в открытый доступ на Github, дамп базы данных появился в день закрытия.</p>
  <p id="laaV">Вот только ни одна из приведённых автором альтернатив не умеет отмечать серии просмотренными, а мне как ленивому человеку это чертовски важно.</p>
  <p id="EBPw">Первая пришедшая в голову идея — написать свой аналог плашики. Я потратил на это где-то часов 10 (за два дня) и ничего рабочего не получил (<a href="http://github.com/shiki-watch" target="_blank">github.com/shiki-watch</a>). В целом, идея интересная, наверное, когда-нибудь я возьмусь за неё серьёзнее.</p>
  <h2 id="WyUq">Jacob Reborn (v4.x)</h2>
  <p id="TpHb">После очередной безуспешной попытки отрефакторить код Якоба, я начал всё с начала: <a href="https://github.com/uni-jacob/jacob/tree/dev-4x" target="_blank">https://github.com/uni-jacob/jacob/tree/dev-4x</a>. Готова система регистрации, в разработке модуль расписания. Планируется наладить сотрудничество с администрацией ВлГУ для получения свежего расписания в режиме реального времени для любой группы университета.</p>
  <p id="RC4K">Основной упор сделаю на автоматические линтеры, чтобы обеспечить высокое качество кода, своевременное избавление от технического долга (поменьше &quot;ай, и так сойдет&quot;) и написание тестов</p>
  <h2 id="mTxi">Учеба</h2>
  <p id="GJ3U">Закрыл долг по математике (Ура!), пытаюсь наверстать лабы, которые не делал за время подготовки. Чертовски муторное занятие...</p>
  <h2 id="JXzw">Работа</h2>
  <p id="0ekK">Прошёл собеседование в Hawking Bros., и как мне показалось, проявил себя неплохо. Сказали, что работы сейчас нет и предложили подождать декабря/января, когда запустится стажировка по моему направлению. Дали список тем и технологий, которые мне нужно наверстать. Пока нарабатываю портфолио, делая для себя всякие проекты.</p>
  <h3 id="ioCN">CRM для работы с шоколадом</h3>
  <p id="AyiS">Я во Владимире занимаюсь продажей шоколада в килограммовых брикетах. Мне надоели постоянные рассинхроны по остаткам в гугл табличке и фактически на складе. Поэтому пишу систему (на базе бота ВКонтакте) для автоматизации управления этим делом. Вот только в API контача нет функционала, который критически необходим для этой системы. Они где-то с полгода назад (а может и больше) добавили поддержку остатков в карточках товаров в маркете сообщества. А методы API для получения / редактирования этой циферки не обновили. Так что пока оно работает очень неполноценно, изменяя значения только во внутреннем хранилище системы.</p>
  <p id="8mQ0"></p>
  <p id="EPG1" data-align="center"><strong>Впереди куча планов и новостей, stay tuned!</strong></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@yadevblog/second_mind</guid><link>https://teletype.in/@yadevblog/second_mind?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog</link><comments>https://teletype.in/@yadevblog/second_mind?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=yadevblog#comments</comments><dc:creator>yadevblog</dc:creator><title>Второй мозг</title><pubDate>Sun, 11 Oct 2020 14:34:41 GMT</pubDate><media:content medium="image" url="https://teletype.in/files/ff/63/ff63423c-0461-40c1-8ebd-b0ba10ca86e6.png"></media:content><description><![CDATA[<img src="https://teletype.in/files/3f/26/3f265d37-9847-4882-8c15-0dcc55865fe2.png"></img>Меня попросили рассказать о том, как я использую Notion и как изменил его для большего удобства (Ахтунг, много картинок).]]></description><content:encoded><![CDATA[
  <p>Меня попросили рассказать о том, как я использую Notion и как изменил его для большего удобства <em>(Ахтунг, много картинок)</em>.</p>
  <h2>Структура</h2>
  <h3>Dashboard</h3>
  <figure class="m_column">
    <img src="https://teletype.in/files/3f/26/3f265d37-9847-4882-8c15-0dcc55865fe2.png" width="1280" />
  </figure>
  <p>Так выглядит главная страница моего воркспейса (чёрт, какой бы аналог подобрать). Слева ссылки на учебные сайты и ссылки на отдельные страницы с образовательными дисцилинами по семестрам, справа — личные страницы, не связанные с универом; внизу текущий список задач. На скрине например, предстоящие домашние задания. В этой базе данных есть еще несколько представлений:</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/e8/ef/e8efdb45-9ce7-41cd-a956-be75a3e68fc2.png" width="771" />
    <figcaption>Представление &quot;Ближайшие задачи&quot;. Показывает все задачи, дедлайн которых не дальше, чем через неделю</figcaption>
  </figure>
  <figure class="m_column">
    <img src="https://teletype.in/files/ee/8f/ee8fb7be-ac49-4c77-bfd9-0e8349c2b801.png" width="748" />
    <figcaption>Представление &quot;weekly&quot;. Показывает календарь на неделю с отмеченными на нем задачи с дедлайном. Реализовано через notion-enhancer</figcaption>
  </figure>
  <h3>Универ</h3>
  <p>Как я и говорил, блок &quot;Универ&quot; состоит из нескольких страниц с семестрами. На странице семестра есть список с изучаемыми дисциплинами, каждая с пометкой о типе аттестации по итогам семестра:</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/3c/26/3c265ed0-4f5a-462a-aba9-61005e445cb7.png" width="1280" />
  </figure>
  <p>Под спойлером &quot;Экзамены, зачёты&quot; находится таблица с дисциплинами, по которым будет аттестация в том или ином формате. Каждая запись это отдельная страница, куда, например, можно собрать материалы для подготовки к аттестации:</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/93/23/9323d722-86a5-4215-96a3-6b9d6497eb08.png" width="714" />
  </figure>
  <p>На странице дисциплины собрана информация о преподавателях, их контактах, расписании и домашних работах по этой дисциплине (зеркало таблицы с дашборда, в Notion называется &quot;Linked Database&quot;)</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/17/84/17847a5e-191f-4852-bdd9-36c09effb5db.png" width="1280" />
  </figure>
  <h3>Списки</h3>
  <figure class="m_column">
    <img src="https://teletype.in/files/e7/5b/e75b0363-d1ed-47ea-a188-d07ae0a2bcff.png" width="1280" />
  </figure>
  <p>Это отдельная страница, где я храню все, что можно категоризировать — фильмы, сериалы, игры и прочее.</p>
  <p>Например — страница &quot;Фильмы&quot;, другие показывать не буду, они все +- аналогичны</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/67/dc/67dc2de7-0343-42f5-84ef-5cc760962208.png" width="1280" />
    <figcaption>В представление &quot;Посмотреть&quot; я собираю фильмы, которые хотел бы посмотреть в будущем</figcaption>
  </figure>
  <figure class="m_column">
    <img src="https://teletype.in/files/86/32/863297d2-0f55-4c72-a9b9-b21e04e1ad14.png" width="1280" />
    <figcaption>В представлении &quot;Просмотрено&quot; - фильмы, которые я досмотрел с моей личной оценкой</figcaption>
  </figure>
  <figure class="m_column">
    <img src="https://teletype.in/files/53/29/5329989e-5e43-402e-9351-4f104f6bc635.png" width="1280" />
    <figcaption>И в &quot;Брошено&quot; фильмы, которые я по тем или иным причинам не досмотрел</figcaption>
  </figure>
  <h2>Организация списка дел</h2>
  <figure class="m_column">
    <img src="https://teletype.in/files/a4/28/a4283664-02c4-46d9-976b-4f27821a5cd9.png" width="1280" />
    <figcaption>Вот так без прикрас выглядит мой список дел</figcaption>
  </figure>
  <h3>Статус выполнения</h3>
  <p>Это поле с выбором одного варианта из &quot;Сделать&quot;, &quot;В процессе&quot; или &quot;Выполнено&quot;.</p>
  <h3>Проект</h3>
  <p>Это поле нужно только для удобства поиска задач, на постоянной основе оно нигде не используется</p>
  <h3>Дисциплина</h3>
  <p>Основное фильтрующее поле на страницах дисциплин</p>
  <h3>Блокирующий фактор</h3>
  <p>Бывает такое, что выполнить задачу мешает что-то извне, например отстутствие знаний о чем-либо. В этом текстовом поле можно описать причину, почему задачу нельзя выполнить сейчас.</p>
  <h3>Дедлайн</h3>
  <p>Дата крайнего срока выполнения задачи</p>
  <p>И самое интересное:</p>
  <h3>Просрочено?</h3>
  <p>Это вычисляемое поле, значение которого зависит от каких-то условий, например, от значения других полей. Там находится не очень сложная формула, которая выводит &quot;Ахтунг!&quot;, если до дедлайна осталось меньше двух дней или &quot;Просрочено&quot;, если дедлайн прошел. Но синтаксис у Notion&#x60;а ужасен:</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/81/f4/81f4c084-742d-4c4a-aff6-49aae791572d.png" width="640" />
  </figure>
  <h2>Notion-enhancer</h2>
  <p>Это плагин, который работает с Windows, Mac или Linux/AUR версией приложения Notion и предоставляет набор улучшений для интерфейса Notion.</p>
  <p><a href="https://github.com/dragonwocky/notion-enhancer" target="_blank">Ссылка на проект</a></p>
  <p>Из этого пакета я использую несколько улучшений:</p>
  <ul>
    <li>Close window to the tray — вместо закрытия окна сворачивает его в трей</li>
    <li>Выключил по умолчанию включенный Integrated titlebar, он отнимает слишком много места</li>
    <li>Integrated scrollbars — полосы прокрутки выглядят согласно выбранной теме</li>
    <li>Bypass preview — выключает открытие страницы в виде небольшого превью и сразу разворачивает ее на полный экран</li>
    <li>Font Chooser — изменяет шрифты приложения. Когда я установил шрифт Times New Roman для написания отчетов в универ, Notion решил, что нужно использовать этот шрифт во всем приложении. </li>
  </ul>
  <figure class="m_column">
    <img src="https://teletype.in/files/7e/7b/7e7b2955-7de8-4788-8227-81f83855611a.jpeg" width="480" />
  </figure>
  <ul>
    <li>Neutral — на мой взгляд, самая приятная темная тема из всех в notion-enhancer. Ее можно видеть на всех скриншотах в этом посте.</li>
    <li>Property layout — по умолчанию скрывает список свойств страницы под спойлер</li>
  </ul>
  <figure class="m_original">
    <img src="https://teletype.in/files/a6/6b/a66b5de5-6591-4464-ad03-fb16acb13c1a.png" width="304" />
  </figure>
  <ul>
    <li>Weekly view — расширение, дающее способ создания представления с календарем на неделю, вместо месяца по умолчанию. Для этого достаточно создать представление Calendar и дать ему имя weekly, что на мой взгляд не самое удачное решение не-англоязычной аудитории</li>
  </ul>
  <p>Спасибо за прочтение, надеюсь эта статья была вам полезна. Я думаю, что буду иногда писать такие большие статьи с рассуждениями на разные темы, так что stay tuned!</p>
  <p><a href="http://t.me/dadyarriscorner" target="_blank">(c) Dadyarri&#x27;s corner</a></p>

]]></content:encoded></item></channel></rss>