У вас тоже есть такой друг, а может это Вы?

Моему другу почти 32 и он программист (java-разработчик, если хотите). Раньше я любил читать «мотивашки», о том как люди приходят в IT, я читал их пачками, и каждая следующую, хоть и была похожа на предыдущую — давала свежий глоток позитива и оптимизма, веры в светлое будущее и чудеса. История моего друга возможно тоже могла бы послужить «мотивашкой» для кого-то, и раз есть хотя бы небольшой шанс на это — ее нужно рассказать.

Мой друг жил в маленькой деревушке (1к человек),

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

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

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

Отличительной чертой того времени можно отметить практически 90 процентов бесполезности получаемого материала, который не пригодился на практике, от слова «совсем», но тут пытливый читатель скажет что мол «получил общее развитие, учился, а не деградировал» и я соглашусь.

Из чего-то связанного с программированием на тот момент мой друг мог бы отметить первый курс и один семестр лекций по программированию на делфи, в конце курсовая (которая была куплена на 200р, на дворе был 2010 год), на этом все.

После института и армии мой друг пошел работать по специальности, ощущая себя крайне полезным, по почему-то совсем никому не нужным кадром. Очень долго искал работу (возможно сказались отголоски экономического кризиса 2008г) и в итоге устроился в фирму сотового оператора, местного значения, получив должность «Инженер» и жалование в 12 000р (2011г).

Тут, наверное, второй раз покачнулись его представления о жизни и правильности всего того что в ней происходит (первый раз при разводе родителей).

Работа инженером, о которой 5 лет рассказывали в институте разительно отличалась от работы в пользу местного сотового оператора: друг занимался эксплуатацией базовых станций, которые, как все наверняка знают, стоят по городам и селам и трассам преимущественно в металлических контейнерах, 2*3 метра, снаружи вышка с антеннами, внутри драгоценное (в прямом смысле слова, стоит оно не мало) оборудование. Помимо всего прочего ему приходилось косить траву, вокруг контейнера (требование пожарной безопасности), таскать железо (вероятно вы слышали про нормы ТК, о том что мужчине разрешено поднимать в сутки столько-то кг? Там это не работало), лазить по крышам, мачтам(особенно радостно это делать зимой, в мороз) и строго-обязательно мыть за собой пол, покидая контейнер.

Была в этом всем романтика, которая поначалу очень грела душу и закрывала глаза на неудобства: разъездная работа, часто в пути (можно поспать), часто можно сделать работу быстрей чем положено (и поспать), все самые вкусные и дешевые столовки в Екб и области он знал как свои 5 пальцев.

Летние бонусы особо приятные: поехал на объект — заехал искупаться, а можешь взять в магазине мясо (а можешь и пиво)и поехать на работу со своим обедом, благо мангал всегда был в машине водителя.

Говоря о тех днях, мой друг отмечает, что на тот момент было четкое ощущение того, что он на своем месте и все у него хорошо, денег хватает, работа «не сидячая, не заскучаешь», ну и в коллективе его уважали. А вы представляете какой там коллектив? Люди простые… и уважение в таком коллективе очень важно.

Он женился и постепенно жизнь скатилась в один глобальный «день сурка», который он называл позже «зона комфорта». Работа — дом — жена — пиво — сериальчики — World Of Warcraft (чтобы жена не мешала играть, он ее тоже подсадил на варик) — выходные — долгие красивые разговоры с тестем о светлом будущем (непонятно на каком основании), под коньячок.

Спустя пару лет его подозвал начальник и сказал: «готовь свои амбиции и пожелания о ЗП к должности старшего инженера», это был второй «подвиг» на работе (первый — это закончившийся за 1 месяц исп. срок), он им очень гордился тогда, там было много коллег, которые работали значительно дольше, но должность старшего инженера они не получили.

Факт карьерного роста и рост (незначительный) ЗП только укрепили ощущение что «все идет по плану».

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

В разгар этого периода, одногруппник моего друга, который на тот момент трудился разработчиком, начал рассказывать как это круто. В доказательство он приводил цифры (а начинал он таким же инженером в той же компании), рассказывал про java и показал какую-то простенькую программу.

Памятую о тех временах, мой друг рассказывает что начал читать первую java-книгу Я.Файн «Программирование для дедушек и бабушек» без особой веры в себя, если бы ему тогда сказали, что он станет разработчиком, он бы никогда не поверил. Было четко сформулированная уверенность!, что даже мысль, о том что можно стать программистом — абсурдна и примерно на том же уровне что мысль слетать в космос.

Дальше были первые стандартные вещи: калькулятор, крестики-нолики. И знаете что? Ни-че-го, не зацепило совсем. Это была забава (причем не самая веселая), не более.

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

Скорее от отчаянии, а не от глубоко осознания, и уж тем более не от тяги к программированию была куплена книга Head First Java издательства O`Relly, именно куплена, а не скачена с интернета, за 1800р, и так для него книга за такие деньги была очень дорогой покупкой было решено дочитать ее до конца, при любых обстоятельствах, чтоб хоть как то оправдать ее стоимость.

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

И тут повезло: удалось перевестись внутри компании на должность сопровожденца БД Oracle, по счастью произошло совпадение интересов, работодателю срочно нужны были люди, а моему другу хоть какая-то запись в трудовой и опыт, которые бы немного отличались от «запитывания БС дизельным генератором», для последующего устройства java-разработчиком.

Это бы определяющий шаг, и отчасти рискованный, так как познаний в SQL не было от слова «совсем», но было желание учиться, работать и зарабатывать(а еще была ипотека, которая не оставляет вариантов).

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

Работа с SQL стала серьёзным подспорьем в развитии и становлении моего друга, во-первых, он начал зарабатывать деньги без помощи отвертки и плоскогубцев, во-вторых, довольно быстро прокачал свой SQL-скилл, так как охотно брался за сложные, (начальство их называло «творческие») задачи и читал книги, в-третьих он очень хорошо помнил и понимал, зачем пришел в сопровождение и спрятал, но не похоронил свою мечту стать разработчиком.

Серьезным подспорьем стала удаленка и первый написанный самостоятельно веб-сервис (мой друг шутит, что ни за что на свете не хотел бы увидеть исходники этого сервиса). На руку сыграло то, что у работодателя был просто омут задач, которые можно было автоматизировать, а у моего друга — страстная тяга к автоматизации ручного труда.

В ход пошел spring, и работа над довольно функциональным web-сервисом, начиная писать который, мой друг совсем не понимал что такой spring, а заканчивая, спустя 2 месяца уже кое-что знал.

На тот момент он бросил пить и курить, ушел с головой в работу, все свободное время (не считая фитнес-клуба) тратил на книги и кодинг, подстегивал результат: сервисы, которые экономили часы ручной работы и благодарности коллег их других ведомств.

Он говорит что в какой то момент, мысль о том что он станет разработчиком стала нормой, перестала казаться нереальной, сформировалась четкая установка: «я этого не знаю, но это ПОКА».

Спустя еще год он устроился java-разработчиком, на приличную ЗП в приличный банк, вопреки скепсису коллег с первой работы («ботаник, куда-ты прешься, пошли накатим»), все получилось.

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

У вас есть такой друг? А может это Вы?

У меня он есть, а может это я…


ссылка на оригинал статьи https://habr.com/ru/post/465661/

FAQ по Superjob API (публикация вакансий)

Недавно я рассказывал о Headhunter API для публикации вакансий, упомянув Superjob. Теперь, реализовав тот же функционал на Superjob API будет справедливо поделиться с вами полученным опытом.

image

Работа с API Superjob

Итак, есть задача по публикации вакансий на Superjob, вам понадобятся:

Актуальная версия API

Здесь всё ожидаемо — версионность присутствует и передаётся в URLе:

https://api.superjob.ru/:version/method_name/:params

Регистрация приложения

Тоже максимально простая процедура — создать аккаунт, создать приложение, получить токены. Без ожиданий, регистрации и смс.

redirect_uri, передаваемый в параметрах, видимо, вообще не связан с Callback URL, указанном в настройках приложения. Его (Callback URL) можно даже и не указывать, всё будет работать.

А также

Указать обязательные параметры

Обязанности, требования и условия — необязательные параметры вакансии, а вот название компании и описание её деятельности — обязательно нужно передавать в каждую вакансию.

В прошлый раз (на HeadHunter) была попытка публиковать ссылку внутри вакансии, здесь же нашёлся параметр url, однако, где он отображается в вакансии понять не удалось.

Запрашивать ссылку на созданную вакансию

Вместо ожидаемого superjob/vacancies/id ссылка формируется в виде vacancy-name-id.html, но в ответе приходит лишь id вакансии. Русский текст проходит транслитерацию неизвестным алгоритмом (или по одному из N ГОСТов), что делает невозможным формировать ссылку на своей стороне. Приходится делать отдельный запрос на роут api откуда уже возвращается полная ссылка.

Писать с заглавной буквы

При авторизации возвращается объект с полями token_type и access_token, которые необходимо использовать для дальнейших запросов в виде строки: token_type + ' ' + access_token. При таком подходе Superjob ругается на «неверный тип токена» потому что возвращают они token_type = bearer, а ожидают token_type = Bearer.

Выбрать между графиком работы и типом занятости

Superjob объединяет эти два поля, предлагая из списка, например, частичную занятость или неполный день. Это неудобно когда есть парттаймеры, срочные договора и другие варианты развития событий.


Итоги

Про форматирование и задачи без аналитики

В прошлый раз я упомянул, что вакансии на HeadHunter поддерживают HTML и на сайте для этого прикручен WYSIWYG-редактор. В дополнение к задаче публикации ссылок в вакансиях (которая слегка провалилась), прилетела и задача прикрутить WYSIWYG для них в нашем приложении. Текст вакансии вместе с форматированием сохраняется в БД, поэтому в таком же виде он улетел на Superjob, который HTML не поддерживает. В принципе, ожидаемо, но главный факап в том, что посмотрев эту же вакансию на HeadHunter, обнаружилось, что он тоже не поддерживает присланное форматирование! Теги просто удаляются и на выходе остаётся голый текст. Как итог — WYSIWYG будет выпиливаться, а все записанные вакансии с HTML надо будет в трёх БД как-то распарсить и почистить лишнее.

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

Про удобство

Если сравнивать HeadHunter и Superjob, то очевидно, что с последним всё гораздо проще. Интеграция построилась очень быстро — тексты ошибок не сбивали с толку, всё удалось протестировать на нескольких окружениях из-за необязательности Callback URL.

Что меня расстроило — это отсутствие Superjob API на Github, зато повеселил там «простой клиент» на PHP в полторы тысячи строк. Для общения с техподдержкой есть обратная связь, однако, в форме обращения отсутствует категория вопросов по API. Ну такое.

Заключение

В целом, вряд ли можно однозначно сказать что у кого-то лучше, у кого-то хуже. У Superjob есть к чему придраться, но в конечном счёте сервис предоставляет нормальный API, полностью решающий наши задачи.


ссылка на оригинал статьи https://habr.com/ru/post/465663/

Подсчет скорости скачивания в вашем приложении

Предыстория

Есть у меня маленький и уютный pet-project, который позволяет качать файлы из интернета. Файлы при этом группируются и пользователю отображается не каждый файл, а некоторая группировка. И весь процесс скачивания (и отображение этого процесса) сильно зависел от данных. Данные при этом получались на лету, т.е. пользователь запускает на скачивание и нет никакой информации, сколько придётся качать в реальности.

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

И тут появляется пользователь с логичной проблемой — на большой группировке непонятно, почему прогресс еле ползёт — много файлов надо скачать или низкая скорость? Как я упоминал выше — количество файлов заранее неизвестно. Поэтому, я принял решение добавить счетчик скорости.

Анализ

Хорошая практика — посмотреть тех, кто уже решал аналогичную задачу, чтобы не изобретать велосипед. Разный софт закрывает этим разные задачи, но выглядит отображение довольно одинаково:

uTorrent DownloadMaster
uTorrent DownloadMaster

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

Итак, нам нужна простая цифра вида 10 MB/s или что-то подобное. Как же нам её посчитать?

Теория и практика

Существующая реализация скачивания использовала HttpWebRequest и я решил не переделывать само скачивание — не стоит трогать работающий механизм.

Итак, начальная реализация без какого-либо подсчета:

            var request = WebRequest.Create(uri);             var response = await request.GetResponseAsync();             using (var ms = new MemoryStream())             {                 await response.GetResponseStream().CopyToAsync(ms);                 return ms.ToArray();             }

На уровне такого API реагировать можно только на полное скачивание файла, для небольших групп (или даже для одного файла) скорость фактически не посчитать. Идём за исходниками CopyToAsync, копипастим оттуда простую логику:

            byte[] buffer = new byte[bufferSize];             int bytesRead;             while ((bytesRead = await ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)             {                 await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);             }

Теперь мы можем реагировать на каждый буфер, отданный нам по сети.

Итак, во первых, что мы делаем вместо коробочного CopyToAsync:

        public static async Task<byte[]> GetBytesAsync(this Stream from)         {             using (var memory = new MemoryStream())             {                 byte[] buffer = new byte[81920];                 int bytesRead;                 while ((bytesRead = await from.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) != 0)                 {                     await memory.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);                     NetworkSpeed.AddInfo(bytesRead);                 }                 return memory.ToArray();             }         }

Единственное, что реально добавлено — NetworkSpeed.AddInfo. И единственное, что мы передаем — количество скачанных байт.

Сам код для скачивания выглядит в итоге так:

            var request = WebRequest.Create(uri);             var response = await request.GetResponseAsync();             var array = await response.GetResponseStream().GetBytesAsync();

Вариант для WebClient

            var client = new WebClient();             var lastRecorded = 0L;             client.DownloadProgressChanged += (sender, eventArgs) =>             {                 NetworkSpeed.AddInfo(eventArgs.BytesReceived - lastRecorded);                 lastRecorded = eventArgs.BytesReceived;             };             var array = await client.DownloadDataTaskAsync(uri);

Вариант для HttpClient

            var httpClient = new HttpClient();             var content = await httpClient.GetStreamAsync(uri);             var array = await content.GetBytesAsync();

Хорошо, половина задачи решена — мы знаем, сколько мы скачали. Переходим к скорости.

Согласно википедии :

Скорость передачи данных — объём данных, передаваемых за единицу времени.

Первый наивный подход

У нас есть объём. Время можно взять буквально запуска и получать разницу с DateTime.Now. Берем и делим?
Для консольных утилит типа curl такое возможно и имеет смысл.
Но если ваше приложение чуть сложнее, то буквально кнопка "пауза" резко усложнит вам жизнь.

Немного про паузу
Может я очень наивен, а может вопрос действительно не так прост — но пауза меня заставляет задумываться постоянно. Пауза при скачивании может вести себя минимум тремя способами:

  • прерывать закачку файлов, начинать заново после
  • просто не качать файл дальше, надеяться что сервер даст продолжить после
  • докачивать уже начатые файлы, не качать новые, качать новые после

Так как первые два приводят к потере уже скачанной информации, я у себя использую третий.
Чуть выше я обращал внимание, что скорость нужна именно на момент времени. Так вот, пауза это дело усложняет:

  • нельзя нормально посчитать, какой была средняя скорость, просто взяв объем на время
  • пауза может иметь внешние причины, которые поменяют скорость и канал (переподключение к сети провайдера, переключение на VPN, завершение uTorrent-a занявшего весь канал), что приведёт к изменению реальной скорости
    Фактически, пауза разделяет любые показатели на до и после неё. Это не влияет особо на код ниже, просто минутка забавной информации на подумать.

Второй наивный подход

Добавим таймер. Таймер каждый период времени будет брать всю свежую информацию о скачанном объеме и пересчитывать показатель скорости. А если таймер поставить в секунду, то вся полученная за эту секунду информация о скачанном объеме и будет равна скорости за эту секунду:

Реализация класса NetworkSpeed целиком

    public class NetworkSpeed     {         public static double TotalSpeed { get { return totalSpeed; } }          private static double totalSpeed = 0;          private const uint TimerInterval = 1000;          private static Timer speedTimer = new Timer(state =>         {             var now = 0L;             while (ReceivedStorage.TryDequeue(out var added))                 now += added;             totalSpeed = now;         }, null, 0, TimerInterval);          private static readonly ConcurrentQueue<long> ReceivedStorage = new ConcurrentQueue<long>();          public static void Clear()         {             while (ReceivedStorage.TryDequeue(out _))             {             }              totalSpeed = 0;         }          public static void AddInfo(long received)         {             ReceivedStorage.Enqueue(received);         }     }

По сравнению с первым вариантом, такая реализация начинает реагировать на паузу — скорость снижается до 0 в ближайшую секунду после того, как перестают приходить данные снаружи.
Но, есть и минусы. Мы работаем с буфером в 80кб, а значит загрузка начатая в одной секунде, отобразится только в следующей. И при большом потоке параллельных загрузок такие погрешности в измерениях будут отображать что угодно — у меня разброс был до 30% от реальных цифр. Я бы может и не заметил, но превышение 100мбит выглядело слишком уж подозрительно.

Третий подход

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

Реализация чуть усложняется, но в целом ничего такого:

Реализация класса NetworkSpeed целиком

    public class NetworkSpeed     {         public static double TotalSpeed { get { return totalSpeed; } }          private static double totalSpeed = 0;          private const uint Seconds = 3;          private const uint TimerInterval = 1000;          private static Timer speedTimer = new Timer(state =>         {             var now = 0L;             while (ReceivedStorage.TryDequeue(out var added))                 now += added;             LastSpeeds.Enqueue(now);             totalSpeed = LastSpeeds.Average();             OnUpdated(totalSpeed);         }, null, 0, TimerInterval);          private static readonly LimitedConcurrentQueue<double> LastSpeeds = new LimitedConcurrentQueue<double>(Seconds);          private static readonly ConcurrentQueue<long> ReceivedStorage = new ConcurrentQueue<long>();          public static void Clear()         {             while (ReceivedStorage.TryDequeue(out _))             {             }             while (LastSpeeds.TryDequeue(out _))             {             }              totalSpeed = 0;         }          public static void AddInfo(long received)         {             ReceivedStorage.Enqueue(received);         }          public static event Action<double> Updated;          private class LimitedConcurrentQueue<T> : ConcurrentQueue<T>         {             public uint Limit { get; }              public new void Enqueue(T item)             {                 while (Count >= Limit)                     TryDequeue(out _);                 base.Enqueue(item);             }              public LimitedConcurrentQueue(uint limit)             {                 Limit = limit;             }         }          private static void OnUpdated(double obj)         {             Updated?.Invoke(obj);         }     }

Пара моментов:

  • на момент реализации не нашел готовой очереди с ограничением на количество элементов и взял её в интернете, в коде выше это LimitedConcurrentQueue.
  • вместо реализации INotifyPropertyChanged почему то Action, использование фактически одинаковое, причин не помню. Логика простая — показатель меняется, надо пользователей об этом уведомить. Реализация может быть любой, хоть IObservable, кому как удобнее.

И немного читабельности

API отдает скорость в байтах, для читаемости пригодится простой (взятый в интернете)

конвертер

    public static string HumanizeByteSize(this long byteCount)     {       string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB       if (byteCount == 0)         return "0" + suf[0];       long bytes = Math.Abs(byteCount);       int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));       double num = Math.Round(bytes / Math.Pow(1024, place), 1);       return Math.Sign(byteCount) * num + suf[place];     }      public static string HumanizeByteSize(this double byteCount)     {       if (double.IsNaN(byteCount) || double.IsInfinity(byteCount) || byteCount == 0)         return string.Empty;        return HumanizeByteSize((long)byteCount);     }

Напомню, что скорость в байтах, т.е. на 100мбитный канал должно выдать не более 12.5МБ.

Как это в итоге выглядит:

Скачивание образа ubuntu

Current speed 904,5KB/s
Current speed 1,8MB/s
Current speed 2,9MB/s
Current speed 3,2MB/s
Current speed 2,9MB/s
Current speed 2,8MB/s
Current speed 3MB/s
Current speed 3,1MB/s
Current speed 3,2MB/s
Current speed 3,3MB/s
Current speed 3,5MB/s
Current speed 3,6MB/s
Current speed 3,6MB/s
Current speed 3,6MB/s

Ну и несколько образов сразу

Current speed 1,2MB/s
Current speed 3,8MB/s
Current speed 7,3MB/s
Current speed 10MB/s
Current speed 10,3MB/s
Current speed 10MB/s
Current speed 9,7MB/s
Current speed 9,8MB/s
Current speed 10,1MB/s
Current speed 9,8MB/s
Current speed 9,1MB/s
Current speed 8,6MB/s
Current speed 8,4MB/s

Заключение

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

Хочется сказать спасибо Stack Overflow на русском и конкретно VladD-exrabbit — в хорошем вопросе хоть и есть половина ответа, но любые подсказки и любая помощь всегда двигают тебя вперёд.

Хочу напомнить, что это pet-project — поэтому класс статический и один на всех, поэтому точность не особо. Я вижу много мелочей, которые можно было бы сделать лучше, но… всегда есть чем заняться ещё, так что пока скорость я считаю вот так и считаю что это не самый плохой вариант.


ссылка на оригинал статьи https://habr.com/ru/post/465669/

Документируем процесс подключения и генерации документов в будущей ERP-системе

image

Несколько месяцев назад я закончил один из этапов своего профессионального пути многорукого Шивы в стартапе по разработке системы управления лабораториями неразрушающего контроля. Я расскажу как мне удалось задокументировать часть разработки связанную с подключением и генерацией документов в достаточном объеме для дальнейшего спокойного использования созданной системы в течении двух лет.

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

Дано:

  • крутая команда разработки и конечно же менеджер проекта. На момент старта проекта я работал арт-директором в одной из студий Томска, затем оказался в команде стартапа
  • стартап с железобетонными сроками к определенному событию — старт акселерации во ФРИИ
  • первоначальный набор шаблонов из 15+ документов различного объема от 1 страницы до 100+ страниц в одном документе с разными условиями подключения
  • сторонний проект, который должен быть интегрирован с будущим решением
  • дизайнер (аналитик, проектировщик, дизайнер, арт-директор, product owner, менеджер продукта в одном лице)

Задача:

  • запустить проект к сроку
  • не сдохнуть команде через полгода в хаосе при подключении нового функционала и еще большего объема документации в системе (в случае успешного окончания акселерации)
  • минимальным количеством букв и затраченных сил добиться пригодной документации
  • отчуждаемость документации любой команде/любому сотруднику не в контексте

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

Анализ и подготовка

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

Следующий шаг — понять состояние чистоты разметки документов. Объясню. Дело в том, что я получил уже заполненные шаблоны документов от методолога — кто, когда и как делал эти документы я не знал, даже если бы и знал мне это мало бы что дало. Документ .docx внутри что-то вроде xml для текста и некоторые элементы визуально могут быть не видны в открытом документе, но в разметке документа присутствовать. Как на эти элементы разметки отреагирует генератор документов и различный софт для просмотра документа — неизвестно. Основная ставка была на Microsoft Word, но есть OpenOffice, LibreOffice и все они могут давать различный результат. Поэтому все шаблоны сначала проходили процедуру очистки стилей — полный сброс любого оформления и повторное оформление стилями документов, где-то с корректировкой структуры документа. И даже после этой процедуры мы собирали проблемы в содержимом документов после генерации. В дальнейшем я пришел к тому, что если документ небольшой, лучше его перенабрать с нуля, а не брать в работу предоставленный методологом шаблон, это здорово экономит время на документах до 5-ти страниц. Никому не хочется потом искать причину, почему что-то поехало, процесс отладки данных случаев крайне утомителен для команды. На этом же этапе, если у вас пакет документов, вы приходите к единообразному визуальному языку.

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

Разметка документов

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

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

Документация переменных и интерфейса

В начале заметки я написал, что мы были жестко ограничены к определенному событию. Вдобавок ко всему, у меня уже был спланирован отпуск. Когда я был недоступен, но нужно было срочно добавить системную переменную (отсутствует в интерфейсе конечного пользователя), разработчики сами добавляли строку с переменной, а я потом дописывал недостающие условия. В связи с этим спецификация переменных не претендует на правильность и идеальность, но это вполне рабочий документ, который в последствии разрастался и эволюционировал. Основная вкладка в документе структурно не менялась со старта и на момент моего ухода проекта.

image

Шаблон «Спецификации данных полей», который вы можете брать и использовать в своей работе. В документе я оставил часть данных для примера. Этот шаблон может подойти для документации интерфейса, чтобы контролировать качество разработки. Например, product owner знает какой минимальный результат он получит, разработчик четко понимает какой минимум требуется сделать из описания задачи + спецификации данных полей, а если чего не хватает он об этом скажет, инженер по тестированию ясно видит очевидные кейсы. В итоге, все в плюсе.

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

Содержание:

  • Страница — ориентир человеку вне контекста проекта, где искать. Полезно для нового члена в команде или передачи проекта на аутсорс разработку
  • Название поля
  • Тип поля
  • Обязательность поля в проектах (напоминаю, у нас была БД другого проекта) — маркер синхронизации требования обязательности между документом и интерфейсом. В случае, обязательности информации в документе и система не может другим путем её получить, необходимо будет сделать это поле в интерфейсе обязательным
  • Маска поля — в нормативной документации четко определен формат записи информации.
  • Значение по умолчанию
  • Максимальное количество символов в поле
  • Масштабируемость поля (зависит от разрешения) — описание поведения элемента интерфейса в зависимости от разрешения
  • Требование к данным — какое взаимодействие разрешено с элементом интерфейса, и что может придти на вход
  • Образец успешного заполнения
  • Плэйсхолдер — подсказка для пользователя внутри элемента интерфейса
  • Кастомизация поля — нестандартные элементы интерфейса или допиленные под задачи
  • Дополнительная информация рядом с полем — когда плэйсхолдером не обойтись из-за объема текста, то используем тултип или дескриптор
  • Тип валидации
  • Сообщение валидации — условия и ответ системы
  • Переменная в шаблонах документов — что будет вставлено в шаблон документа
  • Ссылка на страницу — не использовал в итоге
  • Расположение поля в интерфейсе — не использовал в итоге

Документация подключения документа

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

image

Шаблон «Подключение документов», надеюсь что он кому-то пригодится.

Содержание:

  • Статус — говорит в каком состоянии на данный момент документ в системе. Один документ мы подключали в 3 этапа, статус документа был «Доработать»
  • Документ — название документа внутри команды, базы знаний и внутри нашей документации и системы постановки задач
  • Тип
  • Формат документа — когда один и тот же документ, может быть в разных шаблонах в зависимости от нормативно-технической документации, которой этот документ соответствует
  • Формирование — документ может быть просто шаблоном, в который просто подставляются переменные или же из шаблона в 3 стр может получаться 100+ страничные документы — динамические документы
  • Наличие в пакете — особенность системы, можно получить пакет документов или скачать документы по отдельности
  • Условие наличия — присутствие конкретного документа в пакете
  • Особенность подключения — та часть документа, которой нет в шаблоне и она регламентируется кодом.
  • Ссылка на файл для подключения
  • Скачать отдельно
  • Название файла для скачивания — документ в системе может называться как угодно, но конечный пользователь при скачивании должен видеть определенное название

Итого

В результате мной в обоих документах заполнено 362 строки. Внушительный объем? Но на деле это на 30+ шаблонов документов и суммарно затрачено 40-60 часов работы одного человека за два года (1-1,5 недели), без учета редактуры самих шаблонов и формулировки задач на подключение.

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

Основные этапы при документации процесса генерации документов:

  • Анализ содержательной части документов
  • Гигиена документов
  • Фиксировать переменные параллельно с разметкой документов
  • Фиксировать нюансы подключения шаблонов документов.

Спасибо, что добрались до конца.


ссылка на оригинал статьи https://habr.com/ru/post/465651/

Новости из мира OpenStreetMap № 474 (13.08.2019-19.08.2019)

Logo

Участки зеленого цвета — информация из OpenStreetMap, наложенная поверх спутникового снимка 1 | CC-BY-SA 2019 Public Lab contributor MaggPi – data OpenstreetMap contributors

Картографирование

  • Кевин Кенни начал разработку схемы тегирования protection_class=*, с помощью которой можно будет отметить степень защиты охраняемых территорий. Предполагается, что новая схема тегирования заменит собой существующую protect_class=*. Новая схема была разработана с целью повышения читаемости и полезности значений тегов, которые используются с этим ключом. Например, не совсем понятные числовые коды предлагается заменить на более удобно запоминающиеся обозначения.
  • MaggPi продемонстрировал, как можно работать со спутниковыми изображениями в среде разработки Jupyter Notebook. Например, совмещая данные из OpenStreetMap со спутниковым снимком можно понять, где находятся парковые зоны в Ноттингеме (Англия), или сравнить их между собой.
  • Ищешь, чтобы такого помапить? На сервисе MapRoulette появились новые интересные задачи:
    • В Индонезии нужно помочь проверить места, где контуры зданий пересекаются с дорогой
    • В штате Вашингтон (США) идет массовая валидация дорог, которые были добавлены в OpenStreetMap в рамках импорта данных TIGER
    • Порисовать города в Южной Африке, которые до сих пор не отмечены в OSM

  • Пользователь Марк Зоутендийк в своем 15-ом посте из серии «Улучшим OSM? Почему бы и нет!» размышляет об использовании тега landuse=village_green. Он считается, что этот тег не используется так, как должен, и имеет в каждом регионе свой смысловой окрас.
  • Пользователь Nvk рассказывает о своем проекте, в котором он реализовал поддержку в OSM функции отображения спорных границ в зависимости от того, кто зашел на сайт. Пользователь Фродриго также сейчас экспериментирует с нечто подобным.
  • Улица, которая имеет два названия: одно с одной стороны, другое — с другой, вызвала (автоматический перевод) небольшую дискуссию на форуме о том, как лучше всего ее отметить в OSM. Оказывается, такая ситуация в мире не редкость. 4 года назад на GitHub было предложено решение для этого проблемы. Всего же таких улиц сейчас в OSM — 4235. Они отмечены, как name:left/right.
  • Отмечаем солнечные батареи — это проект Великобритании на ближайший квартал. Это поможет улучшить прогнозирование для электросети и уменьшить потребность в генераторах электроэнергии, которые работают на невозобновляемых ресурсах, так как они смогут находиться в режиме ожидания. Посмотрев видео можно понять, как нанести на карту солнечные батареи. Кстати, уже 25 тысяч таких батарей отмечены!
  • Картографическая компания lvl5 была выкуплена и сейчас, как отмечает ее руководство, ее ждут «новые приключения», но при этом все оплаченные ими панорамы улиц в настоящее время загружаются в Mapillary. Вскоре по ним можно будет редактировать OSM.

Сообщество

  • Винсент Приват, один из основных разработчиков JOSM, недоволен одной из номинаций на премию Core Systems Award в этом году.
  • 10 лет назад Эрика Хаген и Микель Марон начали рисовать карту Киберы — крупнейших трущоб Кении. Не так давно Микель написал по этому поводу статью в своем блоге.
  • Фредерик Рамм предлагает отдать предпочтение собственным каналам связи для общения внутри OSM, например, организовать чат внутри онлайн-редактора iD. Он считает неправильным, что мы используем сервисы, которые контролируются извне. Этот же вопрос был поднят Юстомом Шуппе в проекте » OSM Community Index».

Фонд OpenStreetMap

  • Рабочая группа по лицензированию OSMF подготовила протоколы заседаний от 11 июля 2019 года и 8 августа 2019 года. Помимо прочего были обсуждены принципы атрибуции OSM и Brexit.
  • Местное отделение OSMF в Великобритании — OpenStreetMap UK CIC Ltd — представило в OSMF свои годовые и финансовые отчеты за финансовый год, который закончился 31 марта 2019 года.
  • Опубликованы протоколы заседаний совета директоров FOSSGIS от 7 мая (автоматический перевод) and 13 августа (автоматический перевод).

События

  • Информационный центр колледжа Университета Голуэй 31 августа проведет мероприятие, посвященное OpenStreetMap. Оно будет организовано совместно с местным отделением OSM в Ирландии.
  • Исследовательская группа Giscience Гейдельбергского университета приглашает всех на бесплатный семинар по организации маршрутизации на основе открытого кода. Мероприятие состоит 20 сентября 2019 года перед конференцией «State of the Maps».
  • Вы собираетесь побывать на конференции «State of the Map 2019» в этом году? Если да, то Кристоф Хорманн внимательно изучил программу и составил список рекомендованных для посещения лекций. В качестве бонуса он также проанализировал биографии докладчиков и на основе того, где были присуждены стипендии OSMF, предполагает, что конференция в будущем году пройдет на Филиппинах.

Гуманитарный OSM

  • Overpass Turbo — великолепно справляется с запросами и отображением данных из OpenStreetMap. Но все-таки это достаточно сложный сервис для пользователей, которые не совсем разбираются в OSM. Поэтому HOT создал свой собственный инструмент экспорта данных из OSM. Он позволяет любому выбрать интересующую его область, объект и быстро его выгрузить в нужный ему ГИС-формат. При этом совсем не нужно разбираться в тегах OSM, сервис позволяет выбрат из имеющегося списка заготовок.
  • Мелани Шабо — ГИС-координатор в «Красном кресте» — написала статью о том, как она провела совместную акцию с представительством некоммерческой организации «Missing Maps» в Канаде по улучшению устойчивости коренных жителей к стихийным бедствиям.

Карты

  • На сервере Fraunhofer есть отличный тайлы, на которые названия мест обозначены на английском языке. Это круто. Но нельзя просто так взять и использовать их в своем проекте. Придется сначала спросить.
  • Карта «Babykarte«, на которой отображаются объекты для родителей малышей, теперь локализована на французский язык. В новом обновлении есть фильтр, позволяющий выбрать игровые объекты и иные функции.

Открытые данные

  • Роб Китчин доволен тем, как у него получилось напечатать 3D-карту Дублина.

Программирование

  • Николай Петров обратил внимание, что сайт «Domofond» (аренда и продажа недвижимости) использует данные OSM. Удивление вызвало то, что в качестве подложки — Яндекс.Карта, а данные OSM накладываются поверх нее.
  • Российский пользователь ZKir усовершенствовал свой валидатор, который проверяет наличие 3D-моделей для церквей и некоторых других исторических зданий. Теперь 3D-модели отображаются прямо на web-странице в валидаторе. Выглядит это так или вот так.

Релизы

  • Мобильное приложение для общественного транспорта в городе Кочабамба (Боливия) Trufi теперь доступно и на iOS.

А знаете ли вы …

  • … что вы можете наблюдать в режиме реального времени за перемещениями морских судов на сайте «Vessel Finder«? Этот сайт использует данные из автоматической системы идентификации и отображает их на карте на основе OpenStreetMap.
  • … в чем состоит разница между тегом change (при движении разрешено покидать полосу — разворот) и overtaking (разрешен обгон)? Несмотря на законодательство эти два теги не являются идентичными, ведь обгон может быть разрешен даже там, где есть физическое разделение полос полосы, а разворот возможен там, где можно пересекачь линию.
  • … о простом и красивом сайте Nebo.live, который показывает качество воздуха в Красноярске?
  • … про карту запретных зон для полетов на квадрокоптере?
  • … как подключить онлайн-карты к навигатору в смартфоне (части 1, 2, 3)

OSM в СМИ

  • Нередко бывает так, что правки карты в OSM являются информподом, что не так давно и случилось в районе Вальдсхвт (Германия). Альбальштрассе закрыта в 2015 года в связи с камнепадом, а это было расценено, как доказательство (автоматический перевод) того, что она не будет вновь открыта для движения.

Другие «гео» события

  • На сайте theverge.com появились материалы из китайских газет, согласно которым Huawei работает над альтернативой Google Maps. Ожидается, что их собственные карты «Map Kit» появятся в октябре.
  • Radio Garden — это геосервис, позволяющий находить и слушать потоковые радиостанции всего мира в прямом эфире. «Radio Garden» появился в 2016 году по заказу Нидерландского института звука и видения в рамках выставки, посвященной международному исследовательскому проекту «Транснациональные радиопередачи».
  • Корпорация «Лондонский транспорт» (Transport for London) в этом месяце опубликовала “самую большую в мире базу данных велосипедной инфраструктуры». Стартапы уже во всою используют эти данные для улучшения своих услуг планирования поездок. Компания «Beeline» сейчас разрабатывает собственный инструмент маршрутизации, построенный на OpenStreetMap для Лондона.
  • Yanko Design создает и продает карты освещения, которые показывают, как выглядел бы ваш любимый город сверху ночью. Эти карты составлены на основе данных OSM.


Общение российских участников OpenStreetMap идёт в чатике Telegram и на форуме. Также есть группы в социальных сетях ВКонтакте, Facebook, но в них в основном публикуются новости.

Присоединяйтесь к OSM!


Предыдущие выпуски: 473, 472, 471, 470, 469,


ссылка на оригинал статьи https://habr.com/ru/post/465655/