Русский
Русский
English
Статистика
Реклама

Профессиональная литература

Интервью с Михаилом Михеевым, автором первой книги на русском по vSphere

20.05.2021 18:13:57 | Автор: admin

Не так давно мы публиковали интервью Один день из жизни разработчика VMware рассказ о карьере ИТ-специалиста в крупной международной компании.

А сейчас у нас возникла идея поискать в своем отечестве, и мы обратили внимание на российский офис VMware. Программистов в нем нет, но есть о чем поговорить с инженерами presales. Встречайте Михаил Михеев!

Если вы стояли у истоков использования виртуализации в России, то вы могли знать о нем как о человеке, который:

  • вел блог по этой узкой тематике и обучающие курсы;

  • участвовал в организации встреч сообщества;

  • написал книгу Администрирование VMware vSphere.

Мы решили поговорить с Михаилом по душам и выведать, как он попал в ИТ, почему решил написать собственную книгу и как стал сотрудником VMware, не будучи программистом. Небольшой спойлер: оказалось, под маской уверенного в себе специалиста скрывается обычный человек. Скромный и с превосходным чувством юмора.

Эксперт с форума

Пути, по которым ведет нас жизнь, не всегда поддаются логическому анализу. Порой даже случайности, которым не придаешь особого значения, становятся решающими. Итак, представьте: Казань. Я учусь на последнем курсе университета. Стажируюсь за еду бесценный опыт у местного интегратора. (Большое спасибо им, кстати: я в первые полгода действительно не умел делать ничего полезного, чтобы просить денег.) И вот передо мной поставили задачу разобраться с неподдавшимся с наскока продуктом, Microsoft SMS 2003. Мне удалось найти один админский форум: там я искал информацию и задавал тонны вопросов в основном как раз по этому продукту. В первое время я только спрашивал, затем осмелел и начал понемногу отвечать менее опытным товарищам. Как потом выяснится, потребность делиться знаниями это неотъемлемая часть моего характера.

Мои ответы заметил форумчанин, очень много помогавший мне на начальных этапах. Можно сказать, я рос на его глазах. Совпало, что в то же самое время к нему обратился один из московских учебных центров: мол, есть ли на примете тренер, который может прочитать курс по MS SMS? И он пришел с этим предложением ко мне.

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

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

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

Шел 2005 год. Товарищ с форума оставил мне контакты учебного центра. Представьте мое состояние: где я, студент Миша из Казани, а где это достойное заведение! Заметьте: я раньше не только лекции сам не вел, но даже слушателем подобных вендорских курсов мне бывать не доводилось. Я очень ОЧЕНЬ волновался перед звонком.

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

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

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

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

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

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

Со временем я начал читать и другие курсы по продуктам Microsoft немного, буквально две-три штуки. Учебный центр нашел еще одного нишевого вендора, и некоторые курсы по его продуктам тоже достались мне. Приблизительно в то же время (2006 год) на российский рынок вышла и VMware. Мой учебный центр оперативно заключил с ними соглашение, и я стал первым преподавателем по vSphere (тогда продукт носил немного другое название) на территории РФ. Наверное, достаточно долгое время я был вообще единственным. Как и сейчас, курс назывался Install, Configure, Manage (ICM). Добротный и весьма полный материал для подготовки молодых бойцов в сфере виртуализации.

Личный блог для самообучения

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

В первое время мне за глаза хватало и тренинг-гайда: я мог прочитать его 10 раз и каждый раз находил что-то новое. Много времени я проводил с лабораторными машинами: разворачивал продукты, воспроизводил лабы, крутил их по-разному. Эта практика тоже оказалась очень полезной, я восполнял пробелы в базовых знаниях. Сейчас уже не вспомню: возможно, я читал какие-то англоязычные книги, но привычки их искать и изучать еще не было. Это пришло немного позже. Может быть, я тогда вообще ничего профильного со стороны не читал (смеется).

Затем я открыл для себя мир блогов. Они стали сами собой появляться по всему интернету: гуглишь что-то специфическое, и бац! выдается чей-то личный блог. Я перешел в фазу жадного поглощения информации и спустя короткое время оказался подписан буквально на десятки тематических блогов. Тогда я столкнулся со следующей проблемой: оказалось, недостаточно просто прочитать информацию, чтобы ее запомнить. Мне нужен был способ пропустить знания сквозь себя, выделить наиболее важные моменты и усвоить их. Так и возник мой собственный блог не из желания продвинуть свою фигуру, а чтобы важная информация откладывалась в голове через написание статей и заметок. Надо сказать, этот шаг тоже дался мне непросто. Все-таки, это публичное поле, новая ответственность :)

Главная страница блога МихаилаГлавная страница блога Михаила

Работа преподавателем, с одной стороны, заставляла меня постоянно получать новые знания, с другой оставляла много свободного времени на учебу. Либо тренинги удавалось закончить немного пораньше, либо выдавались свободные недели, и я мог активно постить в блог. Можно сказать, я тогда занимался на 90% именно переработкой: публиковал короткое резюме-выдержку со ссылкой на оригинальную заметку.

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

Огонь в глазах, дискуссии и споры

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

С опытом я научился различать, к какой категории относятся те или иные мои слушатели. К моему удивлению, огонь далеко не всегда коррелирует с возрастом. Я видел и сонных молодых людей, которым ничего не интересно, и (почти) бабушек-дедушек, которые расспрашивали меня и действительно понимали, о чем идет речь на курсе. Я тогда решил, что дедушкой я хочу стать именно таким. Разумеется, не прямо сейчас, а с годами :)

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

Так я заметил еще один момент: в каждой группе между инициативными слушателями возникали дискуссии, споры. Я поощрял такие ситуации, даже говорил: Ребята, так получилось, что преподаватель здесь я, но у многих из вас есть опыт, которого нет ни у меня, ни у ваших коллег. Обменивайтесь этим опытом!. Наблюдая со стороны, я обратил внимание на то, что многие споры возникали из-за недопониманий между людьми. Два человека могли говорить об одном и том же, но разными словами. Или для обозначения разных понятий использовали одни и те же термины. Я старался всеми силами минимизировать такие ситуации, выводя спор в конструктивное русло. Дискуссии хороши, если обе стороны понимают друг друга и не пускаются в терминологические споры. Возможно, эта практика помогала людям учиться эффективнее и, в том числе, находила свое отражение в позитивных отзывах.

Мужики в свитерах: правда или вымысел?

Пару слов скажу о контингенте на моих курсах: на 98% процентов это были системные администраторы и инженеры заказчиков или интеграторов. Как правило, характеры у тех, кто представляет заказчиков, отличаются от тех, кто пошел на работу к интеграторам. Это, скорее, курьезное наблюдение, чем строгое. Что касается возраста были все, от молодежи до зрелых специалистов. Люди постарше приходили, конечно, реже.

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

Когда в 2008-ом у меня вышла собственная книга и в узких кругах я стал Тем-Самым-Михаилом-С-Книжкой, я даже дежурно шутил: жаль, что в ИТ мало девушек. Приятно, конечно, когда бородатые мужики в свитерах пожимают тебе руку и говорят, какую классную книгу ты написал. Это льстит. Но все равно это бородатые мужики в свитерах

(На всякий случай еще раз поясню: это дежурная шутка!)

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

Как писалась книга

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

Я хорошо запомнил день, с которого все началось. Меня тогда отправили в командировку в Хабаровск как раз таки с курсами по VMware. Время от времени я летал с учебными задачами, в основном по отдаленным от Москвы местам: Казахстан, Баку, Дальний Восток. А длительный перелет это смена часовых поясов и неминуемый джет лаг.

Представьте себе: 4 часа утра. Гостиница, сна ни в одном глазу. Чтобы занять руки, отвечаю на вопрос читателя моего блога. Гуглю, чтобы уточнить информацию и попадаю... правильно, в собственный блог! Выходит, я все это знал, даже писал об этом, но забыл. За пониманием пришло озарение: а что, если я возьму и зафиксирую свои текущие знания в виде книги? Под рукой как раз была программа для составления mind mapов, в ней я начал накидывать приблизительное содержание про что и в каком порядке можно рассказать. Это был первый подход: крупные мазки, обширные планы.

Запала хватило на то, чтобы написать начало, а потом я стал перегорать. Не знаю, продвинулся бы я дальше, если бы не очередное удивительное совпадение. Спустя короткое время я поехал на конференцию VMware. Во время перерыва ко мне подошел представитель нишевого издательства: Вы Михаил Михеев? Очень приятно. Мне посоветовали обратиться к вам по поводу написания книги по теме виртуализации. Звезды сошлись: мысли о книге одновременно пришли в голову и мне, и издателю.

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

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

Есть несколько воспоминаний из той поры:

  • Издатель выдал набор правил оформления рукописи (подозреваю, что-то из области ГОСТов). А-ля пункты нумерованного списка должны заканчиваться точкой, а не-нумерованного точкой с запятой, кроме последнего, где тоже нужна точка. Запомнить все эти заморочки оказалось непросто, но в дальнейшем эти знания мне не раз пригодились.

  • Скриншоты это сущий ад. На них уходила если не бльшая, то как минимум львиная доля времени. А в инструкции от издателя было указано: скриншоты сохраняйте в таком-то формате, притом обязательно черно-белые. Я люблю делать все по инструкции, поэтому не противился. И угадайте что? Оказывается, инструкция не учитывала существование электронных версий книг, где, очевидно, не имеет смысла черно-белить картинки. Подозреваю, издатель попросту не подумал об электронной книге (да-да, смешно звучит с высоты 2021 года). А для меня это обернулось повторным созданием почти всех скринов, так как исходники я почему-то не сохранял.

  • Знали бы вы, как я стеснялся выложить анонс у себя в блоге. Очень сильно нервничал :)

Анонс книги в блогеАнонс книги в блоге

Всего было три релиза: первый по 4-ой версии vSphere, второй по 4.1, а последний был посвящён уже 5-ой версии. Бумажные издания оформлены в разных цветах, чтобы читатели не путались.

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

В свое время я шутил: мол, я написал самую лучшую книгу по VMware на русском языке. Знаете, почему? Потому что единственную, других нет.

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

Один писатель-фантаст сказал: автор [в случае пиратства] теряет не столько деньги, сколько право распоряжаться плодом своего труда. В правовом поле автор может убрать свое произведение из конкретного магазина или вообще изъять из продажи. С условным торрентом это не так, это обидно. Вне зависимости от того, будешь ты что-то такое делать или нет.

Меня часто спрашивают, пишу ли я новую книгу. Короткий ответ нет. Чаще всего отшучиваюсь: мол, куда, у меня уже двое детей!

А если серьезно я и блог-то уже лет 7 не веду. Когда я был занят преподаванием, и блог, и книга были частью моей работы. В том числе, над собой. Моя текущая работа в VMware оставляет намного меньше времени на такие проекты. Честности ради в какой-то момент я предпринял еще одну попытку обновить книгу, но буквально через неделю понял: нет, не стоит этим заниматься. На предыдущем жизненном этапе у меня была четкая цель: что я хочу сделать, для кого и зачем. А книга ради книги это никому не интересно.

Сам собой назревает дискуссионный вопрос: вот я молодой, горящий специалист, есть ли мне смысл заявить о себе, написав книгу? [не суть важно, но, допустим, по решению VMware].

Выскажу свое мнение.

С одной стороны, сейчас у VMware есть продукты, по которым нет русскоязычных материалов. Так что смысл написать по ним книгу имеется, у специалистов она будет востребована. Но насколько велика будет аудитория? Вопрос открытый. К примеру, первый тираж моей книги составил порядка 5 тысяч экземпляров (за давностью могу ошибаться).

Это много или мало?

C другой стороны, старая добрая книга это уже немного олдскул. Есть блоги, есть YouTube. Есть Telegram-каналы, в конце концов. Может, лучше в эту сторону копнуть?

Готовогоответа у меня нет, но мне кажется, что классическая книга по-прежнему имеет смысл. Все-таки, когда ты говоришь: я Миша, автор [например] Telegram-канала такого-то или я автор такой-то книги, эффект получится разным.

Мой совет прислушайтесь к себе, постарайтесь понять задачу, которую хотите решить. Тогда вам станет ясно, каким способом подходить к решению: с помощью блога, канала или, к примеру, книги.

Как я попал в VMware

Наступил 2011 год. К тому моменту я уже имел около 6 лет преподавательского стажа. Популярность VMware и, соответственно, номенклатура курсов росли. Бывало так, что в течение месяца я мог читать один и тот же курс двум-трем разным группам.

С одной стороны, работа мне нравилась: я получал удовольствие от общения с людьми. Любил объяснять какие-то нетривиальные моменты. А с другой стал замечать, что прихожу на работу в понедельник, а голова включается только к среде. Рутина. Вышел к доске и пошел по накатанной: одни и те же слова, одни и те же шутки. Всем, вроде, нравится, а мне нет.

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

Помнится, сижу я в больнице. Жду приема врача. Раздается звонок с незнакомого номера: оказалось, звонит руководитель пресейлов VMware. Предлагает пообщаться. Я тогда ничего не понял какую именно работу мне предлагают, чем я буду заниматься... Но все равно согласился на встречу.

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

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

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

Значимую долю времени занимает обучение на внутренних и внешних курсах. Мир развивается, портфолио развивается, продукты обзаводятся новыми функциями и возможностями. Без обучения никак.

Кстати: еще в задачи пресейл-инженера входит обучение заказчиков и партнеров, а также выступления на различных мероприятиях. Например, в этом году наши пресейлы проводят цикл весенних вебинаров VMware 2021, которые будут идти до июня. На них можно не только послушать экспертов, но и пообщаться с ними в чатах и Q&A. Зарегистрироваться на вебинары можно на сайте, а посмотреть онлайн-мероприятия в записи на нашем YouTube-канале. А для энтузиастов у нас есть канал в Telegram: там мы напоминаем о старте вебинаров и делимся видео.

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

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

Немного об изоляции

У нас переход на полную удаленку прошел очень гладко. Иногда мы с коллегами обмениваемся опытом, у кого и как оборудовано рабочее место.

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

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

Кто востребован в VMware

Наверное, я сейчас скажу не самую очевидную вещь. Нам не особо важно, является ли человек экспертом в продуктах VMware. Этому мы как раз можем научить на месте: и ресурсов, и учебных материалов, и опыта у нас достаточно. Любые ИТ-продукты это не квантовая физика. Получить нормальную или даже отличную экспертизу в них можно. Главное воспринимать это не как проблему, а как задачу. Попробовал получилось. Поотвечал на вопросы и сам не заметил, как освоил тему.

Гораздо сложнее научить человека soft-скиллам и такому навыку, как доведение дел до конца. Работы больше, чем времени в сутках, поэтому всегда есть соблазн что-то здесь поделать, там поковырять, но до конца не доводить. Льется нескончаемый поток задач, и ты думаешь: я буду что-то отдельное выхватывать. Это не очень хорошая история. Если уж взялся делай. Не берешься скажи. Не оставляй повисшим в воздухе.

Один из главных soft-скиллов уметь говорить на языке собеседника. Отличным примером является известный в хаброкругах Milfgard. Помните шикарную статью про недочеты в унаследованной архитектуре живых существ? Огонь же! И в том числе потому, что материал подан на языке читательской аудитории.

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

Из очевидных требований сотруднику необходим разговорный английский. VMware мировая компания, на ежедневной основе люди работают в интернациональных группах, обращаются за консультацией или помощью к западным коллегам. По-моему, это здорово, когда ты в рамках рабочего общения можешь поговорить с крутыми людьми, представителями родственной профессии, живущими в другой стране или даже части мира. Прикоснуться к их культуре, менталитету. Незабываемый опыт. Отдельная приятность прямой доступ к Product Managerам, которые непосредственно отвечают за развитие продуктов (нередко прямо в Кремниевой долине, с географической точки зрения). Лично мне очень импонирует возможность обратиться к первоисточникам, а то и пригласить их на конф-колл по проекту с заказчиком.

Немного о Хабре

Хабр для меня один из главных источников информации из разных сфер.

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

Просто просмотр заголовков статей в RSS-клиенте позволяет составить мнение о событиях мира ИТ в целом.

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

Обязательно читаю статьи Milfgardа. Во-первых, он в принципе хорошо складывает слова в приложения. Во-вторых, он хорошо умеет разговаривать на языке аудитории. Это крутая тема, близкая мне и по работе преподавателем, и по нынешней. Его статью Вы неправильно пишете животных я даже перечитываю для удовольствия иногда, круто написана и оптимизирована под ИТ.

Ну и нельзя не сказать, что именно с его статьи Настольные игры: во что играют в IT-офисах? от далекого 2011 года началось мое нынешнее увлечение настольными играми, в котором я весьма глубоко погряз :)


Друзья! Если вам интересен такой формат, будем рады вашим пожеланиям. Поделитесь в комментариях, интервью с представителями каких сфер и профессий вам бы хотелось видеть на Хабре.

Подробнее..

Книга JavaScript с нуля

15.06.2021 18:13:51 | Автор: admin
imageПривет, Хаброжители! JavaScript еще никогда не был так прост! Вы узнаете все возможности языка программирования без общих фраз и неясных терминов. Подробные примеры, иллюстрации и схемы будут понятны даже новичку. Легкая подача информации и живой юмор автора превратят нудное заучивание в занимательную практику по написанию кода. Дойдя до последней главы, вы настолько прокачаете свои навыки, что сможете решить практически любую задачу, будь то простое перемещение элементов на странице или даже собственная браузерная игра.

Вот небольшой список того, что вы узнаете:

Как организовать код с помощью переменных.
Как функции делают ваш код повторно используемым.
Как работать с циклами и условиями.
Что такое глобальная и локальная области видимости.
Что такое замыкания.
Как правильно писать комментарии.
Основные типы объектов, с которыми вы столкнетесь в JavaScript.
Как работать с текстом и выполнять стандартные операции со строками.
Как использовать массивы для обработки списков.
Как создавать собственные объекты.

О ПИЦЦЕ, ТИПАХ, ПРИМИТИВАХ И ОБЪЕКТАХ


В ЭТОЙ ГЛАВЕ:

  • разберем суть и особенности объектов;
  • познакомимся с базовыми типами в JavaScript;
  • выясним, что пицца обладает не только прекрасным вкусом, но и образовательной ценностью.

Пора заняться серьезными делами. Суперсерьезными! В последних нескольких главах мы изучили разные значения, в том числе: строки (текст), числа, логические значения (true и false), функции и другие встроенные элементы JavaScript.

Вот некоторые примеры, чтобы освежить память:

let someText = "hello, world!";let count = 50;let isActive = true;

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

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

Поехали!

Сначала поговорим о пицце


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

Если вы давненько ее не ели, то напомню, как она выглядит:

image

Конечно же, пицца не появляется в таком виде из ниоткуда. Она создается из простых и сложных ингредиентов:

image

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

image

Они не изготавливаются и не составляются из других компонентов.

К сложным же ингредиентам относятся сыр, соус, основа из теста и пеперони. Сложными их делает то, что они сделаны из других ингредиентов:

image

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

От пиццы к JavaScript


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

image

Подобно сыру, соусу, пеперони, грибам и бекону в нашей пицце, типами в JavaScript являются string (строка), number (число), boolean (логическое значение), null (пустой), undefined (не определен), bigint (целочисленные значения), symbol (символы) и Object (объект). С некоторыми из этих типов вы уже можете быть знакомы, с некоторыми нет. Подробнее мы будем рассматривать их в дальнейшем, сейчас же в табл. 12.1 вы можете посмотреть краткое описание их назначения.

image

Как мы видим, каждый тип имеет свое уникальное назначение. При этом они, аналогично ингредиентам пиццы, также подразделяются на простые и сложные. Только в терминологии JavaScript простые и сложные типы называются примитивами (примитивные типы) и объектами (объектные типы) соответственно.

К примитивным типам относятся string, number, boolean, null, bigint, symbol и undefined. Любые значения, попадающие в их юрисдикцию, не подлежат делению на части. Они являются халапеньо и грибами в мире JavaScript. Примитивы достаточно легко определять и оформлять в понятные элементы. В них нет глубины, и при встрече с ними мы, как правило, получаем то, что видим изначально.

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

Что такое объект?


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

Некоторые объекты вроде пресс-папье малофункциональны и могут долго бездействовать.

image

Другие объекты, вроде телевизора, уже выходят за рамки простого существования и выполняют множество задач:

image

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

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

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

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

Предопределенные объекты в JavaScript


Помимо встроенных типов, перечисленных ранее, в JS также изначально присутствуют предопределенные объекты. Эти объекты позволяют работать с чем угодно, включая наборы данных, даты, текст и числа. В табл. 12.2 приводится аналогичный предыдущему список, описывающий их назначения:

image

Использование встроенных объектов несколько отличается от использования примитивов. Каждый объект в этом плане по-своему особенный. Подробное пояснение всех этих особенностей использования я отложу на потом, а здесь приведу короткий фрагмент кода c комментарием, который покажет возможные варианты:

// массивlet names = ["Jerry", "Elaine", "George", "Kramer"];let alsoNames = new Array("Dennis", "Frank", "Dee", "Mac");// округленное числоlet roundNumber = Math.round("3.14");// текущая датаlet today = new Date();// объект booleanlet booleanObject = new Boolean(true);// бесконечностьlet unquantifiablyBigNumber = Number.POSITIVE_INFINITY;// объект stringlet hello = new String("Hello!");

Вас может несколько озадачить то, что примитивы string, boolean, symbol, bigint и number могут существовать и в форме объектов. Внешне эта объектная форма выглядит очень похожей на примитивную. Вот пример:

let movie = "Pulp Fiction";let movieObj = new String("Pulp Fiction");console.log(movie);console.log(movieObj);

При выводе обоих вариантах вы увидите одинаковый результат. Тем не менее внутренне movie и movieObj весьма различны. Первый буквально является примитивом типа string, а второй имеет тип Object. Это ведет к интересному (а иногда и непонятному) поведению, о котором я постепенно расскажу в процессе изучения встроенных типов.

КОРОТКО О ГЛАВНОМ

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

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

Более подробно с книгой можно ознакомиться на сайте издательства
Оглавление
Отрывок
Электронная версия книги цветная

Для Хаброжителей скидка 25% по купону JavaScript

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Подробнее..

Книга TypeScript быстро

22.04.2021 12:11:11 | Автор: admin
image Привет, Хаброжители! TypeScript быстро научит вас секретам продуктивной разработки веб- или самостоятельных приложений. Она написана практиками для практиков. В книге разбираются актуальные для каждого программиста задачи, объясняется синтаксис языка и описывается разработка нескольких приложений, в том числе нетривиальных так вы сможете понять, как использовать TypeScript с популярными библиотеками и фреймворками. Вы разберетесь с превосходным инструментарием TypeScript и узнаете, как объединить в одном проекте TypeScript и JavaScript. Среди продвинутых тем, рассмотренных авторами, декораторы, асинхронная обработка и динамические импорты. Прочитав эту книгу, вы поймете, что именно делает TypeScript особенным.


ДЛЯ КОГО ЭТА КНИГА
Эта книга написана для инженеров ПО, которые хотят повысить продуктивность разработки веб- или самостоятельных приложений. Мы, ее авторы, являемся практиками и книгу писали для таких же практиков. В ней не только объясняется синтаксис языка на простых примерах, но также описывается разработка нескольких приложений так вы можете понять, как использовать TypeScript с популярными библиотеками и фреймворками.

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

Этот материал, в свою очередь, предполагает, что у читателей уже есть практические познания в HTML, CSS и JavaScript, использующем последние нововведения из спецификации ECMAScript. Если вам знаком только синтаксис ECMAScript 5, рекомендуем просмотреть приложение, чтобы лучше понимать примеры кода, используемые в книге. Приложение выполняет роль введения в современный JavaScript.

СТРУКТУРА КНИГИ
Эта книга состоит из двух частей. В части 1 мы рассматриваем различные элементы синтаксиса TypeScript, приводя для наглядности небольшие образцы кода. В части 2 мы используем TypeScript в нескольких версиях блокчейн-приложения. Если ваша цель как можно быстрее освоить синтаксис TypeScript и сопутствующие инструменты, тогда части 1 будет достаточно.

Глава 1 поможет начать разработку с помощью TypeScript. Вы скомпилируете и запустите самые простые программы, чтобы понять суть рабочего процесса от написания программ в TypeScript и до их компиляции в выполняемый JavaScript. Мы также рассмотрим преимущества программирования в TypeScript в сравнении с JavaScript и представим вам редактор Visual Studio Code.

Глава 2 поясняет, как объявлять переменные и функции с типами. Вы научитесь объявлять псевдонимы типов с помощью ключевого слова type, а также узнаете, как объявлять пользовательские типы с классами и интерфейсами. Это поможет понять разницу между номинальными и структурными системами типов.

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

Глава 4 посвящена перечислениям и обобщенным типам. Она рассматривает преимущества использования перечислений, синтаксис для численных и строчных перечислений, назначение обобщенных типов, а также показывает, как прописывать классы, интерфейсы и поддерживающие их функции.

Глава 5 описывает декораторы, а также отображенные и условные типы. Все это относится к продвинутым типам TypeScript, поэтому для понимания этой главы следует ознакомиться с синтаксисом обобщенных типов.

Глава 6 посвящена сопутствующим инструментам. В ней мы рассказываем об использовании карт кода и TSLinter (несмотря на то, что TSLinter считается устаревшим, многие разработчики по-прежнему им пользуются). Затем мы покажем вам, как компилировать и обвязывать (bundle) приложения TypeScript с помощью Webpack. Вы также узнаете, как и зачем компилировать TypeScript с помощью Babel.

Глава 7 научит вас использовать библиотеки JavaScript в вашем TypeScript-приложении. Мы начнем с объяснения роли файлов определений типов, а затем представим небольшое приложение, использующее библиотеку JavaScript в приложении TypeScript. В завершение мы пройдем через весь процесс постепенного перевода имеющегося проекта JavaScript в TypeScript.

В части 2 мы используем TypeScript в блокчейн-приложении. Здесь вы можете подумать: Ни одна из компаний, где я работал, не использует блокчейн, так зачем мне его изучать, если моя цель освоение TypeScript? Мы не хотели, чтобы наш образец приложения был очередным стандартным примером, поэтому озадачились поиском горячей технологии, в которой можно было бы применить различные элементы TypeScript, а также техники, представленные в части 1. Знакомство с тем, как TypeScript может быть использован в нетривиальном приложении, придаст содержанию больше практичности, даже если вы не собираетесь использовать блокчейн в ближайшем будущем.

В этой части книги вы разработаете несколько блокчейн-приложений: самостоятельное приложение, браузерное приложение, а также приложения на Angular, React.js и Vue.js. При этом можете выбрать к прочтению только интересующие вас главы, но обязательно прочитайте главы 8 и 10, где объясняются основные принципы.

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

В главе 9 описывается создание веб-клиента для блокчейна. Это приложение не будет использовать никакие фреймворки; в нем мы задействуем только HTML, CSS и TypeScript. Мы также создадим небольшую библиотеку для генерации хеша, которую можно будет использовать как в веб-, так и в самостоятельных клиентах. Помимо этого, вы увидите, как производить отладку кода TypeScript в своем браузере.

Глава 10 рассматривает код блокчейн-приложения, использующего сервер обмена сообщениями для связи между членами блокчейна. Мы создадим Node.js и WebSocket сервер в TypeScript и покажем вам, как для достижения консенсуса блокчейн использует правило длиннейшей цепочки. Вы найдете практические примеры использования TypeScript интерфейсов, абстрактных классов, квалификаторов доступа, перечислений и обобщенных типов.

В главе 11 дается краткий обзор разработки веб-приложений в Angular при помощи TypeScript, а глава 12 рассматривает код блокчейн-веб-клиента, разработанного с помощью этого фреймворка.

Глава 13 дает краткое введение в разработку веб-приложений в React.js с помощью TypeScript, а глава 14 рассматривает код блокчейн-веб-клиента, разработанного с React.

Глава 15 аналогичным образом представляет разработку веб-приложений в Vue.js с помощью TypeScript, а глава 16 рассматривает блокчейн-веб-клиент, разработанный с использованием Vue.

ИСПОЛЬЗОВАНИЕ КОМПИЛЯТОРА BABEL


Babel это популярный JS-компилятор, предлагающий решение для широко известной проблемы: не все браузеры поддерживают весь набор возможностей, объявленных в ECMAScript. Мы даже не говорим о полной реализации конкретной версии ECMAScript. В любой момент времени один из браузеров может реализовать конкретную выборку возможностей из ECMAScript 2019, в то время как другой по-прежнему будет понимать только ECMAScript 5. Посетите сайт caniuse.com и поищите arrow functions (стрелочные функции). Вы увидите, что Internet Explorer 11, OperaMini и некоторые другие браузеры их не поддерживают.

Если вы разрабатываете новое веб-приложение, то захотите протестировать его для всех браузеров, которые могут использоваться вашей целевой аудиторией. Babel позволяет вам писать современный JS и компилировать его в более старые версии. Несмотря на то что tsc дает возможность указать для компиляции конкретную целевую спецификацию ECMAScript (например, ES2019), Babel более точен. Он позволяет выборочно указать возможности языка, которые требуется трансформировать в JavaScript, поддерживаемый старыми браузерами.

На рис. 6.9 показан фрагмент таблицы совместимости с браузерами (из mng.bz/O9qw). Сверху вы видите названия браузеров и компиляторов, а слева расположен список возможностей. Браузер, компилятор или среда выполнения сервера могут полностью либо частично поддерживать некоторые из перечисленных возможностей, а плагины Babel позволяют указывать только конкретные из них, которые требуется трансформировать в более старый код. Полный список плагинов можно посмотреть в документации Babel: babeljs.io/docs/en/plugins.

image


В целях этого рассмотрения мы выбрали функцию Обрезка строк из ES2019 (см. черную стрелку слева от рис. 6.9). Давайте предположим, что наше приложение должно работать в браузере Edge. Проследуйте по вертикальной стрелке, и вы увидите, что Edge 18 на данный момент реализует обрезку строк только частично (2/4).

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

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

В разделе A.12 приложения мы включили скриншот из babeljs.io, иллюстрирующий Babel-инструмент REPL. Взгляните на меню Babel Try it now, показанное на рис. 6.10, где вы увидите навигационную панель, позволяющую конфигурировать предустановки.

Каждая предустановка просто является группой плагинов, и если вы хотите скомпилировать код в синтаксис ES2015, достаточно отметить галочкой es2015. Вместо указания имен спецификаций ECMAScript вы можете настраивать конкретные версии браузеров или других сред выполнения, используя опцию ENV PRESET. Белая стрелка на рис. 6.10 показывает редактируемое окошко с предполагаемыми значениями для предустановки ENV: >2%, ie11, safari>9. Это означает, что вы хотите, чтобы Babel скомпилировал код для запуска во всех браузерах, имеющих рыночный охват не менее 2%, а также в Internet Explorer 11 и Safari.

Ни IE11, ни Safari 9 не поддерживают стрелочные функции, и если вы введете (a, b) ?a+b;, Babel преобразует это в JS, который перечисленные браузеры понимают, как показано в правой части рис. 6.11.

СОВЕТ Если вы видите ошибки после ввода имен браузеров, уберите галочку Enabled после введения браузеров и версий. Это похоже на баг, но к моменту прочтения вами этой книги он может быть уже устранен.

Теперь давайте изменим предустановку на last 2 chrome versions (две последние версии Chrome), как показано на рис. 6.12. Babel достаточно сообразителен, чтобы понять, что последние две версии Chrome поддерживают стрелочные функции и нет нужды производить преобразование.

image

Предустановка ENV идет со списком браузеров, и вам нужно использовать верные имена и фразы, чтобы указать ограничения (например, last2majorversions, Firefox>=20 или >5% in US). Эти фразы перечислены в проекте browserslist, который доступен здесь: github.com/browserslist/browserslist.

Мы использовали предустановку ENV в Babel REPL, чтобы поиграть с целевыми средами, но эти настройки могут быть также сконфигурированы и использованы из командной строки. В листинге 6.15 мы добавим в файл конфигурации .babelrc следующее: babel/preset-env. В листинге 6.17 вы увидите файл .browserlistrc, в котором вы можете настроить конкретные браузеры и версии, как мы делали в Babel REPL. Подробнее о preset-env вы можете прочитать в документации Babel здесь: babeljs.io/docs/en/next/babel-preset-env.html.

image


Babel может использоваться для компиляции таких языков, как JavaScript, TypeScript, CoffeeScript, Flow и др. Например, фреймворк React использует синтаксис JSX, который не относится к стандарту JS, и Babel это понимает. В главе 12 мы используем Babel с приложением React.

Когда Babel компилирует TS, он не выполняет проверку типов в отличие от tsc. Создатели Babel не реализовали полноценный компилятор TS. Babel просто считывает TS-код и генерирует соответствующий синтаксис JS.

Должно быть, вы подумали: Я вполне доволен компилятором TS. Зачем вообще в эту книгу о TypeScript включать раздел о компиляторе JS-в-JS? Причина в том, что вы можете подключиться к проекту, где часть модулей написаны в JS, а часть в TS. В таких проектах Babel может уже быть частью потока разработки-развертывания. Например, Babel популярен среди разработчиков, использующих фреймворк React, который лишь недавно начал поддерживать TS.

Подобно любому npm-пакету, вы можете установить Babel локально или глобально (с опцией -g). Локальная установка внутри директории проекта делает этот проект самодостаточным, так как после запуска npm install вы можете использовать Babel, не ожидая, что он установлен где-то в другом месте (кто-нибудь может работать над вашим проектом с другого компьютера).

npm install babel/core babel/cli babel/preset-env

Здесь babel/core является компилятором Babel, babel/cli интерфейсом командной строки, а babel/preset-env это предустановка ENV, которую мы недавно рассматривали.

В реестре npmjs.org пакеты JavaScript могут быть организованы как ветки. Например, babel это ветка для пакетов, относящихся к Babel. angular это ветка для пакетов, принадлежащих фреймворку Angular. @types это место для файлов определений типов TS для различных популярных JS-библиотек.


В последующих разделах мы представим вам три небольших проекта. Первый использует Babel с JS, второй Babel с TS, а третий Babel, TS и Webpack.

Использование Babel с JavaScript

В этом разделе мы рассмотрим простой проект, использующий Babel с JavaScript и расположенный в директории babel-javascript. Мы продолжим работать с трехстрочным скриптом index.js, представленным в листинге 6.7 и использующем JS-библиотеку Chalk. Единственное изменение в следующем листинге заключается в том, что сообщение теперь гласит Compiled with Babel (Скомпилировано с помощью Babel).

Листинг 6.15. index.js: исходный код приложения babel-javascript

const chalk = require('chalk');const message = 'Compiled with Babel';console.log(chalk.black.bgGreenBright(message));


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

image


Babel настраивается в файле .babelrc, и наш файл конфигурации будет очень прост. Нам нужно только использовать preset-env для компиляции.

Листинг 6.17. Файл .babelrc

{    "presets": [       "@babel/preset-env"    ]}


Мы не настраивали здесь никакие конкретные версии браузеров, и без каких бы то ни было опций конфигурации babel/preset-env ведет себя в точности так же, как babel/preset-es2015, babel/preset-es2016 и babel/preset-es2017. Другими словами, все возможности языка, представленные в ECMAScript2015, 2016 и 2017, будут скомпилированы в ES5.

СОВЕТ Мы сконфигурировали Babel в файле .babelrc, который отлично подходит для статических конфигураций вроде нашей. Если ваш проект требует программного создания конфигураций Babel, вам понадобится использовать файл babel.config.js (подробнее в документации Babel здесь: babeljs.io/docs/en/config-files#project- wide-configuration). Если вы хотите увидеть, как Babel компилирует наш файл src/index.js, установите зависимости этого проекта, выполнив npm install, а затем запустите npm-скрипт из package.json: npm run babel.

Следующий листинг показывает скомпилированную версию index.js, созданную в директории dist. Она будет иметь следующее содержимое (сравните с листингом 6.15):

image


Скомпилированный файл по-прежнему вызывает require('chalk'), и эта библиотека расположена в отдельном файле. Помните, что Babel это не бандлер. Мы используем Webpack с Babel в разделе 6.4.3.


Можете запустить скомпилированную версию так:

node dist/index.js

Вывод консоли будет выглядеть схожим с изображенным на рис. 6.13.

Если бы мы захотели, чтобы Babel генерировал код, работающий в конкретных версиях браузеров, потребовалось бы добавить дополнительный файл конфигурации, .browserslistrc. Например, нам нужно, чтобы код работал только в двух последних версиях Chrome и Firefox. Мы можем создать следующий файл в корне проекта:

image


Листинг 6.19. Пример файла .browserslistrc

last 2 chrome versionslast 2 firefox versions


Теперь при запуске Babel не будет преобразовывать const в var, как в листинге 6.18, потому что и Firefox, и Chrome уже поддерживают ключевое слово const. Попробуйте сами, чтобы убедиться.

Использование Babel с TypeScript

В этом разделе мы рассмотрим простой проект, использующий Babel с TypeScript; он размещен в директории babel-typescript. Мы продолжим работать с трехстрочным скриптом, представленным в листинге 6.11 и использующим JS-библиотеку Chalk. Единственное изменение будет в том, что теперь сообщение гласит Compiled with Babel (Скомпилировано с помощью Babel).

Листинг 6.20. index.ts: исходный код приложения babel-typescript

import chalk from 'chalk';const message: string = 'Compiled with Babel';console.log(chalk.black.bgGreenBright(message));


В сравнении с package.json из чистого JS-проекта (см. листинг 6.16) наш TS-проект добавляет dev-зависимость preset-typescript, отделяющую типы TS от кода, чтобы Babel мог воспринимать его как чистый JS. Мы также добавим опцию --extensions '.ts' в npm-скрипт, запускающий Babel, как в листинге 6.21. Теперь Babel будет считывать файлы .ts.

image


Как правило, предустановки включают набор плагинов, но preset-typescript содержит только один, babel/plugin-transform-typescript. Этот плагин внутренне использует babel/plugin-syntax-typescript, чтобы считывать TypeScript, и babel/helper-plugin-utils для основных утилит плагинов.

Несмотря на то что babel/plugin-transform-typescript преобразует TS-код в синтаксис ES.Next, это не компилятор TS. Как бы странно это ни звучало, Babel просто стирает TypeScript. Например, он преобразует const x: number = 0 в const x = 0. babel/plugin-transform-typescript намного быстрее, чем компилятор TS, так как не производит проверку типов для вводных файлов.

babel/plugin-transform-typescript имеет несколько небольших ограничений, перечисленных в документации на babeljs.io/docs/en/babel-plugin-transform-typescript (например, он не поддерживает const enum). Для лучшей поддержки TS рассмотрите использование плагинов babel/plugin-proposal-class-properties и babel/plugin-proposal-object-rest-spread.

Прочитав первые пять глав этой книги, вы наверняка уже начали ценить проверку типов и обнаружение ошибок во время компиляции, осуществляемое реальным компилятором TS. Неужели теперь мы действительно предлагаем вам использовать Babel, чтобы стереть связанный с TS синтаксис? Не совсем так. В процессе разработки вы можете продолжать использовать tsc (с помощью tsconfig.json) и IDE с полной поддержкой TypeScript. Тем не менее на стадии развертывания вы можете все же ввести Babel- и ENV-предустановки. (Скорее всего, вы уже оценили гибкость, предлагаемую ENV-предустановками, при конфигурировании целевых браузеров, не так ли?)

В вашем процессе сборки вы можете даже добавить npm-скрипт (в package.json), запускающий tsc:

check_types: tsc --noEmit src/index.ts

Теперь вы можете последовательно запустить check_types и Babel при наличии локально установленного tsc:

npm run check_types && npm run babel

Опция --noEmit гарантирует, что tsc не сгенерирует никаких файлов (вроде index.js), так как это будет сделано командой babel, выполняемой сразу после check_types. Если в index.js присутствуют ошибки компиляции, процесс сборки провалится и команда babel даже не запустится.

СОВЕТ Если вы используете && (двойной амперсанд) между двумя npm-скриптами, они будут выполняться последовательно. Для параллельного выполнения используйте & (одинарный амперсанд). Подробности вы можете найти во врезке Использование амперсандов в npm-скриптах в Windows в главе 10.

В этом проекте файл конфигурации .babelrc включает babel/preset-typescript.

Листинг 6.22. Файл .babelrc

{"presets": ["@babel/preset-env","@babel/preset-typescript"]}


В сравнении с проектом babel-javascript мы сделали следующие относящиеся к TypeScript изменения:

Добавили опцию --extensions '.ts' в команду, запускающую Babel.
Добавили в package.json связанные с TypeScript dev-зависимости.
Добавили babel/preset-typescript в файл конфигурации .babelrc.

Чтобы скомпилировать наш простой скрипт index.ts, запустите следующий npm-скрипт из package.json:

npm run babel

Вы найдете скомпилированную версию index.js в директории dist. Вы можете запустить скомпилированный код так же, как мы это делали в предыдущем разделе:

node dist/index.js

Теперь давайте добавим в наш рабочий поток Webpack, чтобы связать скрипт index.js и JS библиотеку Chalk.

Использование Babel с TypeScript и Webpack

Babel это компилятор, но не бандлер, который необходим для любого реального приложения. Вы вольны выбирать из ряда доступных бандлеров (вроде Webpack, Rollup и Browserify), но мы будем придерживаться Webpack. В этом разделе мы рассмотрим простой проект, использующий Babel с TypeScript и Webpack. Расположен он в директории webpack-babel-typescript.

В разделе 6.3.2 мы рассмотрели настройку TypeScript-Webpack, и далее мы продолжим использовать наш трехстрочный исходный код из того проекта.

Листинг 6.23. index.ts: исходный код приложения webpack-babel-typescript

import chalk from 'chalk';const message: string = 'Built with Babel bundled with Webpack';console.log(chalk.black.bgGreenBright(message));


В следующем листинге показан раздел devDependency из package.json.

image


Сравните зависимости Babel в листингах 6.24 и 6.21. В листинге 6.24 присутствуют три изменения:

Мы добавили babel-loader, являющийся Webpack-загрузчиком для Babel.
Мы удалили babel-cli, потому что не будем запускать Babel из командной строки.
Вместо babel-cli Webpack будет использовать babel-loader как часть процесса связывания.

Как вы помните из раздела 6.3, Webpack использует файл конфигурации webpack.config.js. Для настройки TS с помощью Webpack мы использовали ts-loader (см. листинг 6.14). В данном же случае мы хотим, чтобы файлы с расширением .ts обрабатывал babel-loader. Следующий листинг показывает раздел Babel из файла webpack.config.js.

image


Файл .babelrc будет выглядеть в точности так же, как и в предыдущем разделе (см. листинг 6.20).

После установки зависимостей командой npm install мы готовы к созданию связки через выполнение команды bundleup из package.json:

npm run bundleup

Эта команда создаст index.bundle.js в директории dist. Этот файл будет содержать скомпилированную (при помощи Babel) версию файла index.js, а также код из JS-библиотеки Chalk. Запустить эту связку вы можете как обычно:

node dist/index.bundle.js

Вывод, показанный на рис. 6.14, будет знакомым.

Для генерации JavaScript не нужно выбирать между Babel и tsc. Они могут успешно сосуществовать в одном проекте.

image


Противники TypeScript зачастую используют такой аргумент: Если я буду писать на чистом JS, мне не потребуется использовать компилятор. Я смогу запустить JS-программу сразу после ее написания. Это абсолютно ошибочно, так как если вы не хотите игнорировать новейший синтаксис JS, представленный, начиная с версии 2015, потребуется процесс, который сможет компилировать код, написанный в современном JS, в код, который смогут понять все браузеры. Скорее всего, вы так или иначе будете использовать в своем проекте компилятор, будь то Babel, TypeScript или какой-либо другой.

ОБ АВТОРАХ

Яков Файн является сооснователем двух IT-компаний: Farata Systems и SuranceBay. Он автор и соавтор таких книг, как Java Programming: 24-Hour Trainer, Angular Development with TypeScript1, Java Programming for Kids и др. Являясь чемпионом Java, провел множество классов и семинаров, посвященных веб- и Java-технологиям. Помимо этого, также был докладчиком на международных конференциях. Файн опубликовал более тысячи статей в своем блоге на yakovfain.com. В твиттере и инстаграме его можно найти по адресу @yfain. Он также публикует видео на YouTube.

Антон Моисеев является ведущим разработчиком в SuranceBay. Провел за разработкой корпоративных приложений более десяти лет, работая с Java и .NET. Имеет обширный опыт и фокусируется на развитии веб-технологий, реализующих лучшие методики слаженной работы фронтенда и бэкенда. Некоторое время проводил обучение по фреймворкам AngularJS и Angular. Периодически Антон делает посты в блоге antonmoissev.com. В твиттере вы можете найти его по адресу @antonmoiseev.

Более подробно с книгой можно ознакомиться на сайте издательства
Оглавление
Отрывок

Для Хаброжителей скидка 25% по купону TypeScript

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Подробнее..

Коты и лебеди на выпасе листаем книги для введения в профессию менеджера

22.03.2021 20:04:15 | Автор: admin

Привет! Это Кирилл, куратор потока Менеджмент. На Хабр часто выкладывают посты про интересную профессиональную литературу. В итоге наша площадка давно превратилась в одну из самых крупных библиотек с отзывами на книги про IT, но структурировать это никто пока не пытался. Чтобы это исправить, запускаем серию библиотечных подборок. Под катом первая из них с книгами, которые помогут новичку освоиться в роли руководителя, а маститому боссу освежить знания и стать ещё лучше.

1. Нассим Николас Талеб. Чёрный лебедь. Под знаком непредсказуемости
Теория чёрного лебедя рассматривает редкие, труднопрогнозируемые события, следом за которыми идут серьёзные последствия. Если вы имеете дело с разработкой ПО, книга поможет расширить кругозор и увидеть потенциальные опасности, которые раньше были незаметны.
Рассмотрев эту теорию можно понять актуальность потенциальной фундаментальной уязвимости в любой автоматизированной системе. Проблема достаточно старая, существует столько же сколько и язык C.
Krasnoglazik

2. Фредерик Брукс. Мифический человеко-месяц, или Как создаются программные системы
Классическая книга об управлении разработкой ПО. В 2018 году журнал PC World поставил её на первое место в своём топе IT-книг, которые стыдно признать, что не читал, а несколько сотен пользователей StackOverflow поместили её на восьмое место в списке самых важных книг по программированию из когда-либо написанных.
О книге Фредерика Брукса я услышал ещё учась в универе. Через пару лет я к ней вернулся. К тому моменту у меня уже было несколько лет работы в IT-индустрии. И когда я начал читать, то удивился, насколько книга, написанная в 1975 актуальна!
devmark

3. Дж. Х. Рейнвотер. Как пасти котов. Наставление для программистов, руководящих другими программистами
Книга о том, как совмещать лидерство с руководством, если управляешь IT-проектами. Будет полезна тем, кто оказался в менеджерской позиции после работы обычным программистом или уже давно руководит людьми, но хочет улучшить свои навыки.
Книга Как пасти котов подкупает своей предметностью: здесь описываются хорошо всем знакомые ситуации, разбираются по косточкам разные составляющие и условия работы команды, даже приводятся авторские технологические решения.
ProductivityInside

4. Джефф Сазерленд. Scrum. Революционный метод управления проектами
Одна из тех книг, которые точно нужно прочитать, если пытаетесь разобраться в этой методике. Как минимум потому, что её написал сам создатель Scrum.
Вся книга поделена на главы, которые являются основными акцентами фреймворка Scrum, а заодно и основными его преимуществами. Отдельно выделяется первая глава, где описываются времена, когда методология только зарождалась. Читается на одном дыхании, оторваться невозможно.
dmitriyabr

5. Джим Кэмп. Сначала скажите нет
Кэмп учит проводить переговоры с позиции силы. Задавать правильные вопросы, противостоять манипуляциям, не обращать внимания на вещи, которые не получится изменить и концентрироваться на своём поведении. Словом, это универсальная книга, которая будет полезна и при трудоустройстве на новую работу, и во время сложных переговоров с партнёрами.
Лучшая презентация та, которую ваш клиент не увидел. Кэмп утверждает, что презентация ставит вас в положение ниже противника. Если же вы действуете в рамках системы Кэмпа, если вы описали противнику его боль, то сделали тем самым самую лучшую презентацию. Если же вы не смогли описать боль, презентация не поможет и ничего не даст.
navff

6. Том ДеМарко. Deadline. Роман об управлении проектами
Автор этой книги глава консалтинговой компании Atlantic Systems Guild, которая выстраивает сложные бизнес-системы и помогает управлять рисками. Из 13 написанных книг эту он считает самой сильной. Написанная в форме художественного романа, она раскрывает закономерности и говорит о проблемах, которые могут поджидать зазевавшегося менеджера.
Deadline своеобразная пародия на приключения Джеймса Бонда. История про попаданца, рассказанная в мире информационных технологий планеты, похожей на нашу. После прочтения будет сложно взяться за любую другую книгу по управлению проектами неизбежно покажется скучной.
Arch_Stanton

7. Джейсон Фрайд и Дэвид Хайнемайер Хенссон. Rework: бизнес без предрассудков
Эту книгу написали основатели компании 37signals, которая сейчас известна как BaseCamp. При 14 постоянных сотрудниках продуктами этой организации регулярно пользуются более 3 млн человек по всему миру. В книге их опыт о том, как начать своё дело или просто довести проект до удачного финала. Даже если у вас нет времени и кажется, что чего-то не хватает.
Rework читается легко и быстро. Чем-то напоминает смесь Берись и делай Ричарда Брэнсона и Партизанского маркетинга Джея Конрада Левинсона: мотивирует и содержит много полезных и применимых на практике рекомендаций для IT-компаний.
VitaliyACTIVITI

8. Психбольница в руках пациентов. Алан Купер об интерфейсах
Первая и самая известная книга отца Visual Basic о том, как делать интерфейсы, которые будут понятны и удобны пользователям.
Все мы безумцы, живущие в технологическом сумасшедшем доме, и создали этот безумный мир мы сами. Своими руками сотворили этот кошмар: интерфейсы, которые нас раздражают и утомляют глаза, устройства, которые приводят к болям в спине и в запястьях.
ph_piter

9. Максим Батырев. 45 татуировок менеджера
Относительно короткое руководство о том, как вести дела, чтобы успешно их завершать и приходить к прогнозируемому результату.
Все татуировки очень напомнили мне и самому не чуждый армейский опыт. 45 татуировок менеджера написаны кровью управленца и его подчиненных, и уже хотя бы поэтому я рекомендую эту книгу всем, вне зависимости от занимаемой должности.
jasiejames
Подробнее..

Перевод Интервью авторов Искусства схемотехники сообществу element14 (05.06.2015)

07.05.2021 02:13:27 | Автор: admin

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

Сагар Джетани (Sagar Jethani) беседует от имени сообщества "element14" с соавторами книги, Полом Хоровицем (Paul Horowitz) и Уинфилдом Хиллом (Winfield Hill), о новом третьем издании.

Соавторы "Искусства схемотехники": Пол Хоровиц (слева) и Уинфилд Хилл (справа)Соавторы "Искусства схемотехники": Пол Хоровиц (слева) и Уинфилд Хилл (справа)

Сагар Джетани

Вопрос от одного из членов нашего сообщества, Дона Берки (Don Bertke).

Почему книга названа "Искусство схемотехники"? Разве схемотехника не строгий предмет? Ведь искусство подразумевает сочетание свободы и индивидуальности!

Пол Хоровиц

Это было идеей Уина, назвать книгу "Искусство схемотехники".

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

По нашему мнению, правильно спроектированная схема изящна.

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

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

Уинфилд Хилл

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

Пол Хоровиц

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

Если вы выделите время на изучение искусства схемотехники, то сможете получить ответы на терзающие вас вопросы.

Из этих соображений мы и определили название книги.

Сагар Джетани

В чем особенности третьего издания книги? Книга полностью переписана или частично дополнена?

Уинфилд Хилл

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

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

Пол Хоровиц

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

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

Большинство из них касаются периферии микроконтроллеров.Встроенные контроллеры стали настолько распространенными, что мы добавили классификацию дополнительных компонентов. Очень важных, поскольку они могут применяться в "обвязке" микроконтроллера.

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

Эти четыре главы, это действительно нечто!

Каждую из них можно рассматривать как небольшие, отдельные книги.

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

Уинфилд Хилл

Мы добавили 50 фотографий в книгу. Каждая из них подробно подписана и отражает действительную суть изображенных на них вещей. Мы ими гордимся, так как они стали результатом кропотливого труда.

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

Сагар Джетани

Один из членов нашего сообщества, Эрик Рэтклифф (Erik Ratcliff), интересуется, с какого издания ему начать изучение. До настоящего момента у него не было ни одного из изданий. Можете ли вы поподробнее рассказать о содержимом третьего издания, которого не найти во втором издании?

Уинфилд Хилл

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

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

Пол Хоровиц

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

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

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

Мы добавили в третье издание 90 осциллограмм, показывающих необычное поведение схем. Если сравнивать, то во втором издании их примерно пять.

Уинфилд Хилл

Если у вас имеются файлы осциллограмм, то вы можете их редактировать: накладывать друг на друга или размещать рядом. Вы можете создавать осциллограммы с одновременными показаниями нескольких каналов, в соответствии с возможностями осциллографа.

Пол Хоровиц

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

Сагар Джетани

Уин, вы упомянули, что некоторые темы второго издания исключили в третьем издании. Можете привести примеры?

Уинфилд Хилл

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

Те, кому интересны эти темы, всегда могут их найти во втором издании.

Пол Хоровиц

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

Сагар Джетани

В тексте книги часто встречаются ссылки на главы, помеченные "иксом". Члену нашего сообщества, Шабазу Юсуфу (Shabaz Yousaf), интересно, можете ли вы объяснить, что это за главы.

Пол Хоровиц

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

Эту концепцию мы воплотили в виде особых дополнительных глав, которые мы назвали "икс"-главами. На эти главы делаются ссылки из основных глав.

Всего мы выделили пять "икс"-глав.

Глава 1x, которая охватывает пассивные компоненты, такие как катушки индуктивности, конденсаторы и резисторы.

Глава 2x, которая охватывает биполярные транзисторы.

Глава 3x, которая охватывает полевые транзисторы.

Глава 4x, которая охватывает операционные усилители.

Глава 9x, которая охватывает источники питания и их применение.

Первоначально, мы хотели разместить эти главы следом за главами, из которых на них идут ссылки. Так получилось, что третье издание книги занимает свыше 1200 страниц даже без вкрапления "икс"-глав. Даже с учетом крупного формата страниц и до некоторой степени мелким шрифтом. Около года назад, нами было принято решение напечатать "икс"-главы отдельным изданием. Часть материала, который мы намеревались включить в "икс"-главы и который мы сочли очень важным, мывернули обратно в текст книги. Таким образом, некоторые главы в книге получились теперь более сложными.

Сагар Джетани

Когда Вы намереваетесь издать сборник "икс"-глав?

Пол Хоровиц

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

Сагар Джетани

Следующий вопрос поступил от члена нашего сообщества, Джона Вилтраута (John Wiltrout).

У второго издания есть известное приложение в виде "Студенческого руководства". Планируете ли Вы выпустить что-либо подобное для третьего издания?

Пол Хоровиц

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

Теперь, у этой книги новое название, "Постижение искусства схемотехники: вспомогательный лабораторный курс".

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

Книга включает лабораторные и классные занятия, а также весь материал, содержащийся в применяемых ныне руководствах для студентов. Вдобавок, в книге содержится еще кое-какой дополнительный материал. Данная книга снимает некоторую нагрузку с основной книги. Ее автором является Том Хейс (Tom Hayes), который был в свое время автором "Студенческого руководства" ко второму изданию.

Сагар Джетани

По сравнению со вторым изданием, мы наблюдаем значительные авторские изменения. Книга "Постижение искусства схемотехники: вспомогательный лабораторный курс" ("Студенческое руководство") ориентирована на практиков, а не на тех, кто привык к традиционным текстам.

Пол Хоровиц

Да, я так считаю.

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

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

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

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

"Студенческое руководство" лишь призвано помочь начать практическую деятельность.

Уинфилд Хилл

Да, весь материал этой книги затрагивает связь теории и практики. Это присовокупляет практическую сторону к книге "Искусство схемотехники".

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

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

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

Сагар Джетани

Один из авторов статей в нашем сообществе, Элиша Вайт (Elecia White), интересуется:

"При характерной внушительности вашей книги (90 осциллограмм, 80 таблиц, свыше 1600 дискретных компонентов), имеются ли у Вас любимые схемы? Какие из них Вы постоянно приводите в качестве примеров?"

Пол Хоровиц

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

Это такая потрясающая картинка!

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

У меня было много "головной боли" при создании рисунка 8.58 в программе Adobe Illustrator. Он озаглавлен "Действующее значение плотности входного шума". И чтобы быть созданным, он потребовал от меня всех моих знаний о программе Adobe Illustrator.

Это наш любимый график.

Сагар Джетани

Есть ли у Вас любимые таблицы?

Пол Хоровиц (улыбаясь)

Нашей любимой является таблица 5.5, которая включает "великолепную семерку" высокоточных операционных усилителей.

На самом деле их там значительно больше!

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

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

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

Сагар Джетани

Вы предоставили любимый график и любимую таблицу. Есть ли у Вас любимая схема?

Уинфилд Хилл

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

Пол Хоровиц

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

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

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

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

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

Мы отталкивались от дискретной цифровой логики в направлении FPGA, CPLD и в итоге перешли к микроконтроллерам.

Мы истратили 12 страниц на то, чтобы показать вам полдюжины различных способов получения псевдослучайной последовательности. Отличным примером является рисунок 8.93 на странице 559, на котором показано, как использовать генератор шума с псевдослучайной битовой последовательностью и аналоговую фильтрацию, чтобы получать различные цвета шума: "белый", "розовый", "красный". Сюда еще стоит отнести графики, качественно характеризующие данную схему.

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

Уинфилд Хилл

К моим любимым относится схема на рисунке 9.13, со страницы 606.

Там показана схема внутреннего устройства линейного стабилизатора напряжения 317-й серии. Я всегда считал ее особенно элегантной и милой.

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

Не меньше, я люблю схемы функциональных блоков цифровых мультиметров под торговыми марками "HP", "Agilent" и "Keysight", которые мы разместили во многих частях книги. Например, рисунок 8.49 со страницы 513, рисунок 13.15 со страницы 896, рисунок 13.47 со страницы 919.

Сагар Джетани

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

Пол Хоровиц

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

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

Сейчас мы возвращаемся к эпохе, когда люди снова начинают заниматься индивидуальным производством. И нам это приятно видеть. Все это благодаря наличию дешевых микроконтроллеров и готовых платформ для проектирования, таких как "Arduino", "Raspberry Pi" и им подобных.

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

Сейчас это направление бурно развивается.

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

По поводу будущего, я бы хотел привести цитату Нильса Бора:

"Предсказать что-либо очень сложно, особенно если это касается будущего."

Уинфилд Хилл

Предыдущее издание книги было опубликовано в 1989 году.

Это намек специально для тех, кто хочет знать, как что-либо меняется за 25 лет.

Пол Хоровиц

Я не думаю, что мы в свое время предвидели появление платформы "Arduino", сети Internet, журнала "Make" и многого другого.

Еще в 60-х годах прошлого века япрочил туннельным диодам большое будущее. Но их свергли транзисторы, которые были быстрее, проще и дешевле.

Где теперь туннельные диоды? Они исчезли!

По-моему, те, кто берется за предсказание глупцы!

Уинфилд Хилл

Мы затрудняемся ответить на этот вопрос!

Сагар Джетани

Вы неоднократно упоминали огромное значение микроконтроллеров.

Сообщество "element14" популяризует широкое разнообразие микроконтроллеров. Шабаз и я недавно обсуждали, повлияло ли на процесс проектирования появление дешевых, полностью фунциональных плат на их основе.

Есть ли здесь подводные камни?

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

Возможно это немного чересчур, но приемлемо.

Пол Хоровиц

Хотелось бы предостеречь!

Вы конечно можете собрать схему из готовых блоков на микроконтроллерах, как конструктор "LEGO".

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

Позвольте в качестве примера привести ситуацию, сложившуюся у нас в Гарвардском университете.

У нас имеются студенты, с конструкторскими заданиями построить то-то и то-то.

Они посещают популярные технические сайты, набирают готовые модули и собирают на их основе схемы по принципу "этот выход похоже идет на этот вход" в надежде, что схема заработает. Но она в итоге не работает!

Проблема состоит в том, что они не понимают таких вещей, как: различные уровни напряжения, различие в импедансах и шунтирование.

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

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

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

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

Уинфилд Хилл

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

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

Подавляющее большинство цифровых устройств не поддерживают работу с уровнями напряжения 3,3 В.

Так каким же образом вы собираетесь впоследствии подключить их к выводам процессора?

Именно об этом мы подробно рассказываем в двенадцатой главе. А уже в тринадцатой главе мы обсуждаем подключения процессоров к аналоговым устройствам.

Если в качестве примера мы возьмем небольшую плату от "TI" или любого другого производителя, то увидим, что на ней обязательно имеются штырьки для подключения другой внешней схемы.

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

Вот этому мы и пытаемся научить.

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

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

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

Там целая куча всевозможных устройств, которые вы захотели бы подключить!

Не малая часть повествования посвящена обучению читателей применять это многообразие устройств в своих проектах.

Сагар Джетани

Что делать инженерам, если они хотят держать свои навыки в тонусе?

Уинфилд Хилл

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

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

Пол Хоровиц

По этому поводу я общался с опытным схемотехником, Джимом Макартуром (Jim McArthur). Иногда в нашей книге мы приводим его цитаты.

И вот одна из них:

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

Вы всегда будете в курсе дела, если у вас имеется такое окружение.

Сагар Джетани

Я заметил, что Вы упоминаете в приложениях к третьему изданию книги наш магазин, "Newark Electronics".

Уинфилд Хилл

Я постоянный покупатель "Newark Electronics".

Пол Хоровиц

В приложении K, озаглавленном "Где мне купить электронные "вкусняшки"?", мы отдельно упомянули "Newark Electronics" за хороший ассортимент. Еще отмечу, что в "Newark Electronics" до сих пор есть печатный каталог!

К сожалению, в "Digi-Key" отказались от его выпуска пару лет назад.

Сагар Джетани

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

Пол Хоровиц

Конечно, я уже не верю в мемристоры.

Хотелось бы увидеть действительно энергонезависимую технологию памяти.

Я не думаю, что это будет флэш-память с плавающим затвором. Я считаю, что это будет кое-что гораздо лучше. Но я не уверен, что это будет одна из тех четырех технологий, которые претендуют на это сейчас. Возможно, это будет нечто совершенно иное. В нашей книге мы перечислили плюсы и минусы технологий магнитной памяти (MRAM), сегнетоэлектрической памяти (FeRAM), памяти на основе фазового перехода (PRAM) и ряда других.

Давайте через тридцать лет посмотрим, что из этого выйдет!

Сагар Джетани

Пол, Вы один из основателей программы по поиску внеземных цивилизации (SETI). Вы работали с ныне покойным Карлом Саганом (Carl Sagan). Расскажите о Вашей работе по данному направлению. Каковы задачи программы поиска внеземных цивилизаций сейчас?

Пол Хоровиц

Наша программа по поиску внеземных цивилизаций жива и здорова.

Это огромное внешнее пространство с частотами и направлениями, а также другими нюансами.

Мы не знаем, что посылают внеземные цивилизации, однако мы уверены, что они существуют.

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

Конечно, в Галактике Млечного Пути планет больше, чем звезд. А обитаемых планет примерно столько же, сколько и звезд. Скажем, примерно 100 миллиардов.

Все отлично складывается для возможности существования жизни в других местах.На самом деле все неплохо складывается даже для возможности существования примитивной жизни в других уголках нашей Солнечной системы.

Сагар Джетани

Какой самый лучший способ общения с представителями другой разумной жизни во Вселенной?

Пол Хоровиц

Самой передовой идеей является наблюдение оптических импульсов. Это основа наших исследований последних десяти лет.

Хотя радиоастрономия не потеряла своей актуальности. В настоящее время в радиоастрономии мало что происходит.

Проект радиотелескопа Аллена (Allen telescope array), на который возлагались большие надежды, был закрыт. У радиотелескопа в Аресибо (штаб-квартира программы SETI) слишком узкий луч для наблюдения за небом и ограниченный диапазон частот.

Контакт может произойти в любой момент.

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

Уинфилд Хилл (шутит улыбаясь)

Пол и его студенты спроектировали телескоп в Гарвардском университете, в штате Массачусетс. Он автоматически запускается в ясные ночи и сканирует небо в поисках сигналов от внеземной жизни. Пол не успел указать этого на своей страничке в сети, поскольку был сильно занят написанием третьего издания книги "Искусство схемотехники". Телескоп как раз заработает этой ночью. Не правда ли?

Пол Хоровиц (улыбается)

Я не против, но только сегодня немного облачно. Вот если бы погода была такой, как у Вас в Калифорнии, Сагар!

Позвольте мне закрыть эту тему маленькой цитатой! Она родилась во время экспериментов с радиосистемой и работ по модернизации телескопа, о котором только что упомянул Уин. Я тогда показал схему модернизации одному своему коллеге, Биллу Прессу (Bill Press), автору книги "Вычислительные рецепты" ("Numerical Recipes").

Билл посмотрел на проект, и сказал:

"Хоровиц, ты знаешь, что шанс прославиться у тебя один на миллион?".

Так и здесь.

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

Надежда вечный спутник искателя разумной жизни во Вселенной.

Уинфилд Хилл

Варианта всего два: либо это будет величайшее открытие в истории человечества, либо не будет ничего.

Пол Хоровиц (улыбается)

Да, либо не будет ничего.

Сагар Джетани

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

Уинфилд Хилл

Большое спасибо! Нам понравилось беседовать с Вами!

Пол Хоровиц

Если этот ваш член сообщества прав, то делает ли это нас святыми или кем-то наподобие?

Сагар Джетани (улыбаясь)

Она не уточнила!

Заключительная ремарка переводчика

Первоначальная версия данной статьи была опубликована на сайте "Паяльник".

Если у Вас имеются какие-либо обоснованные замечания, предложения, пожелания или Вы просто хотите поделиться своими впечатлениями, буду рад выслушать.

У каждого автора имеется свой почерк. Поэтому я решил внести в свои публикации маленькую невинную традицию. Уж не обессудьте!

В конце каждой публикации будет объявляться муза.

Таким образом, музой этой публикации объявляется Наташа Васичева, за интересные методы "беспалевной" видеосъемки на смартфон. Как бы странно это не звучало для непосвященных и что бы ни значило.

Надеюсь статья Вам показалась интересной.

До новых встреч!

Подробнее..

Перевод Dan Luu Как пишутся (некоторые) хорошие корпоративные инженерные блоги

14.06.2021 02:23:55 | Автор: admin
image


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

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

Что касается первого, сотрудники компании будут выполнять более интересную инженерную работу, рассказывать больше забавных историй и обладать более глубокими знаниями, чем любой человек, ведущий личный блог. Во втором случае мой блог помогает мне в поиске работы и помогает компаниям нанимать меня. Но мне нужна только одна работа, так что большее влияние блога в том, что в лучшем случае он дает мне немного лучшую работу, тогда как все, кроме одной технологической компании, в которой я работал, отчаянно пытаются нанять кого-то и все время теряют кандидатов в пользу других компаний. Более того, я на самом деле не конкурирую с другими кандидатами на собеседовании (даже если мы собеседуемся на одну и ту же работу, если компании нравится больше, чем один кандидат, она обычно просто создает больше рабочих мест). Важнейший момент в этом блоге в отношении поиска работы заключается в том, сможет ли процесс отбора принять значительную обратную связь, не связанную с собеседованием, или если я провалю собеседование, потому что они проводят обычное собеседование, и предельная ценность дополнительной публикации в блоге, вероятно очень низка по отношению к этому. С другой стороны, при найме на работу компании конкурируют относительно напрямую, так что быть более привлекательными по сравнению с другой компанией крайне важно для них. Повторение Playbook, который Cloudflare или Segment использовали для своих инженерных брэндов, будет значительным преимуществом при найме на работу. Playbook не является секретом: эти компании транслируют свою продукцию по всему миру и, как правило, с удовольствием рассказывают о своих процессах ведения блога.

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

Чтобы попытаться понять, что общего у компаний с хорошим корпоративным инженерным блогом, я опросил людей из трех разных компаний, у которых интересные корпоративные инженерные блоги (Cloudflare, Heap и Segment), а также людей из трех разных компаний, у которых посредственные корпоративные инженерные блоги (которые я не буду называть).

На высоком уровне в интересных инженерных блогах происходили процессы, которые обладали следующими свойствами:

  • Простой процесс одобрения, не требуется много одобрений
  • Не требуется никаких одобрений, не относящихся к инженерным, или совсем не требуется
  • Неявный или явно быстрый SLO для одобрений
  • Процесс одобрения/редактирования в основном делает пост более привлекательными для инженеров
  • Прямая поддержка высокого уровня (сооснователь, C-level или VP-level) для облегчения процесса ведения блога


В менее привлекательных технических блогах происходили процессы, которые обладали следующими свойствами:
  • Медленный процесс одобрения
  • Требуется много одобрений
  • Необходимы значительные нетехнические одобрения:
    • Неинженерные одобрения предполагают, что изменения, по мнению авторов, разочаровывают
    • Туда-сюда может продолжаться месяцами
  • Процесс одобрения/редактирования в основном снижает риски для публикаций, удаляет ссылки на конкретную информацию, делает посты более расплывчатыми и менее интересными для инженеров.
  • Фактически нет поддержки высокого уровня для ведения блога
    • Руководство может согласиться с тем, что ведение блога это хорошо в абстрактном смысле, но это недостаточно высокий приоритет, чтобы предпринимать конкретные действия.
    • Очень сложно реформировать процесс ведения блога; предыдущие попытки потерпели неудачу
    • Изменение процесса для сокращения накладных расходов требует, чтобы все заинтересованные стороны подписались (14 в одном случае)
      • Любая отдельная заинтересованная сторона может заблокировать пост
      • Ни одна заинтересованная сторона не может одобрить пост
    • Заинтересованные стороны опасаются одобрять все, что снижает накладные расходы.
      • Одобрение включает принятие на себя предполагаемого риска (что, если случится что-то плохое) без видимой выгоды для них

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

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

Вот описанные мне процессы для трех компаний, с которыми я беседовал (представленные в порядке sha512sum, который случайно упорядочен путем увеличения размера компании с пары сотен сотрудников до почти тысячи сотрудников):

Heap


  • У кого-то есть идея написать пост
  • Писатель (инженер) находится в паре с приятелем, который редактирует, а затем одобряет пост
    • Приятель инженер, имеющий опыт написания разумных текстов
    • Это может занять несколько раундов, может измениться направленность поста
  • Технический директор читает и одобряет
    • Обычно давая только незначительную обратную связь
    • Может вносить предложения вроде дизайнер может улучшить этот график.
  • Публикация поста


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

Segment


  • У кого-то есть идея написать пост
    • Часто исходит из: внутренней документации, внешнего обсуждения, одобренного проекта, инструментов с открытым исходным кодом (созданных Segment).
  • Автор (инженер) пишет черновик
    • Может быть, с ними будет работать старший инженер, чтобы написать черновик
  • До недавнего времени процесс обратной связи никому не принадлежал
    • Кальвин Френч-Оуэн (сооснователь) и Рик (технический менеджер) обычно дают больше всего обратной связи<
    • Возможно также получить обратную связь от менеджера и руководства
    • Обычно 3-й черновик считается завершенным
    • Теперь у вас есть штатный редактор, которому принадлежит ответственность за редактирование постов
  • Также обсуждение с инженерной командой, чтобы получить обратную связь от 15-20 человек.
  • PR и юристы просто посмотрят, простой процесс одобрения


Некоторые внесенные изменения включают

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


Хотя есть официальное одобрение и одобрение со стороны PR, Кэлвин отметил: В целом мы стараемся сделать процесс одобрения достаточно легким. Я считаю, что более серьезной проблемой ведения блогов является отсутствие постов или расплывчатый высокоуровневый контент, который не интересен, и не раскрывает слишком много.

Cloudflare


  • У кого-то есть идея написать пост
    • Внутреннее ведение блога является частью культуры, некоторые посты публикуются из внутреннего блога
  • Джон Грэм-Камминг (технический директор) читает каждый пост, другие будут читать и комментировать
    • Джон одобряет посты
  • Мэтью Принс (генеральный директор) также в целом поддерживает ведение блога.
  • Очень быстрый юридический процесс одобрения, SLO в течение часа
    • Этот процесс настолько легок, что один человек на самом деле не думал об этом как об одобрении, а другой вообще не упоминал это (третий действительно упомянул этот шаг)
    • Комментарии вообще не задействованы


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

Мне показалось интересным то, что Марек собеседовался Cloudflare из-за их блога (его внимание привлекла эта запись в блоге 2013 года на их серверах 4-го поколения), и теперь он является для них ключевым инженером, а также одним из основных источников привлекательных постов блога Cloudflare. На данный момент блог Cloudflare породил по крайней мере еще несколько поколений людей, которые проходили собеседования, потому что они видели пост в блоге и теперь пишут убедительные посты для блога.

Общие комментарии


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

Чтобы блог был скучным, корпорация должна активно мешать инженерам размещать там интересный контент. К сожалению, похоже, что естественное состояние крупных корпораций склонно к избеганию риска и запрету людям писать на всякий случай, если это вызывает юридические, PR или другие проблемы. Individual Cotributors могут придерживаться мнения, что нелепо запрещать инженерам писать технические посты с низким уровнем риска, в то время как руководители высшего звена и вице-президенты регулярно делают публичные комментарии, которые превращаются в PR-катастрофу, но IC в крупных компаниях не имеют полномочий или не чувствуют, что у них есть полномочия что-то делать только потому, что это имеет смысл. И ни одна из четырнадцати заинтересованных сторон, которой пришлось бы подписаться на одобрение оптимизированного процесса, не позаботилась бы об оптимизации процесса, поскольку это было бы хорошо для компании таким образом, чтобы на самом деле не смогло бы не повлиять на них, не тогда, когда это, казалось бы, означало принятие на себя ответственности за риск связанный с оптимизированным процессом, пусть даже с небольшим. Руководитель или старший вице-президент, готовый пойти на риск, могут взять на себя ответственность за последствия, и, если они заинтересованы в найме инженеров или в моральном духе, они могут увидеть причину для этого.

Один комментарий, который я часто слышал от людей из более бюрократических компаний, это что-то вроде каждая компания нашего размера такая же, но это неправда. Cloudflare, компания с оборотом в 6 миллиардов долларов, в которой работает 1 тысяча сотрудников, находится в том же классе, что и многие другие компании с гораздо более обременительным процессом ведения блогов. Ситуация в корпоративном блоге кажется похожей на ситуацию с реальным откликом на собеседование. interviewing.io утверждает, что в этом есть существенные положительные и очень незначительные отрицательные стороны. Некоторые компании действительно дают реальную обратную связь, а те, которые, как правило, считают, что это дает им легкое преимущество при найме с небольшими недостатками, но подавляющее большинство компаний этого не делают, и люди в этих компаниях будут утверждать, что дать обратную связь невозможно, так как на вас подадут в суд, или компания будет аннулирована, хотя обычно этого не происходит с компаниями, которые дают обратную связь, и есть даже целые отрасли, в которых принято давать обратную связь на собеседовании. Легко понять, что определенный риск существует, и очень немногие люди имеют право отвергать расплывчатые сообщения о риске, когда он исходит от нескольких организаций.

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

Приложение: примеры классных публикаций в блогах


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

Cloudflare




Segment




Heap




Следует отметить, что все эти блоги имеют разные стили. Лично я предпочитаю стиль блога Cloudflare, в котором более высокая доля глубоких технических сообщений, но разные люди предпочтут разные стили. Есть много стилей, которые могут cработать.
Подробнее..

Книга PowerShell для сисадминов

27.05.2021 16:21:56 | Автор: admin
image Привет, Хаброжители! PowerShell это одновременно язык сценариев и командная оболочка, которая позволяет управлять системой и автоматизировать практически любую задачу. В книге PowerShell для сисадминов обладатель Microsoft MVP Адам Бертрам aka the Automator покажет, как использовать PowerShell так, чтобы у читателя наконец-то появилось время на игрушки, йогу и котиков. Вы научитесь: -Комбинировать команды, управлять потоком выполнения, обрабатывать ошибки, писать сценарии, запускать их удаленно и тестировать их с помощью фреймворка тестирования Pester. -Анализировать структурированные данные, такие как XML и JSON, работать с популярными сервисами (например Active Directory, Azure и Amazon Web Services), создавать системы мониторинга серверов. -Создавать и проектировать модули PowerShell. -Использовать PowerShell для удобной, полностью автоматизированной установки Windows. -Создавать лес Active Directory, имея лишь узел Hyper-V и несколько ISO-файлов. -Создавать бесчисленные веб- и SQL-серверы с помощью всего нескольких строк кода! Реальные примеры помогают преодолеть разрыв между теорией и работой в настоящей системе, а легкий авторский юмор упрощает чтение. Перестаньте полагаться на дорогое ПО и невнятные советы из сети!

Для кого эта книга
Эта книга предназначена для ИТ-специалистов и системных администраторов, которым надоело постоянно использовать один и тот же интерфейс и выполнять одну и ту же задачу в пятисотый раз за этот год. Также она будет полезна для инженеров DevOps, которые испытывают затруднения с автоматизацией новых серверных сред, выполнением автоматических тестов или автоматизацией конвейера непрерывной интеграции / непрерывной доставки (CI/CD).

Не получится назвать отрасль, для которой PowerShell был бы полезен больше всего. Традиционная должность пользователя PowerShell в магазине Windows системный администратор Microsoft, однако PowerShell хорошо вписывается в набор инструментов любого сотрудника в сфере ИТ. Если вы работаете в ИТ, но не считаете себя разработчиком, эта книга для вас.

Поток управления


Немного повторим. В главе 3 мы узнали, как можно комбинировать команды с помощью конвейера и внешних сценариев. В главе 2 рассмотрели переменные и как их использовать для хранения значений. Одним из основных преимуществ работы с переменными является возможность писать с их помощью код, который работает не со значением, а со смыслом. Вместо того чтобы работать, например, с числом 3, вы будете работать с общим понятием $serverCount. За счет этого вы можете писать код, который работает одинаково, будь у вас один, два или тысяча серверов. Совместите эту способность с возможностью сохранять код в сценариях, которые можно запускать на разных компьютерах, и вы сможете начать решать задачи гораздо большего масштаба.

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

Немного о потоке управления

Мы напишем сценарий, который считывает содержимое файла, хранящегося на нескольких удаленных компьютерах. Чтобы продолжить работу, загрузите файл под названием App_configuration.txt из прилагаемых к книге материалов по ссылке github.com/adbertram/PowerShellForSysadmins/ и поместите его в корень диска C:\ на нескольких удаленных компьютерах. Если у вас нет удаленных компьютеров, пока просто продолжайте читать. В этом примере я буду использовать серверы с именами SRV1, SRV2, SRV3, SRV4 и SRV5.

Чтобы получить доступ к содержимому файла, воспользуемся командой Get-Content и укажем путь к файлу в значении аргумента параметра Path, как показано ниже:

Get-Content -Path "\\servername\c$\App_configuration.txt"

Для начала сохраним все имена наших серверов в массиве и запустим эту команду для каждого сервера. Откройте новый файл .ps1 и введите в него код из листинга 4.1.

Листинг 4.1. Извлечение содержимого файла с нескольких серверов

$servers = @('SRV1','SRV2','SRV3','SRV4','SRV5')Get-Content -Path "\\$($servers[0])\c$\App_configuration.txt"Get-Content -Path "\\$($servers[1])\c$\App_configuration.txt"Get-Content -Path "\\$($servers[2])\c$\App_configuration.txt"Get-Content -Path "\\$($servers[3])\c$\App_configuration.txt"Get-Content -Path "\\$($servers[4])\c$\App_configuration.txt"


Теоретически, этот код должен работать без проблем. Но в этом примере предполагается, что у вас что-то идет не так. Что делать, если сервер SRV2 не работает? А если кто-то забыл положить App_configuration.txt на SRV4? А может, кто-то изменил путь к файлу? Вы можете написать отдельный сценарий для каждого сервера, но это решение не будет масштабироваться, особенно когда вы начнете добавлять все больше и больше серверов. Вам нужен код, который будет работать в зависимости от ситуации.

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

Мы начнем с рассмотрения самого простого типа потока управления условного оператора.

Использование условных операторов

В главе 2 мы узнали, что существуют логические значения: истина и ложь. Логические значения позволяют создавать условные операторы, которые ставят задачу PowerShell выполнить определенный блок кода в зависимости от того, имеет ли выражение (называемое условием) значение True или False. Условие это вопрос с вариантами ответов да/нет. У вас больше пяти серверов? Работает ли сервер 3? Существует ли путь к файлу? Чтобы начать использовать условные операторы, давайте посмотрим, как преобразовать такие вопросы в выражения.

Построение выражений с помощью операторов

Логические выражения можно писать с помощью операторов сравнения, которые сравнивают значения. Чтобы использовать оператор сравнения, нужно поместить его между двумя значениями, например:

PS> 1 eq 1
True

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

-eq сравнивает два значения и возвращает True, если они равны.

-ne сравнивает два значения и возвращает True, если они не равны.

-gt сравнивает два значения и возвращает True, если первое больше второго.

-ge сравнивает два значения и возвращает True, если первое больше или равно второму.

-lt сравнивает два значения и возвращает True, если первое меньше второго.

-le сравнивает два значения и возвращает True, если первое меньше или равно второму.

-contains возвращает True, если второе значение является частью первого. Например, этот оператор позволяет определить, находится ли значение внутри массива.

В PowerShell есть и более продвинутые операторы сравнения. Здесь мы не будем на них останавливаться, но я рекомендую вам почитать о них в документации Microsoft по ссылке docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators или в разделе справки PowerShell (см. главу 1).

Вы можете использовать приведенные выше операторы для сравнения переменных и значений. Но выражение не обязательно должно быть сравнением. Иногда команды PowerShell можно использовать как условия. В предыдущем примере мы хотели узнать доступность сервера. С помощью командлета Test-Connection можно проверить наличие связи с сервером. Обычно в выходных данных командлета Test-Connection содержится много разной информации, но с помощью параметра Quiet вы можете заставить команду вернуть True или False, а с помощью параметра Count можно ограничить тест одной попыткой.

PS> Test-Connection -ComputerName offlineserver -Quiet -Count 1
False

PS> Test-Connection -ComputerName onlineserver -Quiet -Count 1
True

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

PS> -not (Test-Connection -ComputerName offlineserver -Quiet -Count 1)
True

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

Оператор if

Оператор if работает просто: если выражение X истинно, то сделайте Y. Вот и все!

Чтобы использовать оператор в выражении, пишется ключевое слово if, за которым следуют круглые скобки, содержащие условие. После выражения следует блок кода, выделенный фигурными скобками. PowerShell выполнит этот блок кода только в том случае, если это выражение будет иметь значение True. Если выражение if имеет значение False либо вообще ничего не возвращает, блок кода не будет выполнен. Синтаксис оператора if/then показан в листинге 4.2.

Листинг 4.2. Синтаксис оператора if

if (условие) {   # выполняемый код, если условие истинно}


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

Теперь давайте еще раз посмотрим на код, показанный в листинге 4.1. Я расскажу вам о том, как использовать оператор if, чтобы не пытаться достучаться до неработающего сервера. В предыдущем разделе мы уже видели, что команду Test-Connection можно использовать в качестве выражения, которое возвращает True или False, поэтому сейчас давайте упакуем Test-Connection в оператор if, а затем воспользуемся командой Get-Content, чтобы не пытаться обращаться к неработающему серверу. Сейчас мы поменяем код только для первого сервера, как показано в листинге 4.3.

Листинг 4.3. Использование оператора if для выборочного обращения

$servers = @('SRV1','SRV2','SRV3','SRV4','SRV5')if (Test-Connection -ComputerName $servers[0] -Quiet -Count 1) {   Get-Content -Path "\\$($servers[0])\c$\App_configuration.txt"}Get-Content -Path "\\$($servers[1])\c$\App_configuration.txt"--пропуск--


Поскольку у вас есть Get-Content в операторе if, вы не столкнетесь с какими-либо ошибками, если попытаетесь получить доступ к неработающему серверу; если тест завершится неудачно, ваш сценарий будет знать, что не следует пытаться считать файл. Код попытается получить доступ к серверу, только если он уже знает, что тот включен. Но обратите внимание, что этот код срабатывает только в том случае, если условие истинно. Достаточно часто вам нужно будет задать одно поведение сценария для истинного условия и другое для ложного. В следующем разделе вы увидите, как определить поведение для ложного условия с помощью оператора else.

Оператор else

Чтобы предоставить вашему оператору if альтернативу, можно использовать ключевое слово else после закрывающей скобки блока if, за которым будет следовать еще одна пара фигурных скобок, содержащая блок кода. Как показано в листинге 4.4, мы будем использовать оператор else, чтобы вернуть в консоль ошибку, если первый сервер не отвечает.

Листинг 4.4. Использование оператора else для запуска кода, если условие
не истинно

if (Test-Connection -ComputerName $servers[0] -Quiet -Count 1) {   Get-Content -Path "\\$($servers[0])\c$\App_configuration.txt"} else {   Write-Error -Message "The server $($servers[0]) is not responding!"}


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

Оператор elseif

Оператор else охватывает противоположную ситуацию: если if не срабатывает, значит, выполните это в любом случае. Такой подход работает для двоичных условий, то есть когда сервер либо работает, либо нет. Но иногда приходится иметь дело с большим числом вариантов. Например, предположим, что у вас есть сервер, на котором нет нужного вам файла, и вы сохранили имя этого сервера в переменной $problemServer (добавьте в свой сценарий эту строку кода!). Это означает, что вам нужна дополнительная проверка, позволяющая узнать, является ли сервер, который вы опрашиваете в данный момент, проблемным. Это можно реализовать с помощью вложенных операторов if, как показано в коде ниже:

if (Test-Connection -ComputerName $servers[0] -Quiet -Count 1) {   if ($servers[0] eq $problemServer) {      Write-Error -Message "The server $servers[0] does not have the right         file!"   } else {      Get-Content -Path "\\$servers[0]\c$\App_configuration.txt"   }} else {   Write-Error -Message "The server $servers[0] is not responding!"}--пропуск--


Но есть и более аккуратный способ реализовать ту же логику с помощью оператора elseif, который позволяет вам проверить дополнительное условие, перед тем как вернуться к коду в блоке else. Синтаксис блока elseif идентичен синтаксису блока if. Итак, чтобы проверить проблемный сервер с помощью оператора elseif, запустите код из листинга 4.5.

Листинг 4.5. Использование блока elseif

if (-not (Test-Connection -ComputerName $servers[0] -Quiet -Count 1)) {    Write-Error -Message "The server $servers[0] is not responding!"} elseif ($servers[0] eq $problemServer)    Write-Error -Message "The server $servers[0] does not have the right file!"} else {   Get-Content -Path "\\$servers[0]\c$\App_configuration.txt" }--пропуск--


Обратите внимание, что мы не просто добавили оператор elseif, а заодно изменили логику кода. Теперь мы можем проверить, не находится ли сервер в автономном режиме, с помощью оператора not. Затем, как только мы определили сетевой статус сервера, мы проверяем, является ли он проблемным. Если это не так, мы используем оператор else для запуска поведения по умолчанию извлечения файла. Как видите, существует несколько способов структурировать код описанным образом. Важно то, что код работает и что он читабелен для человека со стороны, будь то ваш коллега, видящий его впервые, или вы сами спустя некоторое время после написания.

Вы можете объединить в цепочку сколько угодно операторов elseif, что позволяет учитывать самые разные сочетания обстоятельств. Однако операторы elseif являются взаимоисключающими: когда один из elseif принимает значение True, PowerShell запускает только его код и не проверяет остальные случаи. В листинге 4.5 это не вызвало никаких проблем, так как вам нужно было проверить сервер на предмет проблемности только после проверки работоспособности, но в дальнейшем я советую вам держать в уме эту особенность.

Операторы if, else и elseif отлично подходят для реализации ответа кода на простые вопросы типа да/нет. В следующем разделе вы узнаете, как работать с более сложной логикой.

Оператор switch

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

Обратите внимание, что теперь мы будем работать с другим типом условия. Если раньше нам нужны были ответы на вопросы типа да/нет, то теперь мы хотим получить конкретное значение одной вещи. Это сервер SRV1? SRV2? И так далее. Если бы вы работали только с одним или двумя конкретными значениями, оператор if подошел бы, но в данном случае оператор switch сработает гораздо лучше.

Оператор switch позволяет выполнять различные фрагменты кода в зависимости от некоторого значения. Он состоит из ключевого слова switch, за которым следует выражение в скобках. Внутри блока switch находится серия операторов, построенных по следующему принципу: сначала указывается значение, за ним следует набор фигурных скобок, содержащих блок кода, и наконец ставится блок default, как указано в листинге 4.6.

Листинг 4.6. Шаблон для оператора switch

switch (выражение) {   значениевыражения {      # Код   }   значениевыражения {   }   default {     # Код, который выполняется при отсутствии совпадений   }}


Оператор switch может содержать практически неограниченное количество значений. Если выражение оценивается как значение, выполняется соответствующий код внутри блока. Важно то, что, в отличие от elseif, после выполнения одного блока кода PowerShell продолжит проверять и остальные условия, если не указано иное. Если ни одно из значений не подойдет, PowerShell выполнит код, указанный в блоке default. Чтобы прекратить перебор условий в операторе switch, используйте ключевое слово break в конце блока кода, как показано в листинге 4.7.

Листинг 4.7. Использование ключевого слова break в операторе switch

switch (выражение) {   значениевыражения {      # Код      break   }--пропуск--


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

Листинг 4.8. Проверка различных серверов с помощью оператора switch

$currentServer = $servers[0]switch ($currentServer) {   $servers[0] {      # Check if server is online and get content at SRV1 path.      break   }   $servers[1] {      ## Check if server is online and get content at SRV2 path.      break   }   $servers[2] {      ## Check if server is online and get content at SRV3 path.      break   }--пропуск--


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

Использование циклов

Существует хорошее практическое правило для работы за компьютером: не повторяйся (dont repeat yourself, DRY). Если вы обнаружите, что выполняете одну и ту же работу, то, скорее всего, существует способ ее автоматизировать. То же самое и с написанием кода: если вы используете одни и те же строки снова и снова, вероятно, существует решение получше.

Один из способов избежать повторов использовать циклы. Цикл позволяет многократно выполнять код, до тех пор пока не изменится некоторое заданное условие. Условие остановки может запускать цикл заданное количество раз, либо до тех пор, пока не изменится некоторое логическое значение, либо определить бесконечное выполнение цикла. Каждый проход цикла мы будем называть итерацией.

PowerShell предлагает пять типов циклов: foreach, for, do/while, do/until и while. В этом разделе мы обсудим каждый тип цикла, отметим их уникальные черты и выделим лучшие ситуации для их использования.

Об авторе

Адам Бертрам (Adam Bertram) опытный ИТ-специалист и эксперт в области интернет-бизнеса с 20-летним стажем. Предприниматель, ИТ-инфлюенсер, специалист Microsoft MVP, блогер, тренинг-менеджер и автор материалов по контент-маркетингу, сотрудничающий со многими ИТ-компаниями. Также Адам основал популярную платформу TechSnips для развития навыков ИТ-специалистов (techsnips.io).

Более подробно с книгой можно ознакомиться на сайте издательства
Оглавление
Отрывок

Для Хаброжителей скидка 25% по купону PowerShell

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Подробнее..

Книга C для профи

19.04.2021 16:09:25 | Автор: admin
image Привет, Хаброжители! С++ популярный язык для создания ПО. В руках увлеченного программиста С++ становится прекрасным инструментом для создания лаконичного, эффективного и читаемого кода, которым можно гордиться.

C++ для профи адресован программистам среднего и продвинутого уровней, вы продеретесь сквозь тернии к самому ядру С++. Часть 1 охватывает основы языка С++ от типов и функций до жизненного цикла объектов и выражений. В части II представлена стандартная библиотека C ++ и библиотеки Boost. Вы узнаете о специальных вспомогательных классах, структурах данных и алгоритмах, а также о том, как управлять файловыми системами и создавать высокопроизводительные программы, которые обмениваются данными по сети.


Об этой книге

Современные программисты на C++ имеют доступ к ряду очень качественных книг, например Эффективный современный C++ Скотта Мейерса1 и Язык программирования C++ Бьёрна Страуструпа, 4-е издание2. Однако эти книги написаны для достаточно продвинутых программистов. Доступны также некоторые вводные тексты о C++, но они часто пропускают важные детали, потому что ориентированы на абсолютных новичков в программировании. Опытному программисту непонятно, где можно погрузиться в язык C++.

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

Кому будет интересна эта книга?

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

В ПОЗНАКОМИТЕСЬ С ОСНОВНМИ ФИШКАМИ СОВРЕМЕННОГО С++:

Базовые типы, ссылочные и пользовательские типы.
Полиморфизм во время компиляции и полиморфизм во время выполнения.
Жизненный цикл объекта, включая длительность хранения, стек вызовов, управление памятью, исключения и парадигму RAII.
Продвинутые выражения, операторы и функции.
Умные указатели, структуры данных, дата и время, числовые данные и др.
Контейнеры, итераторы, строки и алгоритмы.
Потоки и файлы, многозадачность, сетевое программирование и разработка приложений.

Отслеживание жизненного цикла объекта


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

Рассмотрим класс Tracer в листинге 4.5, который печатает сообщение всякий раз, когда объект Tracer создается или разрушается. Этот класс можно использовать для исследования жизненных циклов объекта, потому что каждый Tracer четко указывает, когда его жизнь начинается и заканчивается.

Листинг 4.5. Класс Tracer и его конструктор с деструктором

#include <cstdio>struct Tracer {    Tracer(const char* name1) : name{ name }2 {       printf("%s constructed.\n", name); 3    }    ~Tracer() {       printf("%s destructed.\n", name); 4    }private:    const char* const name;};

Конструктор принимает один параметр 1 и сохраняет его в члене name 2. Затем он печатает сообщение, содержащее name 3. Деструктор 4 также выводит сообщение с name.

Рассмотрим программу в листинге 4.6. Четыре различных объекта Tracer имеют разную длительность хранения. Просматривая порядок вывода программы Tracer, вы можете проверить полученные знания о длительности хранения.

Листинг 4.6. Программа, использующая класс Tracer в листинге 4.5 для иллюстрации длительности хранения

#include <cstdio>struct Tracer {    --пропуск--};static Tracer t1{ "Static variable" }; 1thread_local Tracer t2{ "Thread-local variable" }; 2int main() {  const auto t2_ptr = &t2;  printf("A\n"); 3  Tracer t3{ "Automatic variable" }; 4  printf("B\n");  const auto* t4 = new Tracer{ "Dynamic variable" }; 5  printf("C\n");}

Листинг 4.6 содержит Tracer со статической 1, локальной поточной 2, автоматической 4 и динамической 5 длительностью хранения. Между каждой строкой в main выводится символ A, B или C для ссылки 3.

Запуск программы приводит к результату в листинге 4.7.

Листинг 4.7. Пример вывода из листинга 4.6

Static variable constructed.Thread-local variable constructed.A 3Automatic variable constructed.BDynamic variable constructed.CAutomatic variable destructed.Thread-local variable destructed.Static variable destructed.

Перед первой строкой main 3 статические и потоковые локальные переменные t1 и t2 были инициализированы 1 2. Это можно увидеть в листинге 4.7: обе переменные напечатали свои сообщения инициализации до A. Как и для любой автоматической переменной, область видимости t3 ограничена включающей функцией main. Соответственно t3 создается в месте инициализации сразу после A.

После B вы можете видеть сообщение, соответствующее инициализации t4 5. Обратите внимание, что соответствующее сообщение, генерируемое динамическим деструктором Tracer, отсутствует. Причина в том, что вы (намеренно) потеряли память для объекта, на который указывает t4. Поскольку команды delete t4 не было, деструктор никогда не будет вызван.

Перед возвратом main выводится С. Поскольку t3 это автоматическая переменная, область видимости которой ограничена main, на этом этапе она уничтожается, поскольку main делает возврат.

Наконец, статические и локальные поточные переменные t1 и t2 уничтожаются непосредственно перед выходом из программы, в результате чего получаются последние два сообщения в листинге 4.7.

Исключения


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

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

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

Ключевое слово throw

Чтобы вызвать исключение, используйте ключевое слово throw, за которым следует бросаемый объект.

Большинство объектов являются бросаемыми. Однако рекомендуется использовать одно из исключений, доступных в stdlib, например std::runtime_error в заголовке <stdеxcept>. Конструктор runtime_error принимает const char* с нулевым символом в конце, описывающий природу состояния ошибки. Это сообщение можно получить с помощью метода what, который не принимает параметров.

Класс Groucho в листинге 4.8 создает исключение всякий раз при вызове метода forget с аргументом, равным 0xFACE.

Листинг 4.8. Класс Groucho

#include <stdexcept>#include <cstdio>struct Groucho {   void forget(int x) {      if (x == 0xFACE) {         throw1 std::runtime_error2{ "I'd be glad to make an exception." };      }      printf("Forgot 0x%x\n", x);    }};

Чтобы вызвать исключение, в листинге 4.8 используется ключевое слово throw 1, за которым следует объект std::runtime_error 2.

Использование блоков try-catch

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

Листинг 4.9 показывает использование блока try-catch для обработки исключений, генерируемых объектом Groucho.

В методе main создается объект Groucho, а затем устанавливается блок try-catch 1. В части try вызывается метод forget класса groucho с несколькими различными параметрами: 0xC0DE 2, 0xFACE 3 и 0xC0FFEE 4. Внутри части catch обрабатываются любые исключения std::runtime_error 5, выводя сообщение в консоли 6.

Листинг 4.9. Использование try-catch для обработки исключений класса Groucho

#include <stdexcept>#include <cstdio>struct Groucho {      --пропуск--};int main() {   Groucho groucho;   try { 1       groucho.forget(0xC0DE); 2       groucho.forget(0xFACE); 3       groucho.forget(0xC0FFEE); 4    } catch (const std::runtime_error& e5) {       printf("exception caught with message: %s\n", e.what()); 6    }}

При запуске программы в листинге 4.9 вы получите следующий вывод:

Forgot 0xc0deexception caught with message: I'd be glad to make an exception.

При вызове forget с параметром 0xC0DE 2 groucho выводит Forgot0xc0de и завершает выполнение. При вызове forget с параметром 0xFACE 3 groucho выдает исключение. Это исключение остановило нормальное выполнение программы, поэтому forget никогда больше не вызывается 4. Вместо этого исключение в полете перехватывается 5, а его сообщение выводится в консоль 6.

Классы исключений stdlib

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

Стандартные классы исключений

stdlib предоставляет стандартные классы исключений в заголовке <stdеxcept>. Они должны стать вашим первым причалом при программировании исключений. Суперклассом для всех стандартных классов исключений является класс std::exception. Все подклассы в std::exception могут быть разделены на три группы: логические ошибки (logic_error), ошибки выполнения (runtime_error) и ошибки языковой поддержки. Ошибки языковой поддержки обычно не относятся к вам как к программисту, но вы наверняка столкнетесь с логическими ошибками и ошибками выполнения. Рисунок 4.1 обобщает их отношения.

image


КРАТКИЙ КУРС ПО НАСЛЕДОВАНИЮ

Прежде чем вводить исключения stdlib, нужно понять простое наследование классов C++ на очень высоком уровне. Классы могут иметь подклассы, которые наследуют функциональность своих суперклассов. Синтаксис в листинге 4.10 определяет это отношение.

Листинг 4.10. Определение суперклассов и подклассов

struct Superclass {    int x;};struct Subclass : Superclass { 1    int y;    int foo() {      return x + y; 2    }};

В Superclass нет ничего особенного. Но вот объявление Subclass 1 является особенным. Оно определяет отношения наследования с использованием синтаксиса: Superclass. Subclass наследует члены от Superclass, которые не помечены как private. Это можно увидеть в действии, когда Subclass использует поле x 2. Это поле принадлежит Superclass, но поскольку Subclass наследует от Superclass, x доступно.

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

Логические ошибки

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

Поскольку инвариант класса это то, что определяет программист, ни компилятор, ни среда выполнения не могут применять его без посторонней помощи. Можно использовать конструктор класса для проверки различных условий, и если нельзя установить инвариант класса, можно вызвать исключение. Если сбой является результатом, скажем, передачи неверного параметра в конструктор, logic_error является подходящим типом исключения.

logic_error имеет несколько подклассов, о которых следует знать:

  • domain_error сообщает об ошибках, связанных с допустимым диапазоном ввода, особенно для математических функций. Например, квадратный корень поддерживает только неотрицательные числа (в реальном случае). Если передается отрицательный аргумент, функция квадратного корня может выдать domain_error.
  • Исключение invalid_argument сообщает, как правило, о неожиданных параметрах.
  • Исключение length_error сообщает, что какое-либо действие нарушит ограничение максимального размера.
  • Исключение out_of_range сообщает, что некоторое значение не находится в ожидаемом диапазоне. Каноническим примером является индексирование с проверкой границ в структуре данных.

Ошибки выполнения

Ошибки выполнения происходят из класса runtime_error. Эти исключения помогают сообщать об ошибках, которые выходят за рамки программы. Как и logic_error, runtime_error имеет несколько подклассов, которые могут оказаться полезными:

  • system_error сообщает, что операционная система обнаружила некоторую ошибку. Такого рода исключения могут тысячи раз встретиться на вашем пути. Внутри заголовка <system_error> находится большое количество кодов ошибок и их состояний. Когда создается system_error, информация об ошибке упаковывается, чтобы можно было определить природу ошибки. Метод .code() возвращает enumclass типа std::errc, который имеет большое количество значений, таких как bad_file_descriptor, timed_out и license_denied,
  • overflow_error и underflow_error сообщают об арифметическом переполнении и потере значимости соответственно.


Другие ошибки наследуются напрямую от exception. Распространенным является исключение bad_alloc, которое сообщает, что new не удалось выделить необходимую память для динамического хранения.

Ошибки языковой поддержки

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

Обработка исключений

Правила обработки исключений основаны на наследовании классов. Когда выбрасывается исключение, блок catch обрабатывает его, если тип выброшенного исключения соответствует типу исключения обработчика или если тип выброшенного исключения наследуется от типа исключения обработчика.

Например, следующий обработчик перехватывает любое исключение, которое наследуется от std::exception, включая std::logic_error:

try {   throw std::logic_error{ "It's not about who wrong "                          "it's not about who right" };} catch (std::exception& ex) {   // Обрабатывает std::logic_error. Поскольку он наследуется от std::exception}

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

try {  throw 'z'; // Don't do this.} catch (...) {  // Обрабатывает любое исключение, даже 'z'}

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

Можно обрабатывать различные типы исключений, происходящих из одного и того же блока try, объединяя операторы catch, как показано здесь:

try {  // Код, который может вызвать исключение  --пропуск--} catch (const std::logic_error& ex) {  // Запись исключения и завершение работы программы; найдена программная ошибка!  --пропуск--} catch (const std::runtime_error& ex) {  // Делаем все, что можно  --пропуск--} catch (const std::exception& ex) {  // Обработка любого исключения, наследуемого от std:exception,  // которое не является logic_error или runtime_error.  --пропуск--} catch (...) {  // Паника; было сгенерировано непредвиденное исключение  --пропуск--}

Обычно такой код можно увидеть в точке входа в программу.

ПЕРЕБРАСВАНИЕ ИСКЛЮЧЕНИЯ
В блоке catch можно использовать ключевое слово throw, чтобы возобновить поиск подходящего обработчика исключений. Это называется перебрасыванием исключения. Есть несколько необычных, но важных случаев, когда вы, возможно, захотите дополнительно проверить исключение, прежде чем обработать его, как показано в листинге 4.11.

Листинг 4.11. Перебрасывание ошибки

try {  // Код, который может вызвать system_error  --пропуск--} catch(const std::system_error& ex) {   if(ex.code()!= std::errc::permission_denied){   // Ошибка, не связанная с отказом в доступе     throw; 1}  // Восстановление после ошибки   --пропуск--}

В этом примере код, который может выдать system_error, помещается в блок trycatch.
Все системные ошибки обрабатываются, но, если это не ошибка EACCES (в доступе отказано), исключение перебрасывается 1. У этого подхода есть некоторые потери производительности, и полученный код часто оказывается излишне запутанным.

Вместо повторной обработки можно определить новый тип исключения и создать отдельный обработчик перехвата для ошибки EACCES, как показано в листинге 4.12.

Листинг 4.12. Перехват конкретного исключения, но не перебрасывание


try {  // Генерация исключения PermissionDenied  --пропуск--} catch(const PermissionDenied& ex) {  // Восстановление после ошибки EACCES (отказано в доступе) 1  --пропуск--}

Если генерируется std::system_error, обработчик PermissionDenied 1 не поймает его. (Конечно, обработчик std::system_error все равно можно оставить, чтобы перехватывать такие исключения, если это необходимо.)

Пользовательские исключения

Программист может при необходимости определить свои собственные исключения; обычно эти пользовательские исключения наследуются от std::exception. Все классы из stdlib используют исключения, которые происходят от std::exception. Это позволяет легко перехватывать все исключения, будь то из вашего кода или из stdlib, с помощью одного блока catch.

Ключевое слово noexcept

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

bool is_odd(int x) noexcept {  return 1 == (x % 2);}

Функции с пометкой noexcept составляют жесткий контракт. При использовании функции, помеченной как noexcept, вы можете быть уверены, что функция не может вызвать исключение. В обмен на это вы должны быть предельно осторожны, когда помечаете собственную функцию как noexcept, так как компилятор не может это проверить. Если код выдает исключение внутри функции, помеченной как noexcept, это плохо. Среда выполнения C++ вызовет функцию std::terminate, которая по умолчанию завершит работу программы через abort. После такого программа не может быть восстановлена:

void hari_kari() noexcept {   throw std::runtime_error{ "Goodbye, cruel world." };}

Пометка функции ключевым словом noexcept позволяет оптимизировать код, полагаясь на то, что функция не может вызвать исключение. По сути, компилятор освобождается для использования семантики переноса, что может быть выполнено быстрее (подробнее об этом в разделе Семантика перемещения, с. 184).
ПРИМЕЧАНИЕ
Ознакомьтесь с правилом 14 Эффективного использования C++ Скотта Мейерса, чтобы подробно обсудить noexcept. Суть в том, что некоторые конструкторы переноса и операторы присваивания переноса могут выдавать исключение, например если им нужно выделить память, а система не работает. Если конструктор переноса или оператор присваивания переноса не указывает иное, компилятор должен предполагать, что перенос может вызвать исключение. Это отключает определенные оптимизации.

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

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

image

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

Стеки вызовов и обработка исключений

Среда выполнения ищет ближайший обработчик исключений для выброшенного исключения. Если в текущем кадре стека есть соответствующий обработчик исключения, он его обработает. Если соответствующий обработчик не найден, среда выполнения раскручивает стек вызовов, пока не найдет подходящий обработчик. Любые объекты, срок жизни которых заканчивается, уничтожаются обычным способом.

Выбрасывание исключений из деструктора

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

Допустим, генерируется исключение и во время размотки стека другое исключение генерируется деструктором во время обычной очистки. Теперь у вас есть два исключения в состоянии полета. Как среда выполнения C++ должна справляться с такой ситуацией?

У вас может быть свое мнение на этот счет, но среда выполнения вызовет функцию terminate (завершение). Рассмотрим листинг 4.13, который показывает, что может произойти при выбрасывании исключений из деструктора:

Листинг 4.13. Программа, где показана опасность создания исключения в деструкторе

#include <cstdio>#include <stdexcept>struct CyberdyneSeries800 {  CyberdyneSeries800() {   printf("I'm a friend of Sarah Connor."); 1  }  ~CyberdyneSeries800() {    throw std::runtime_error{ "I'll be back." }; 2}};  int main() {    try {      CyberdyneSeries800 t800; 3      thro std::runtime_error{ "Come with me if you want to live." }; 4    } catch(const std::exception& e) { 5      printf("Caught exception: %s\n", e.what()); 6    }}----------------------------------------------------------------------I'm a friend of Sarah Connor. 

ПРИМЕЧАНИЕ
Листинг 4.13 вызывает std::terminate, поэтому в зависимости от операционной среды может быть показано всплывающее окно с уведомлением.

Во-первых, был объявлен класс CyberdyneSeries800, который имеет простой конструктор, который выводит сообщение 1, и воинственный деструктор, который генерирует необработанное исключение 2. В main определяется блок try, в котором инициализируется CyberdyneSeries800 под именем t800 3, и выбрасывается runtime_error 4. В лучшем случае блок catch 5 обработает это исключение, выведет его сообщение 6 и все выйдет изящно. Поскольку t800 это автоматическая переменная в блоке try, она разрушается во время обычного процесса поиска обработчика для исключения, которое было выброшено 4. А поскольку t800 создает исключение в своем деструкторе 2, программа вызывает std::terminate и внезапно завершается.

Как правило, обращайтесь с деструкторами так, как если бы они были noexcept.

Класс SimpleString


Используя расширенный пример, давайте рассмотрим, как конструкторы, деструкторы, члены и исключения объединяются. Класс SimpleString в листинге 4.14 позволяет добавлять строки в стиле C и выводить результат.

Листинг 4.14. Конструктор и деструктор класса SimpleString

#include <stdexcept>struct SimpleString {  SimpleString(size_t max_size) 1    : max_size{ max_size }, 2      length{} { 3    if (max_size == 0) {      throw std::runtime_error{ "Max size must be at least 1." }; 4    }    buffer = new char[max_size]; 5    buffer[0] = 0; 6    }   ~SimpleString() {     delete[] buffer; 7    }--пропуск--private:    size_t max_size;    char* buffer;    size_t length;};

Конструктор 1 принимает один параметр max_size. Это максимальная длина строки, которая включает символ завершения строки. Инициализатор члена 2 сохраняет эту длину в переменной-члене max_size. Это значение также используется в выражении new массива для выделения буфера для хранения данной строки 5. Полученный указатель сохраняется в buffer. Длина инициализируется нулем 3, и это гарантирует, что по крайней мере буфер будет достаточного размера для хранения нулевого байта 4. Поскольку строка изначально пуста, первый байт буфера заполняется нулем 6.
ПРИМЕЧАНИЕ
Поскольку max_size это size_t, он не имеет знака и не может быть отрицательным, поэтому не нужно проверять это фиктивное условие.

Класс SimpleString владеет ресурсом памятью, на которую указывает буфер, которая должна быть освобождена при прекращении использования. Деструктор содержит одну строку 7, которая освобождает buffer. Поскольку распределение и освобождение buffer связаны конструктором и деструктором SimpleString, память никогда не будет потеряна.

Этот шаблон называется получение ресурса есть инициализация (RAII), или получение конструктора освобождение деструктора (CADRe).
ПРИМЕЧАНИЕ
Класс SimpleString все еще имеет неявно определенный конструктор копирования. Несмотря на то что память не может быть потеряна, при копировании класс потенциально освободится вдвое. Вы узнаете о конструкторах копирования в разделеСемантике копирования, с. 176. Просто знайте, что листинг 4.14 это обучающий инструмент, а не рабочий код.

Добавление и вывод

Класс SimpleString пока не очень полезен. В листинг 4.15 добавлена возможность выводить строку и добавлять набор символов в конец строки.

Листинг 4.15. Методы print и append_line для SimpleString

#include <cstdio>#include <cstring>#include <stdexcept>struct SimpleString {  --пропуск--  void print(const char* tag) const { 1    printf("%s: %s", tag, buffer);  }  bool append_line(const char* x) { 2  const auto x_len = strlen3(x);  if (x_len + length + 2 > max_size) return false; 4  std::strncpy(buffer + length, x, max_size - length);  length += x_len;  buffer[length++] = '\n';  buffer[length] = 0;  return true; } --пропуск--};


Первый метод print 1 выводит строку. Для удобства можно предоставить строку tag, чтобы можно было сопоставить вызов print с результатом. Этот метод является постоянным, потому что нет необходимости изменять состояние SimpleString.

Метод append_line 2 принимает строку с нулем в конце и добавляет ее содержимое плюс символ новой строки в buffer. Он возвращает true, если был успешно добавлен, и false, если не было достаточно места. Во-первых, append_line должен определить длину x. Для этого используется функция strlen 3 из заголовка <сstring>, которая принимает строку с нулевым символом в конце и возвращает ее длину:

size_t strlen(const char* str);

strlen используется для вычисления длины x и инициализации x_len с результатом. Этот результат используется для вычисления того, приведет ли добавление x (символов новой строки) и нулевого байта к текущей строке к получению строки с длиной, превышающей max_size 4. Если это так, append_line возвращает false.

Если для добавления x достаточно места, необходимо скопировать его байты в правильное место в buffer. Функция std::strncpy 5 из заголовка <сstring> является одним из подходящих инструментов для этой работы. Она принимает три параметра: адрес назначения, адрес источника и количество символов для копирования:

char* std::strncpy(char* destination, const char* source, std::size_t num);

Функция strncpy будет копировать до num байтов из source в destination. После завершения она вернет значение destination (которое будет отброшено).

После добавления количества байтов x_len, скопированных в buffer, к length работа завершается добавлением символа новой строки \n и нулевого байта в конец buffer. Функция возвращает true, чтобы указать, что введенный х был успешно добавлен в виде строки в конец буфера.
ПРЕДУПРЕЖДЕНИЕ
Используйте strncpy очень осторожно. Слишком легко забыть символ конца строки в исходной строке или не выделить достаточно места в целевой строке. Обе ошибки приведут к неопределенному поведению. Мы рассмотрим более безопасную альтернативу во второй части книги.

Использование SimpleString
Листинг 4.16 показывает пример использования SimpleString, где добавляются несколько строк и промежуточные результаты выводятся в консоль.

Листинг 4.16. Методы SimpleString

#include <cstdio>#include <cstring>#include <exception>struct SimpleString {   --пропуск--}int main() {   SimpleString string{ 115 }; 1   string.append_line("Starbuck, whaddya hear?");   string.append_line("Nothin' but the rain."); 2   string.print("A"); 3   string.append_line("Grab your gun and bring the cat in.");   string.append_line("Aye-aye sir, coming home."); 4   string.print("B"); 5   if (!string.append_line("Galactica!")) { 6      printf("String was not big enough to append another message."); 7   }}

Сначала создается SimpleString с max_length=115 1. Метод append_line используется дважды 2, чтобы добавить некоторые данные в строку, а затем вывести содержимое вместе с тегом A 3. Затем добавляется больше текста 4 и снова выводится содержимое, на этот раз с тегом B 5. Когда append_line определяет, что SimpleString исчерпал свободное пространство 6, возвращается false 7. (Вы как пользователь SimpleString несете ответственность за проверку этого условия.)

Листинг 4.17 содержит выходные данные запуска этой программы.

Листинг 4.17. Результат выполнения программы в листинге 4.16

A: Starbuck, whaddya hear? 1Nothin' but the rain.B: Starbuck, whaddya hear? 2Nothin' but the rain.Grab your gun and bring the cat in.Aye-aye sir, coming home.String was not big enough to append another message. 3


Как и ожидалось, строка содержит Starbuck, whaddya hear?\nNothin' but the rain.\nвA 1. (Вспомните из главы 2, что \n это специальный символ новой строки.) После добавления Grab your gun and bring the cat in. и Aye-aye sir, coming home. вы получите ожидаемый результат в B 2.

Когда листинг 4.17 пытается добавить Galactica! в string, append_line возвращает false, поскольку в buffer недостаточно места. Это вызывает вывод сообщения String was not big enough to append another message 3.

Составление SimpleString

Рассмотрим, что происходит при определении класса с членом SimpleString, как показано в листинге 4.18.

Как предполагает инициализатор члена 1, string полностью построена, и ее инварианты класса назначаются после выполнения конструктора SimpleStringOwner. Здесь демонстрируется порядок членов объекта во время создания: члены создаются перед вызовом конструктора окружающего объекта. Смысл есть, а иначе как можно установить инварианты класса без знаний об инвариантах его членов?

Листинг 4.18. Реализация SimpleStringOwner

#include <stdexcept>struct SimpleStringOwner {   SimpleStringOwner(const char* x)     : string{ 10 } { 1     if (!string.append_line(x)) {       throw std::runtime_error{ "Not enough memory!" };    }    string.print("Constructed");  }  ~SimpleStringOwner() {    string.print("About to destroy"); 2  }private:  SimpleString string;};

Деструкторы работают в обратном порядке. Внутри ~SimpleStringOwner() 2 нужно хранить инварианты класса строки, чтобы можно было напечатать ее содержимое. Все члены уничтожаются после вызова деструктора объекта.


В листинге 4.19 используется SimpleStringOwner.

Листинг 4.19. Программа, содержащая SimpleStringOwner

--пропуск--int main() {   SimpleStringOwner x{ "x" };   printf("x is alive\n");}--------------------------------------------------------------------Constructed: х 1x is aliveAbout to destroy: х 2

Как и ожидалось, член string в x 1 создается надлежащим образом, потому что конструкторы членов объекта вызываются перед конструктором объекта, в результате чего появляется сообщение Constructed: x. Как автоматическая переменная x уничтожается непосредственно перед выходом из main, и вы получаете сообщение About to destroy: x 2. Член string все еще доступен в этот момент, потому что деструкторы членов вызываются после деструктора вмещающего объекта.

Размотка стека вызовов

Листинг 4.20 демонстрирует, как обработка исключений и размотка стека работают вместе. Блок try-catch устанавливается в main, после чего выполняется серия вызовов функций. Один из этих вызовов вызывает исключение.

Листинг 4.20. Программа, где используется SimpleStringOwner и размотка стека вызовов

--пропуск--void fn_c() {   SimpleStringOwner c{ "cccccccccc" }; 1}void fn_b() {  SimpleStringOwner b{ "b" };  fn_c(); 2}int main() {  try { 3   SimpleStringOwner a{ "a" };   fn_b(); 4   SimpleStringOwner d{ "d" }; 5 } catch(const std::exception& e) { 6  printf("Exception: %s\n", e.what()); }}

В листинге 4.21 показаны результаты запуска программы из листинга 4.20.

Листинг 4.21. Результат запуска программы из листинга 4.20

Constructed: aConstructed: bAbout to destroy: bAbout to destroy: aException: Not enough memory!

Вы установили блок try-catch 3. Первый экземпляр SimpleStringOwner, a, создается без инцидентов, и в консоль выводится сообщение Constructed: а. Далее вызывается fn_b 4. Обратите внимание, что вы все еще находитесь в блоке try-catch, поэтому любое выброшенное исключение будет обработано. Внутри fn_b другой экземпляр SimpleStringOwner, b, успешно создается, и Constructed: b выводится на консоль. Затем происходит вызов еще одной функции, fn_c 2.

Давайте на минуту остановимся, чтобы разобраться, как выглядит стек вызовов, какие объекты живы и как выглядит ситуация обработки исключений. Сейчас у нас есть два живых и действительных объекта SimpleStringOwner: a и b. Стек вызовов выглядит как main() fn_ () fn_c(), и в main настроен обработчик исключений для обработки любых исключений. Эта ситуация показана на рис. 4.3.

В 1 возникает небольшая проблема. Напомним, что SimpleStringOwner имеет член SimpleString, который всегда инициализируется с max_size 10. При попытке создания c конструктор SimpleStringOwner выдает исключение, потому что вы пытались добавить cccccccccc, который имеет длину 10, что выходит за рамки, потому что нужно еще добавить символы новой строки и завершения строки.

Теперь в полете находится одно исключение. Стек будет раскручиваться до тех пор, пока не будет найден соответствующий обработчик, и все объекты, выпадающие из области видимости в результате этого раскручивания, будут уничтожены. Обработчик доходит до стека 6, поэтому fn_c и fn_b разматываются. Поскольку SimpleStringOwner b это автоматическая переменная в fn_b, она разрушается и в консоль выводится сообщение About to destroy: b. После fn_b автоматические переменные внутри try {} уничтожаются. Это включает в себя SimpleStringOwner a, поэтому в консоль выводится About to destroy: a.

image

Как только исключение происходит в блоке try{}, дальнейшие операторы не выполняются. В результате d никогда не инициализируется 5 и конструктор d не вызывается и не выводится в консоль. После размотки стека вызовов выполнение сразу переходит к блоку catch. В итоге в консоль выводится сообщение Exception: Not enough memory! 6.

Исключения и производительность

Обработка исключений обязательна в программах; ошибки неизбежны. При правильном использовании исключений ошибок не возникает, код работает быстрее, чем код, проверенный вручную. Если ошибка все-таки есть, обработка исключений может иногда выполняться медленнее, но у этого есть огромные преимущества в надежности и удобстве обслуживания по сравнению с альтернативными вариантами. Курт Гантерот, автор Оптимизации программ на C++, хорошо пишет об этом: Использование обработки исключений приводит к программам, которые работают быстрее при нормальном выполнении и ведут себя лучше в случае неудачи. Когда программа на C++ выполняется нормально (без исключений), при проверке исключений не возникает никаких издержек во время выполнения. Вы платите только за исключение.

Надеюсь, вы убедились в центральной роли, которую играют исключения в идиоматических программах на C++. К сожалению, иногда нет возможности использовать исключения. Одним из примеров является встроенная разработка, где требуются гарантии в реальном времени. Инструменты просто не существуют (пока) для этих настроек. Если повезет, это скоро изменится, но сейчас приходится обходиться без исключений в большинстве встроенных контекстов. Другой пример некоторый устаревший код. Исключения изящны из-за того, как они вписываются в объекты RAII. Когда деструкторы отвечают за очистку ресурсов, раскрутка стека является прямым и эффективным способом защиты от утечек памяти. В устаревшем коде можно найти ручное управление ресурсами и обработку ошибок вместо объектов RAII. Это делает использование исключений очень опасным, поскольку размотка стека безопасна только для объектов RAII. Без них можно с легкостью допустить утечку ресурсов.

Альтернативы для исключений

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

struct HumptyDumpty {   HumptyDumpty();   bool is_together_again();  --пропуск--};

В идиоматическом C++ вы бы просто сгенерировали исключение в конструкторе, но здесь следует помнить о проверке и обработке ситуации как условии ошибки в вызывающем коде:

bool send_kings_horses_and_men() {  HumptyDumpty hd{};  if (hd.is_together_again()) return false;  // Использование инвариантов класса hd гарантировано.  // HumptyDumpty с треском проваливается.  --пропуск--  return true;}

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

Листинг 4.22. Фрагмент кода с объявлением структурированной привязки

struct Result { 1   HumptyDumpty hd;   bool success;   };  Result make_humpty() { 2    HumptyDumpty hd{};    bool is_valid;    // Проверка правильности hd и установка соответствующего значения is_valid    return { hd, is_valid };   }bool send_kings_horses_and_men() {   auto [hd, success] = make_humpty();    if(!success) return false;   // Установка инвариантов класса   --пропуск--   return true;}

Сначала объявляется POD, который содержит HumptyDumpty и флаг success 1. Затем определяется функция make_humpty 2, которая создает и проверяет HumptyDumpty. Такие методы называются фабричными, поскольку их целью является инициализация объектов. Функция make_humpty оборачивает его и флаг success в Result при возврате. Синтаксис в точке вызова 3 показывает, как можно распаковать Result, получив несколько переменных с определением типа при помощи auto.
ПРИМЕЧАНИЕ
Более подробное описание структурированных привязок приведено в подразделе Структурированные привязки, с. 289.


Об авторе

Джош Лоспинозо (Josh Lospinoso) доктор философии и предприниматель, прослуживший 15 лет в армии США. Джош офицер, занимающийся вопросами кибербезопасности. Написал десятки программ для средств информационной безопасности и преподавал C++ начинающим разработчикам. Выступает на различных конференциях, является автором более 20 рецензируемых статей и стипендиатом Родса, а также имеет патент. В 2012 году стал соучредителем успешной охранной компании. Джош ведет блог и активно участвует в разработке ПО с открытым исходным кодом.

О научном редакторе

Кайл Уиллмон (Kyle Willmon) разработчик информационных систем с 12-летним опытом в C++. В течение 7 лет работал в сообществе по информационной безопасности, используя C++, Python и Go в различных проектах. В настоящее время является разработчиком в команде Sony Global Threat Emulation.

Более подробно с книгой можно ознакомиться на сайте издательства
Оглавление
Отрывок

Для Хаброжителей скидка 25% по купону C++

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Подробнее..

Книга Современный скрапинг веб-сайтов с помощью Python. 2-е межд. издание

12.04.2021 16:18:43 | Автор: admin
image Привет, Хаброжители! Если программирование напоминает волшебство, то веб-скрапинг это очень сильное колдунство. Написав простую автоматизированную программу, можно отправлять запросы на веб-серверы, запрашивать с них данные, а затем анализировать их и извлекать необходимую информацию. Новое расширенное издание книги знакомит не только с веб-скрапингом, но и поможет собрать любого вида данные в современном Интернете. В части I основное внимание уделено механике веб-скрапинга: как с помощью Python запрашивать информацию с веб-сервера, производить базовую обработку серверного отклика и организовать автоматизированное взаимодействие с сайтами. В части II исследованы более специфичные инструменты и приложения, которые пригодятся при любом сценарии веб-скрапинга. Разбирайте сложные HTML-страницы. Разрабатывайте поисковые роботы с помощью фреймворка Scrapy. Изучайте методы хранения данных, полученных с помощью скрапинга. Считывайте и извлекайте данные из документов. Очищайте и нормализуйте плохо отформатированные данные. Читайте и пишите информацию на естественных языках. Освойте поиск по формам и логинам. Изучите скрапинг JavaScript и работу с API. Используйте и пишите программы для преобразования изображений в текст. Учитесь обходить скрапинговые ловушки и блокаторы ботов. Протестируйте собственный сайт с помощью скрапинга.

Веб-краулинг с помощью API


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

По мере распространения методов генерации и загрузки контента с помощью JavaScript и Ajax описанная выше ситуация становится все менее привычной. В главе 11 мы рассмотрели один из способов решения указанной проблемы: использование Selenium для автоматизации браузера и извлечения данных. Это легко сделать. Это работает почти всегда.

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

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

Краткое введение в API

Существует бесчисленное количество книг, докладов и руководств о нюансах API REST, GraphQL21, JSON и XML, однако все они основаны на одной простой концепции. API определяет стандартизованный синтаксис, который позволяет одной программе взаимодействовать с другой, даже если они написаны на разных языках или имеют разную структуру.

Данный раздел посвящен веб-API (в особенности позволяющим веб-серверу взаимодействовать с браузером), и здесь мы будем понимать под API именно этот тип интерфейсов. Но вы можете учесть, что в других контекстах API также является обобщенным термином, который может обозначать, например, интерфейс, позволяющий программе на Java взаимодействовать с программой на Python, работающей на том же компьютере. API не всегда означает интерфейс через Интернет и не обязательно должен включать в себя какие-либо веб-технологии.

Веб-API чаще всего используются разработчиками для взаимодействия с широко разрекламированными и хорошо документированными открытыми сервисами. Например, американский кабельный спортивный телевизионный канал ESPN предоставляет API (http://personeltest.ru/away/www.espn.com/apis/devcenter/docs/) для получения информации о спортсменах, счетах в играх и др. У Google в разделе для разработчиков (http://personeltest.ru/aways/console.developers.google.com) есть десятки API для языковых переводов, аналитики и геолокации.

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

Например, в следующем URL pathparam является параметром пути:

example.com/the-api-route/pathparam

А здесь pathparam является значением параметра param1:

example.com/the-api-route?param1=pathparam

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

Ответ на API-запрос обычно возвращается в формате JSON или XML. В настоящее время JSON гораздо популярнее, чем XML, но последний иногда тоже встречается. Многие API позволяют выбирать тип ответа, обычно с помощью еще одного параметра, определяющего, какой тип ответа вы хотите получить.

Вот пример ответа на API-запрос в формате JSON:

{"user":{"id": 123, "name": "Ryan Mitchell", "city": "Boston"}}


А вот ответ на API-запрос в формате XML:

<user><id>123</id><name>Ryan Mitchell</name><city>Boston</city></user>


Сайт ip-api.com (http://personeltest.ru/away/ip-api.com/) имеет понятный и удобный API, который преобразует IP-адреса в реальные физические адреса. Вы можете попробовать выполнить простой запрос API, введя в браузере следующее

ip-api.com/json/50.78.253.58

В результате вы получите примерно такой ответ:

{"ip":"50.78.253.58","country_code":"US","country_name":"United States","region_code":"MA","region_name":"Massachusetts","city":"Boston","zip_code":"02116","time_zone":"America/New_York","latitude":42.3496,"longitude":-71.0746,"metro_code":506}

Обратите внимание: в запросе есть параметр пути json. Чтобы получить ответ в формате XML или CSV, нужно заменить его на соответствующий формат:

ip-api.com/xml/50.78.253.58
ip-api.com/csv/50.78.253.58


API и HTTP-методы

В предыдущем разделе мы рассмотрели API, отправляющие на сервер GET-запрос для получения информации. Существует четыре основных способа (или метода) запроса информации с веб-сервера через HTTP:

GET;
POST;
PUT;
DELETE.

Технически типов запросов больше четырех (например, еще есть HEAD, OPTIONS и CONNECT), но они редко используются в API и маловероятно, что когда-либо встретятся вам. Подавляющее большинство API ограничиваются этими четырьмя методами, а иногда даже какой-то их частью. Постоянно встречаются API, которые используют только GET или только GET и POST.

GET тот запрос, который вы используете, когда посещаете сайт, введя его адрес в адресной строке браузера. Обращаясь по адресу ip-api.com/json/50.78.253.58, вы применяете именно метод GET. Такой запрос можно представить как команду: Эй, веб-сервер, будь добр, выдай мне эту информацию.

Запрос GET по определению не вносит изменений в содержимое базы данных сервера. Ничего не сохраняется и ничего не изменяется. Информация только считывается.

POST запрос, который используется при заполнении формы или отправке информации, предположительно предназначенной для обработки серверным скриптом. Каждый раз, авторизуясь на сайте, вы делаете POST-запрос, передавая имя пользователя и (как мы надеемся) зашифрованный пароль. Делая POST-запрос через API, вы говорите серверу: Будь любезен, сохрани эту информацию в базе данных.

Запрос PUT при взаимодействии с сайтами используется реже, но время от времени встречается в API. Этот запрос применяется для изменения объекта или информации. Например, в API можно задействовать запрос POST для создания пользователя и запрос PUT для изменения его адреса электронной почты.

Запросы DELETE, как нетрудно догадаться, служит для удаления объекта. Например, если отправить запрос DELETE по адресу myapi.com/user/23, то будет удален пользователь с идентификатором 23. Методы DELETE нечасто встречаются в открытых API, поскольку те в основном создаются для распространения информации или чтобы позволить пользователям создавать или публиковать информацию, но не удалять ее из баз данных.

В отличие от GET запросы POST, PUT и DELETE позволяют передавать информацию в теле запроса, в дополнение к URL или маршруту, с которого запрашиваются данные.
Как и ответ, получаемый от веб-сервера, эти данные в теле запроса обычно представляются в формате JSON или реже в формате XML. Конкретный формат данных определяется синтаксисом API. Например, при использовании API, который добавляет комментарии к сообщениям в блоге, можно создать следующий PUT-запрос:

example.com/comments?post=123

с таким телом запроса:

{"title": "Great post about APIs!", "body": "Very informative. Really helped me out with a tricky technical challenge I was facing. Thanks for taking the time to write such a detailed blog post about PUT requests!", "author": {"name": "Ryan Mitchell", "website": "http://pythonscraping.com", "company": "O'Reilly Media"}}


Обратите внимание: идентификатор сообщения в блоге (123) передается в качестве параметра в URL, а контент создаваемого нами комментария в теле запроса. Параметры и данные могут передаваться и в параметре, и в теле запроса. Какие параметры обязательны и где передаются опять-таки определяется синтаксисом API.

Подробнее об ответах на API-запросы

Как мы видели в примере с сайтом ip-api.com в начале данной главы, важной особенностью API является то, что эти интерфейсы возвращают хорошо отформатированные ответы. Наиболее распространенные форматы ответов XML (eXtensible Markup Language расширяемый язык разметки) и JSON (JavaScript Object Notation нотация объектов JavaScript).

В последние годы JSON стал намного популярнее, чем XML, по нескольким основным причинам. Во-первых, файлы JSON обычно меньше, чем хорошо проработанные файлы XML. Сравните, например, следующие данные в формате XML, занимающие 98 символов:

<user><firstname>Ryan</firstname><lastname>Mitchell</lastname><username>Kludgist</username></user>

А теперь посмотрите на те же данные в формате JSON:

{"user":{"firstname":"Ryan","lastname":"Mitchell","username":"Kludgist"}}


Это всего 73 символа, на целых 36 % меньше, чем те же данные в формате XML.
Конечно, вероятен аргумент, что XML можно отформатировать так:

<user firstname="ryan" lastname="mitchell" username="Kludgist"></user>


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

Другая причина, по которой JSON так быстро становится более популярным, чем XML, связана с изменением веб-технологий. Раньше получателями API были по большей части серверные скрипты на PHP или .NET. Сейчас вполне может оказаться, что получать и отправлять вызовы API будет фреймворк наподобие Angular или Backbone. Серверным технологиям до определенной степени безразлично, в какой форме к ним поступают данные. Однако библиотекам JavaScript, таким как Backbone, проще обрабатывать JSON.

Принято считать, что API возвращают ответ либо в формате XML, либо в формате JSON, однако возможен любой другой вариант. Тип ответа API ограничен только воображением программиста, создавшего этот интерфейс. Еще один типичный формат ответа CSV (как видно из примера с ip-api.com). Отдельные API даже позволяют создавать файлы. Можно отправить на сервер запрос, по которому будет сгенерировано изображение с наложенным на него заданным текстом, или же запросить определенный файл XLSX или PDF.

Некоторые API вообще не возвращают ответа. Например, если отправить на сервер запрос для создания комментария к записи в блоге, то он может вернуть только HTTP-код ответа 200, что означает: Я опубликовал комментарий; все в порядке! Другие запросы могут возвращать минимальный ответ наподобие такого:

{"success": true}


В случае ошибки вы можете получить такой ответ:

{"error": {"message": "Something super bad happened"}}


Или же, если API не очень хорошо сконфигурирован, вы можете получить не поддающуюся анализу трассировку стека или некий текст на английском. Отправляя запрос к API, как правило, имеет смысл сначала убедиться, что получаемый ответ действительно имеет формат JSON (или XML, или CSV, или любой другой формат, который вы ожидаете получить).

Об авторе

Райан Митчелл (Ryan Mitchell) старший инженер-программист в бостонской компании HedgeServ, в которой она разрабатывает API и инструменты для анализа данных. Райан окончила Инженерно-технический колледж им. Франклина В. Олина, имеет степень магистра в области разработки программного обеспечения и сертификат по анализу и обработке данных, полученный на курсах повышения квалификации при Гарвардском университете. До прихода в HedgeServ Райан трудилась в компании Abine, где разрабатывала веб-скраперы и средства автоматизации на Python. Регулярно выступает консультантом проектов по веб-скрапингу для розничной торговли, сферы финансов и фармацевтики. По совместительству работает консультантом и внештатным преподавателем в Северо-Восточном университете и Инженерно-техническом колледже им. Франклина В. Олина.

Более подробно с книгой можно ознакомиться на сайте издательства
Оглавление
Отрывок

Для Хаброжителей скидка 25% по купону Python

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Подробнее..

Книга C 8 и .NET Core. Разработка и оптимизация

15.04.2021 12:10:33 | Автор: admin
image Привет, Хаброжители! В издании рассмотрены все темы, связанные с разработкой на C#. В начале книги вы ознакомитесь с основами C#, в том числе с объектно-ориентированным программированием, а также с новыми возможностями C# 8.0. Несколько глав посвящено .NET Standard API, применяемым для запроса данных и управления ими, отслеживания производительности и ее повышения, работы с файловой системой, асинхронными потоками, сериализацией и шифрованием. Кроме того, на примерах кроссплатформенных приложений вы сможете собрать и развернуть собственные. Например, веб-приложения с использованием ASP.NET Core или мобильные приложения на Xamarin Forms.

Также вы познакомитесь с технологиями, применяемыми при создании приложений Windows для ПК, в частности с Windows Forms, Windows Presentation Foundation (WPF) и Universal Windows Platform (UWP).

Улучшение производительности и масштабируемости с помощью многозадачности


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

В этой главе:

  • процессы, потоки и задачи;
  • мониторинг производительности и использования ресурсов;
  • асинхронное выполнение задач;
  • синхронизация доступа к общим ресурсам;
  • ключевые слова async и await.

Процессы, потоки и задачи


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

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

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

Потоки имеют свойства Priority и ThreadState. Кроме того, существует класс ThreadPool, предназначенный для управления пулом фоновых рабочих потоков, как показано на следующей схеме (рис. 13.1).

image

Если вы как разработчик имеете дело со сложными действиями, которые должны быть выполнены вашим кодом, и хотите получить полный контроль над ними, то можете создавать отдельные экземпляры класса Thread и управлять ими. При наличии одного основного потока и нескольких небольших действий, которые можно выполнять в фоновом режиме, вы можете добавить экземпляры делегатов, указывающие на эти фрагменты, реализованные в виде методов в очередь, и они будут автоматически распределены по потокам с помощью пула потоков.
Дополнительную информацию о пуле потоков можно получить на сайте docs.microsoft.com/ru-ru/dotnet/standard/threading/the-managed-thread-pool.

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

В зависимости от задачи удвоение количества потоков (рабочих) не уменьшает вдвое количество секунд, которое будет затрачено на выполнение задачи. Фактически это может даже увеличить длительность выполнения задачи, как показано на рис. 13.2.

image

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

Мониторинг производительности и использования ресурсов


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

Оценка эффективности типов


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

  • функциональность для принятия решения проверяется, предоставляет ли данный тип необходимую вам функциональность;
  • объем памяти для принятия решения проверяется, сколько байтов памяти потребляет данный тип;
  • производительность для принятия решения проверяется, насколько быстро работает данный тип;
  • потребности в будущем этот фактор зависит от возможных требований и возможности поддержки.

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

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

Если же необходимо сохранить только несколько чисел, но выполнить с ними большое количество операций, то лучше выбрать тип, который быстрее всего работает на конкретном ЦПУ.

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

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

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

В настоящее время оптимальным выбором может стать переменная short, но, вероятно, будет лучше задействовать переменную int, хотя она занимает в два раза больше места в памяти, ведь возможно, что в дальнейшем потребуется хранить более широкий диапазон значений.

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

Мониторинг производительности и использования памяти


В пространстве имен System.Diagnostics реализовано большое количество полезных типов для мониторинга вашего кода. В первую очередь следует рассмотреть тип Stopwatch.

1. Создайте в папке Code папку Chapter13 с двумя подпапками MonitoringLib и MonitoringApp.

2. В программе Visual Studio Code сохраните рабочую область как Chapter13.code-workspace.

3. Добавьте в рабочую область папку MonitoringLib, откройте для нее новую панель TERMINAL (Терминал) и создайте новый проект библиотеки классов, как показано в следующей команде:

dotnet new classlib

4. Добавьте в рабочую область папку MonitoringApp, откройте для нее новую панель TERMINAL (Терминал) и создайте новый проект консольного приложения, как показано в следующей команде:

dotnet new console

5. В проекте MonitoringLib переименуйте файл Class1.cs на Recorder.cs.

6. В проекте MonitoringApp найдите и откройте файл MonitoringApp.csproj и добавьте ссылку на библиотеку MonitoringLib, как показано ниже (выделено полужирным шрифтом):

<Project Sdk="Microsoft.NET.Sdk">   <PropertyGroup>      <OutputType>Exe</OutputType>      <TargetFramework>netcoreapp3.0</TargetFramework>   </PropertyGroup>   <ItemGroup>      <ProjectReference          Include="..\MonitoringLib\MonitoringLib.csproj" />      </ItemGroup></Project>

7. На панели TERMINAL (Терминал) скомпилируйте проекты, как показано в следующей команде:

dotnet build

Реализация класса Recorder


Тип Stopwatch содержит несколько полезных членов, как показано в табл. 13.1.

image

Тип Process содержит несколько полезных членов, перечисленных в табл. 13.2.

image

Для реализации класса Recorder мы будем использовать классы Stopwatch и Process.

1. Откройте файл Recorder.cs и измените его содержимое, чтобы задействовать экземпляр класса Stopwatch в целях записи времени и текущий экземпляр класса Process для записи использованной памяти, как показано ниже:

using System;using System.Diagnostics;using static System.Console;using static System.Diagnostics.Process;namespace Packt.Shared{   public static class Recorder{   static Stopwatch timer = new Stopwatch();   static long bytesPhysicalBefore = 0;   static long bytesVirtualBefore = 0;   public static void Start()   {      // очистка памяти, на которую больше нет ссылок,      // но которая еще не освобождена     GC.Collect();     GC.WaitForPendingFinalizers();     GC.Collect();     // сохранение текущего использования физической     // и виртуальной памяти     bytesPhysicalBefore = GetCurrentProcess().WorkingSet64;     bytesVirtualBefore = GetCurrentProcess().VirtualMemorySize64;     timer.Restart();   }   public static void Stop()   {     timer.Stop();     long bytesPhysicalAfter = GetCurrentProcess().WorkingSet64;     long bytesVirtualAfter =      GetCurrentProcess().VirtualMemorySize64;    WriteLine("{0:N0} physical bytes used.",       bytesPhysicalAfter - bytesPhysicalBefore);    WriteLine("{0:N0} virtual bytes used.",      bytesVirtualAfter - bytesVirtualBefore);    WriteLine("{0} time span ellapsed.", timer.Elapsed);     WriteLine("{0:N0} total milliseconds ellapsed.",       timer.ElapsedMilliseconds);   } }}

В методе Start класса Recorder используется сборщик мусора (garbage collector, класс GC), позволяющий нам гарантировать, что вся выделенная в настоящий момент память будет собрана до записи количества использованной памяти. Это сложная техника, и ее стоит избегать при разработке прикладной программы.

2. В классе Program в метод Main добавьте операторы для запуска и остановки класса Recorder при генерации массива из 10 000 целых чисел, как показано ниже:

using System.Linq;using Packt.Shared;using static System.Console;namespace MonitoringApp{    class Program    {      static void Main(string[] args)      {        WriteLine("Processing. Please wait...");        Recorder.Start();        // моделирование процесса, требующего ресурсов памяти...        int[] largeArrayOfInts =           Enumerable.Range(1, 10_000).ToArray();        // ...и занимает некоторое время, чтобы завершить        System.Threading.Thread.Sleep(           new Random().Next(5, 10) * 1000);        Recorder.Stop();      }   }}

3. Запустите консольное приложение и проанализируйте результат:

Processing. Please wait...655,360 physical bytes used.536,576 virtual bytes used.00:00:09.0038702 time span ellapsed.9,003 total milliseconds ellapsed

Измерение эффективности обработки строк

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

1. Закомментируйте предыдущий код в методе Main, обернув его символами /* и */.

2. Добавьте в метод Main следующий код. Он создает массив из 50 000 переменных int, а затем конкатенирует их, используя в качестве разделителей запятые, с помощью классов string и StringBuilder:

int[] numbers = Enumerable.Range(1, 50_000).ToArray();Recorder.Start();WriteLine("Using string with +");string s = "";for (int i = 0; i < numbers.Length; i++){   s += numbers[i] + ", ";}Recorder.Stop();Recorder.Start();WriteLine("Using StringBuilder");var builder = new System.Text.StringBuilder();for (int i = 0; i < numbers.Length; i++){   builder.Append(numbers[i]); builder.Append(", ");}Recorder.Stop();

3. Запустите консольное приложение и проанализируйте результат:

Using string with +11,231,232 physical bytes used.29,843,456 virtual bytes used.00:00:02.6908216 time span ellapsed.2,690 total milliseconds ellapsed.Using StringBuilder4,096 physical bytes used.0 virtual bytes used.00:00:00.0023091 time span ellapsed.2 total milliseconds ellapsed.

Исходя из результатов, мы можем сделать следующие выводы:

  • класс string вместе с оператором + использовал около 11 Мбайт физической памяти, 29 Мбайт виртуальной и занял по времени 2,7 с;
  • класс StringBuilder использовал 4 Кбайт физической памяти, 0 виртуальной и занял менее 2 мс.

В нашем случае при конкатенации текста класс StringBuilder выполняется примерно в 1000 раз быстрее и приблизительно в 10 000 раз эффективнее по затратам ресурсов памяти!
Избегайте использования метода String.Concat и оператора + внутри цикла. Вместо этого для конкатенации переменных, особенно в циклах, применяйте класс StringBuilder.

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

Об авторе


imageМарк Дж. Прайс обладатель сертификатов Microsoft Certified Trainer (MCT), Microsoft Specialist: Programming in C# и Microsoft Specialist: Architecting Microsoft Azure Infrastructure Solutions. За его плечами более 20 лет практики в области обучения и программирования.

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

В период с 2001 по 2003 год Марк посвящал все свое время разработке официального обучающего программного обеспечения в штаб-квартире Microsoft в американском городе Редмонд. В составе команды он написал первый обучающий курс по C#, когда была только выпущена ранняя альфа-версия языка. Во время сотрудничества с Microsoft он преподавал на курсах повышения квалификации сертифицированных корпорацией специалистов, читая лекции по C# и .NET.

В настоящее время Марк разрабатывает и поддерживает обучающие курсы для системы Digital Experience Platform компании Episerver, лучшей .NET CMS в сфере цифрового маркетинга и электронной коммерции.

В 2010 году Марк получил свидетельство об окончании последипломной программы обучения, дающее право на преподавание. Он преподает старшеклассникам математику в двух средних школах в Лондоне. Кроме того, Марк получил сертификат Computer Science BSc. Hons. Degree в Бристольском университете (Англия).

О научном редакторе


Дамир Арх профессионал с многолетним опытом разработки и сопровождения различного программного обеспечения: от сложных корпоративных программных проектов до современных потребительских мобильных приложений. Он работал со многими языками, однако его любимым остается C#. Стремясь к совершенствованию процессов, Дамир предпочитает разработку, основанную на тестировании, непрерывной интеграции и непрерывном развертывании. Он делится своими знаниями, выступая на конференциях, ведет блоги и пишет статьи. Дамир Арх семь раз подряд получал престижную премию Microsoft MVP за разработку технологий. В свободное время он всегда в движении: любит пеший туризм, геокэшинг, бег и скалолазание.

Более подробно с книгой можно ознакомиться на сайте издательства
Оглавление
Отрывок

Для Хаброжителей скидка 25% по купону .NET

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Подробнее..

Программируем на C 8.0. Атрибуты

18.06.2021 16:08:17 | Автор: admin
image Привет, Хабр! Обращаем ваше внимание на одну новинку (сдана в типографию), доступную уже сейчас для покупки в электронном виде.

Язык C# существует уже около двух десятилетий. Он неуклонно развивался и в плане возможностей, и в плане размера, но основные характеристики Microsoft всегда сохраняла без изменений. Каждая новая возможность должна идеально вписываться в состав предыдущих, улучшая язык, а не превращая его в несвязный набор различных функций.

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

Вашему внимаю предлагаю отрывок из книги.

Атрибуты


В .NET можно аннотировать компоненты, типы и их члены с помощью атрибутов. Назначение атрибута регулировать или изменять поведение платформы, инструмента, компилятора или CLR. Например, в главе 1 я демонстрировал класс, аннотированный атрибутом [TestClass]. Он сообщал инфраструктуре юнит-теста, что класс содержит ряд тестов, которые должны быть выполнены как часть набора тестов.

Атрибуты лишь содержат информацию, но ничего не делают сами по себе. Проведу аналогию с физическим миром. Если вы распечатываете этикетку, содержащую информацию о месте назначения и отслеживании, и прикрепляете ее к посылке, эта этикетка сама по себе не заставит посылку добраться до пункта назначения. Такая этикетка полезна только тогда, когда груз находится в обработке у транспортной компании. Когда компания заберет посылку, этикетка понадобится, чтобы определить, как и куда направить груз. Таким образом, этикетка важна, но ее единственной задачей является предоставление информации, которая требуется какой-либо системе. С атрибутами .NET все так же они работают только в том случае, если кто-то ожидает их найти. Некоторые атрибуты обрабатываются CLR или компилятором, но таких меньшинство. Большинство же используются платформами, библиотеками, инструментами (например, системами юнит-теста) или вашим собственным кодом.

Применение атрибутов

Во избежание необходимости вводить дополнительный набор понятий в систему типов .NET работает с ними как с экземплярами типов .NET. Для использования в качестве атрибута тип должен быть производным от класса System.Attribute, и это его единственная особенность. Чтобы применить атрибут, вы помещаете имя типа в квадратные скобки и, как правило, размещаете непосредственно перед целью атрибута. Листинг 14.1 показывает некоторые атрибуты из среды тестирования Microsoft. Один я применил к классу, чтобы указать, что он содержит тесты, которые я хотел бы запустить. Кроме этого, я применил атрибуты к отдельным методам, сообщая среде тестирования, какие из них представляют собой тесты, а какие содержат код инициализации, который должен выполняться перед каждым тестом.

Листинг 14.1. Атрибуты в классе юнит-теста

using Microsoft.VisualStudio.TestTools.UnitTesting;namespace ImageManagement.Tests{   [TestClass]   public class WhenPropertiesRetrieved   {      private ImageMetadataReader _reader;      [TestInitialize]      public void Initialize()      {         _reader = new ImageMetadataReader(TestFiles.GetImage());      }      [TestMethod]      public void ReportsCameraMaker()      {         Assert.AreEqual(_reader.CameraManufacturer, "Fabrikam");      }      [TestMethod]      public void ReportsCameraModel()      {          Assert.AreEqual(_reader.CameraModel, "Fabrikam F450D");      }   }}

Если вы заглянете в документацию по большинству атрибутов, вы обнаружите, что их настоящие имена оканчиваются на Attribute. Если нет класса с именем, указанным в скобках, компилятор C# попытается добавить Attribute, поэтому атрибут [TestClass] в листинге 14.1 ссылается на класс TestClassAttribute. Если хотите, вы можете записывать имя класса полностью, например [TestClassAttribute], но чаще используют более короткую форму.

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

Некоторые типы атрибутов способны принимать аргументы конструктора. Например, среда тестирования Microsoft содержит атрибут TestCategoryAttribute. При запуске можно выбрать выполнение только тех тестов, которые принадлежат определенной категории. Данный атрибут требует, чтобы вы передали имя категории в качестве аргумента конструктора, потому что нет смысла применять этот атрибут без указания имени. Синтаксис для указания аргументов конструктора атрибута вполне ожидаемый (листинг 14.2).

Листинг 14.2. Атрибут с аргументом конструктора

[TestCategory("Property Handling")][TestMethod]public void ReportsCameraMaker(){...

Вы также можете указать свойства или значения полей. Характеристиками некоторых атрибутов можно управлять только через свойства или поля, но не через аргументы конструктора. (Если атрибут имеет множество необязательных настроек, обычно проще представить их как свойства или поля вместо определения перегрузки конструктора для каждой возможной комбинации настроек.) Синтаксис заключается в одной или нескольких записях вида PropertyOrFieldName=Value после аргументов конструктора (или вместо них, если их нет). В листинге 14.3 показан другой атрибут, используемый в юнит-тестировании, ExpectedExceptionAttribute, позволяющий указать, что при выполнении теста вы ожидаете, что он выдаст конкретное исключение. Тип исключения является обязательным, поэтому мы передаем его в качестве аргумента конструктора, но данный атрибут позволяет также указать, должен ли исполнитель теста принимать исключения типа, производного от указанного. (По умолчанию он принимает только точное совпадение.) Это поведение управляется с помощью свойства AllowDerivedTypes.

Листинг 14.3. Указание необязательных настроек атрибута со свойствами

[ExpectedException(typeof(ArgumentException), AllowDerivedTypes = true)][TestMethod]public void ThrowsWhenNameMalformed(){...

Применение атрибута не ведет к его созданию. Все, что вы делаете при применении атрибута, это предоставляете инструкции о том, как атрибут должен быть создан и инициализирован, если он кому-то потребуется. (Бытует распространенное заблуждение, что атрибуты метода создаются при запуске метода. Это не так.) Когда компилятор создает метаданные для сборки, он включает информацию о том, какие атрибуты были применены к каким элементам, включая список аргументов конструктора и значения свойств, а CLR будет извлекать и использовать эту информацию, только если это кому-то понадобится. Например, когда вы говорите Visual Studio запустить ваши юнит-тесты, он загрузит вашу тестовую сборку, а затем для каждого открытого типа запросит у CLR все связанные с тестированием атрибуты. Это и есть та точка, в которой создаются атрибуты. Если просто загрузить сборку, скажем добавив ссылку на нее из другого проекта, а затем использовать некоторые из содержащихся в ней типов, то атрибуты создаваться не будут они останутся не более чем набором инструкций, затерянных в метаданных вашей сборки.

Цели атрибутов

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

В большинстве случаев вы обозначаете цель, просто помещая атрибут непосредственно перед ней. Но это не сработает в случае сборок или модулей, потому что в вашем исходном коде нет ничего, что бы их представляло, все в вашем проекте идет в сборку, которую он производит. Модули, в свою очередь, тоже являются совокупностью (как правило, составляя сборку, как я описал в главе 12). Поэтому для них мы должны явно указать цель в начале атрибута. Вы часто будете видеть атрибуты уровня сборки, подобные показанным в листинге 14.4, в файле GlobalSuppressions.cs. Visual Studio иногда предлагает варианты для изменения вашего кода, и если вы решите подавить этот функционал, это можно сделать с помощью атрибутов уровня сборки.

Листинг 14.4. Атрибуты уровня сборки

[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(   "StyleCop.CSharp.NamingRules",   "SA1313:Parameter names should begin with lower-case letter",   Justification = "Triple underscore acceptable for unused lambda parameter",   Scope = "member",   Target = "~M:Idg.Examples.SomeMethod")]

Атрибуты уровня модуля следуют той же схеме, хотя и встречаются гораздо реже. Не в последнюю очередь это происходит потому, что многомодульные сборки встречаются довольно редко и не поддерживаются .NET Core. В листинге 14.5 показано, как настроить возможность отладки конкретного модуля в том случае, если вы хотите, чтобы один модуль в многомодульной сборке был легко отлаживаемым, а остальные JIT-компилируемыми с полной оптимизацией. (Это специально придуманный сценарий, с помощью которого я могу показать синтаксис. На практике вы вряд ли захотите это делать.) Я расскажу об атрибуте DebuggableAttribute позже, в подразделе JIT-компиляция на с. 743.

Листинг 14.5. Атрибут уровня модуля

using System.Diagnostics;[module: Debuggable(DebuggableAttribute.DebuggingModes.DisableOptimizations)]

Возвращаемые значения методов могут быть аннотированы, и это также требует квалификации, потому что атрибуты возвращаемого значения располагаются перед методом, там же, где и атрибуты, которые применяются к самому методу. (Атрибуты для параметров не нуждаются в квалификации, потому что они располагаются в круглых скобках вместе с аргументами.) В листинге 14.6 показан метод с атрибутами, применяемыми как к методу, так и к типу возвращаемого значения. (Атрибуты в этом примере являются частью служб взаимодействия, которые позволяют коду .NET вызывать внешний код, такой как API ОС. В этом примере импортируется функция библиотеки Win32, что позволяет использовать ее из C#. Существует несколько различных представлений для логических значений в неуправляемом коде, поэтому в данном случае я аннотировал возвращаемый тип с помощью атрибута MarshalAsAttribute, указав, какой именно тип следует ожидать CLR.)

Оформить предзаказ бумажной книги можно на нашем сайте
Подробнее..

Книга Наглядный CSS

08.06.2021 14:19:38 | Автор: admin
image Привет, Хаброжители! На 1 июня 2018 года CSS содержал 415 уникальных свойств, относящихся к объекту style в любом элементе браузера Chrome. Сколько свойств доступно в вашем браузере на сегодняшний день? Наверняка уже почти шесть сотен. Наиболее важные из них мы и рассмотрим. Грег Сидельников упорядочил свойства по основной категории (положение, размерность, макеты, CSS-анимация и т. д.) и визуализировал их работу. Вместо бесконечных томов документации две с половиной сотни иллюстраций помогут вам разобраться во всех тонкостях работы CSS. Эта книга станет вашим настольным справочником, позволяя мгновенно перевести пожелания заказчика и собственное видение в компьютерный код!



Позиционирование


Тестовый элемент
image

Обратите внимание: на самом деле здесь три элемента. Во-первых, сам документ. Но теоретически это может быть html, или body, или любой другой родительский контейнер. Фактические стили будут применены к тестовому элементу в данном родительском контейнере. Данный образец в качестве примера будет использоваться в главе 6, касающейся позиции элемента.

Позиционирование элементов в CSS может зависеть от свойств родительского контейнера. Для представления различных вариантов данная конкретная настройка будет полезна без отображения полного сайта или макета приложения.

Доступно пять типов позиционирования: static (статичное) (по умолчанию), relative (относительное), absolute (абсолютное), fixed (фиксированное) и sticky (липкое). Мы рассмотрим их на протяжении всей этой главы.

По умолчанию для всех элементов используется статичное позиционирование:

image

Относительное позиционирование практически такое же, как и статичное:

image

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

На статично позиционированные элементы не влияют свойства top, left, right и bottom.

Чтобы понять разницу, создадим несколько основных стилей CSS:

001 /* Применить границу ко всем элементам <div> */002 div { border: 1px solid gray; }003004 /* Установить произвольные значения ширины и положения */005 #A { width: 100px; top: 25px; left: l00px; }006 #B { width: 215px; top: 50px; }007 #C { width: 250px; top: 50px; left:25px; }008 #D { width: 225px; top: 65px; }009 #E { width: 200px; top: 70px; left:50px; }

Граница 1px solid gray применена ко всем элементам div, поэтому теперь легче увидеть фактические размеры каждого HTML-элемента при отображении его в браузере.

Далее мы применим свойства position: static и position: relative к элементу div, чтобы увидеть разницу между статичным и относительным позиционированием.

image

По сути, элементы с позиционированием static и relative одинаковы, за исключением того, что элементы relative могут иметь top (верхнюю) и left (левую) позиции относительно их исходного местоположения. Относительные элементы также могут иметь right (правое) и bottom (нижнее) положение.

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

Следовательно, свойство position: relative не гарантирует полную точность при необходимости разместить элемент в идеальном месте в его родительском контейнере. Для такой цели больше всего подходит свойство position: absolute.

Абсолютное и фиксированное позиционирование

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

image

Это пример того, как элементы с позиционированием absolute и fixed схлопывают родительский элемент, если для родительского контейнера не заданы размеры. Это может казаться неважным, однако при верстке макетов вы часто будете сталкиваться с такими случаями, особенно при переключении элементов с позиционирования relative на absolute.

В данной главе мы рассмотрим более приближенные к реальности примеры.

Обратите внимание: если свойства width и height родителя не указаны явно, то применение позиционирования absolute (или fixed) к его единственному дочернему элементу преобразует его размеры в 0 0, однако данный элемент все равно будет позиционироваться относительно него:

image

На предыдущей схеме слева абсолютно позиционированные элементы не заполняют свой родительский контейнер содержимым. Они как бы плавают над ним, сохраняя положение относительно своего элемента-контейнера. Справа размеры родительского элемента заданы явно. Технически для потомка со свойством position: absolute не задан никакой эффект, его точка поворота все еще находится в положении 0 0 родительского элемента.

Чтобы элементы со свойством position: absolute были выровнены относительно их родителя, его свойство position не должно быть установлено в static (по умолчанию):

image

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

image

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

Использование свойства position: absolute для выравнивания элементов по углам родителя:

image

Изменить начальную точку, из которой будет рассчитываться смещение, можно, комбинируя положения top, left, bottom и right. Однако не получится одновременно использовать положения left и right, так же как и top и bottom. При таком применении один элемент перекроет другой.

Использование свойства position: absolute с отрицательными значениями:

image

Фиксированное позиционирование

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

Использование свойства position: fixed для размещения элементов в фиксированном месте на экране относительно документа:

image

Использование свойства position: fixed с отрицательными значениями:

image

Липкое позиционирование

Это позиционирование было одним из последних дополнений в CSS. Ранее для достижения того же эффекта вам приходилось писать собственный код JavaScript или мультимедийный запрос.
Липкое позиционирование часто используется для создания плавающих панелей навигации:

image

Далее приведен простой код, чтобы навигационная панель прилипала к верхней (top: 0) границе экрана. Обратите внимание: добавлен код -webkit-sticky для совместимости с браузерами на движке Webkit (такими как Chrome):

001 .navbar {002 /* Определение некоторых основных настроек */003 padding: 0px;004 border: 20px solid silver;005 background-color: white;006 /* Добавить липкость */007 position: -webkit-sticky;008 position: sticky;009 top: 0;010 }

Более подробно с книгой можно ознакомиться на сайте издательства
Оглавление
Отрывок

Для Хаброжителей скидка 25% по купону CSS

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Подробнее..

Книга Создаем динамические веб-сайты на PHP. 4-е межд. изд.

24.05.2021 18:21:26 | Автор: admin
image Привет, Хаброжители! Сложно найти что-то толковое про PHP? Проверенная временем, обновленная в четвертом издании, эта книга помогает начинающим разработчикам научиться всему, что необходимо для создания качественных веб-приложений.

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

Вы получите множество рекомендаций по стилю программирования и процессу разработки ПО от Кевина Татро и Питера Макинтайра. Этот материал, изложенный в доступной и компактной форме, поможет вам овладеть мастерством программирования на PHP. Общие сведения о том, какой результат можно получить, используя PHP. Основы языка, включая типы данных, переменные, операторы, управляющие команды. Функции, строки, массивы и объекты. Решение распространенных задач разработки: обработка форм, проверка данных, отслеживание сеансовых данных и cookie. Работа с реляционными базами данных (MySQL) и базами данных NoSQL (например MongoDB). Генерирование изображений, создание файлов PDF, парсинг файлов XML. Безопасность скриптов, обработка ошибок, оптимизация быстродействия и другие нетривиальные темы.

Для кого написана эта книга
PHP это плавильный котел для смешения направлений программирования. Веб-дизайнеры ценят его за доступность и удобство, а программистам нравится его гибкость, мощность, разнообразие и скорость. Обоим направлениям необходим понятный и точный справочник по языку. Если вы (веб-)программист, то эта книга написана для вас. Мы представим общую картину языка PHP, а затем изложим подробности, не отнимая у вас лишнего времени. Многочисленные примеры, практические рекомендации по программированию и советы по стилю помогут вам стать не просто программистом PHP, а хорошим программистом PHP.
Веб-дизайнеры оценят доступные и практичные рекомендации по использованию конкретных технологий: JSON, XML, сеансовых данных, генерирования PDF, работы с графикой и т. д. Описание PHP и базовые концепции программирования изложены в книге доступным языком.

Регулярные выражения


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

В PHP регулярные выражения применяются: для поиска совпадений (и извлечения информации из строк), для замены текста в соответствии с паттерном и для разбиения строк на массив меньших фрагментов. Функция preg_match() выполняет поиск регулярного выражения.

Perl давно считается эталонным языком для работы с регулярными выражениями. В PHP используется библиотека C pcre, обеспечивающая почти полную поддержку возможностей регулярных выражений Perl, которые работают с произвольными двоичными данными и позволяют безопасно выполнять поиск по паттернам или в строках, содержащих нулевой байт (\x00).

Большинство символов в регулярных выражениях являются литеральными, что отражается на поиске совпадений. Например, если вы ищете совпадение для регулярного выражения "/cow/" в строке Dave was a cowhand, то совпадение будет найдено, потому что последовательность символов cow встречается в этой строке.

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

preg_match("/^cow/", "Dave was a cowhand"); // возвращает falsepreg_match("/^cow/", "cowabunga!"); // возвращает true

Аналогичным образом символ $ в конце регулярного выражения означает, что совпадение должно завершаться в конце строки (то есть обозначает привязку регулярного выражения к концу строки).

preg_match("/cow$/", "Dave was a cowhand"); // возвращает falsepreg_match("/cow$/", "Don't have a cow"); // возвращает true

Точка в регулярном выражении обозначает один любой символ:

preg_match("/c.t/", "cat"); // возвращает truepreg_match("/c.t/", "cut"); // возвращает truepreg_match("/c.t/", "c t"); // возвращает truepreg_match("/c.t/", "bat"); // возвращает falsepreg_match("/c.t/", "ct"); // возвращает false

Чтобы обозначить совпадение для одного из этих специальных символов (метасимволов), экранируйте его с помощью обратного слеша:

preg_match("/\$5.00/", "Your bill is $5.00 exactly"); // возвращает truepreg_match("/$5.00/", "Your bill is $5.00 exactly"); // возвращает false

Регулярные выражения по умолчанию учитывают регистр символов, поэтому регулярное выражение "/cow/" не совпадет со строкой COW. Чтобы выполнить поиск совпадения символов без учета регистра, установите соответствующий флаг (показан далее в этой главе).

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

1. Набор допустимых символов, которые могут присутствовать в строке (например, алфавитные символы, цифры, конкретные знаки препинания).

2. Набор альтернатив для строки (например, com, edu, net или org).

3. Повторяющиеся последовательности в строке (например, как минимум одна, но не более пяти цифр).

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

Символьные классы

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

preg_match("/c[aeiou]t/", "I cut my hand"); // возвращает truepreg_match("/c[aeiou]t/", "This crusty cat"); // возвращает truepreg_match("/c[aeiou]t/", "What cart?"); // возвращает falsepreg_match("/c[aeiou]t/", "14ct gold"); // возвращает false

Движок регулярных выражений находит в строке символ c, после чего проверяет, является ли следующий символ гласной буквой (a, e, i, o или u). Если нет, то движок переходит к поиску следующего символа c. Если да, движок проверяет, является ли следующий символ буквой t. Если совпадение обнаружено, движок возвращает true или, в противном случае, возобновляет поиск следующего символа c.

Символьный класс можно инвертировать, поставив символ ^ в начало перечисления символов:

preg_match("/c[^aeiou]t/", "I cut my hand"); // возвращает falsepreg_match("/c[^aeiou]t/", "Reboot chthon"); // возвращает truepreg_match("/c[^aeiou]t/", "14ct gold"); // возвращает false

В этом случае движок регулярных выражений ищет символ c, за которым следует символ, не являющийся гласной буквой, после чего идет буква t.

Символ (дефис) в символьных классах используется для определения диапазонов символов. Он упрощает определение таких символьных классов, как все буквы и все цифры:

preg_match("/[0-9]%/", "we are 25% complete"); // возвращает truepreg_match("/[0123456789]%/", "we are 25% complete"); // возвращает truepreg_match("/[a-z]t/", "11th"); // возвращает falsepreg_match("/[a-z]t/", "cat"); // возвращает truepreg_match("/[a-z]t/", "PIT"); // возвращает falsepreg_match("/[a-zA-Z]!/", "11!"); // возвращает falsepreg_match("/[a-zA-Z]!/", "stop!"); // возвращает true

Когда вы задаете символьный класс, некоторые специальные символы теряют свой смысл, тогда как другие, наоборот, приобретают новые роли. Так, якорный символ $ и точка теряют свои роли в символьных классах, тогда как символ ^ уже не обозначает привязку к началу строки, а инвертирует символьный класс, если является первым символом после открывающей квадратной скобки. Например, [^\]] совпадает с любым символом, кроме закрывающей квадратной скобки, тогда как [$.^] совпадает с любым из трех знаков (доллар, точка или крышка).

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

Символ | (вертикальная черта) используется для определения альтернатив в регулярных выражениях:

preg_match("/cat|dog/", "the cat rubbed my legs"); // возвращает truepreg_match("/cat|dog/", "the dog rubbed my legs"); // возвращает truepreg_match("/cat|dog/", "the rabbit rubbed my legs"); // возвращает false

Приоритет применения альтернатив может показаться странным: так, "/^cat|dog$/" выбирает один из двух вариантов "^cat" и dog$. Это означает, что совпадение будет найдено в строке, которая либо начинается с cat, либо завершается dog. Если вам нужна строка, содержащая только cat или dog, используйте регулярное выражение "/^(cat|dog)$/".

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

preg_match("/^([a-z]|[0-9])/", "The quick brown fox"); // возвращает falsepreg_match("/^([a-z]|[0-9])/", "jumped over"); // возвращает truepreg_match("/^([a-z]|[0-9])/", "10 lazy dogs"); // возвращает true

Повторяющиеся последовательности

Для определения паттернов с повторениями используются квантификаторы. Квантификатор определяет, сколько раз выбранный фрагмент должен повториться. В табл. 4.6 перечислены квантификаторы, поддерживаемые регулярными выражениями PHP.

Чтобы искать повторы отдельного символа, просто поставьте квантификатор за символом:

preg_match("/ca+t/", "caaaaaaat"); // возвращает truepreg_match("/ca+t/", "ct"); // возвращает falsepreg_match("/ca?t/", "caaaaaaat"); // возвращает falsepreg_match("/ca*t/", "ct"); // возвращает true

image


С квантификаторами и символьными классами можно решать такие задачи, как проверка на действительность телефонных номеров США:

preg_match("/[0-9]{3}-[0-9]{3}-[0-9]{4}/", "303-555-1212"); // возвращает truepreg_match("/[0-9]{3}-[0-9]{3}-[0-9]{4}/", "64-9-555-1234"); // возвращает false

Подпаттерны

Части регулярных выражений можно группировать в круглых скобках, чтобы они рассматривались как единое целое, то есть подпаттерн:

preg_match("/a (very )+big dog/", "it was a very very big dog"); // возвращаетtruepreg_match("/^(cat|dog)$/", "cat"); // возвращает truepreg_match("/^(cat|dog)$/", "dog"); // возвращает true

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

preg_match("/([0-9]+)/", "You have 42 magic beans", $captured);// возвращает true и заполняет $captured

Нулевому элементу массива присваивается вся строка, в которой ведется поиск совпадений. В первом элементе хранится подстрока, совпавшая с первым подпаттерном (если совпадение обнаружено), во втором подстрока, совпавшая со вторым подпаттерном, и т. д.

Ограничители

Регулярные выражения в Perl эмулируют действия паттернов Perl, заимствуя из их синтаксиса ограничители. Чаще всего ограничителями выступают слеши (например, /паттерн/), реже любой неалфавитно-цифровой символ, кроме обратного слеша. В частности, это удобно при поиске совпадений для строк, содержащих слеши. Например, следующие вызовы эквивалентны:

preg_match("/\/usr\/local\//", "/usr/local/bin/perl"); // возвращает truepreg_match("#/usr/local/#", "/usr/local/bin/perl"); // возвращает true

Скобки круглые (), фигурные {}, квадратные [] и угловые <> тоже могут использоваться в качестве ограничителей паттернов:

preg_match("{/usr/local/}", "/usr/local/bin/perl"); // возвращает true

В разделе Флаги-модификаторы рассматриваются односимвольные модификаторы, которые можно разместить после закрывающего ограничителя для изменения поведения движка регулярных выражений. Очень полезен флаг x, который заставляет движок отсекать пробелы и комментарии, отмеченные #, из регулярных выражений перед поиском совпадения.

Следующие два паттерна эквивалентны, но второй читается намного проще:

'/([[:alpha:]]+)\s+\1/''/( # начать сохранение[[:alpha:]]+ # слово\s+ # пробел\1 # снова то же слово) # завершить сохранение/x'

Поведение при поиске совпадения

Точка. совпадает с любым символом, кроме символа новой строки (\n). Знак $ совпадает с концом строки или, если строка завершается символом новой строки, с позицией, непосредственно предшествующей этому символу:

preg_match("/is (.*)$/", "the key is in my pants", $captured);// $captured[1] содержит 'in my pants'

Символьные классы

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

image

image

Каждый класс [: что-то :] может использоваться вместо символа в символьном классе. Например, для нахождения любого символа, который является цифрой, буквой верхнего регистра или символом @, используйте следующее регулярное выражение:

[@[:digit:][:upper:]]

Однако символьный класс не может использоваться как конечная точка диапазона:
preg_match("/[A-[:lower:]]/", string);// недопустимое регулярное выражение
Символьная последовательность, которая в локальном контексте рассматривается как один символ, называется сверткой. Чтобы найти совпадение для одной из многосимвольных последовательностей в символьном классе, заключите ее в маркеры [. и .]. Например, если в локальном контексте присутствует свертка ch, следующий символьный класс будет совпадать с s, t или ch:

[st[.ch.]]

Последнее расширение символьных классов класс эквивалентности, для определения которого символы заключаются в [= и =]. Классы эквивалентности совпадают с символами, имеющими одинаковый приоритет упорядочения по правилам локального контекста. Например, локальный контекст может определять, что символы a, и имеют одинаковый приоритет упорядочения при сортировке. Чтобы найти совпадение для любого из них, используйте класс эквивалентности [=a=].

Более подробно с книгой можно ознакомиться на сайте издательства
Оглавление
Отрывок

Для Хаброжителей скидка 25% по купону PHP

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Подробнее..

Как понять, что пришел переломный момент в бизнесе или карьере

23.04.2021 00:07:18 | Автор: admin

В начале карьеры у меня не было проблем c формированием плана развития. Я выбирал релевантные моим целям сертификации, анализировал список тем и вопросов, на основе которых составлял себе план. После получения бизнес образования EMBA, старый проверенный метод перестал работать.На смену пришел длинный список рекомендованной литературы.

Со временем я понял, что недостаточно бездумно "проглатывать" очередную книгу. В идеале - применять полученные знания. Еще лучше - резюмировать, полученный опыт. Так появились статьи на хабре по мотивам книг "Смерть от совещаний" и "Проект Феникс".

Что же делать с теми книгами, которые еще не успел применить? Появилась идея "закреплять" прочитанное в виде саммари основных идей книги. Я решил начать делиться такими саммари с вами. Буду рад, обратной связи и надеюсь, они будут вам полезны.

В этом посте я предлагаю вашему вниманию книгу Энди Гроува, CEO Intel, "Выживают только параноики".

Основная мысль книги: в бизнесе или в карьере рано или поздно наступает "переломный" момент. Если после его наступления не сможете измениться, то скорее всего это будет конец вашей компании и/или карьеры.

Энди Гроув описывает кризис в Intel, когда японские конкуренты "отжимали" у компании рынок. Трагичность ситуации в том, что руководители компании не замечают изменений первыми. Точнее сказать, они узнают о таких изменениях последними. Руководители не видят предвестников изменений. Их замечают люди на "передовой", но не всегда могут "достучаться" до руководителей.

Мои примеры: Японские производители техники и автомобилей "щемили" компании из штатов, Netflix "отжал" рынок у Blockbuster, Viber потеснил Skype, и вместе с другими мессенджерами они убили рынок международных звонков.

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

Важно анализировать шесть сил или направлений:

  • Покупатели - те, для кого ваш продукт или услуга представляет ценность. Даже больше - они готовы за это платить;

  • Поставщики - те, без которых вы не можете производить свой продукт или услугу. Так, поставщиками онлайн кинотеатров будут правообладатели и интернет провайдеры;

  • Внутриотраслевая конкуренция - ваши прямые конкуренты. Они предоставляют аналогичный товар или услугу;

  • Новые конкуренты - тут рассматриваются потенциальные конкуренты, которые могут выйти на рынок. Так, благодаря современным технологиям фрилансер из любой страны может с минимальными затратами составить конкуренцию местным специалистам;

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

  • Сопряженные компании - те, кто помогают продавать товар. Их бизнес связан с вашим. Для продавца процессоров - производитель компьютеров.

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

  • У поставщиков появится другой, более выгодный рынок сбыта, и они пересмотрят цены для вас или не смогут обеспечить требуемый вами уровень сервиса;

  • Конкуренты станут и дешевле и лучше одновременно;

  • Покупатели потеряют интерес к вашему товару, потому что появится более интересный им товар-заменитель.

Мало осознать, что грядут изменения, нужно принять решение измениться. Тяжело что-то менять, пока текущая модель все еще приносит вам прибыль. С другой стороны, когда вас "уволит" клиент - будет уже поздно. Велик шанс потерять все, и тогда придется начинать все с нуля. В идеале, нужно меняться еще до того, как настанет "переломный" момент. Тогда старая бизнес модель будет топливом для новой. Чтобы принять непростое решение, попробуйте представить, что вы увольняетесь, а на ваше место приходит новый руководитель. Что бы он сделал?

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

Как можно понять, что скоро произойдет переломный момент?

Автор предлагает не ждать и налаживать информационные каналы, которые помогут выявить "триггеры" :

  • наладить поставку информации с "передовой" без искажений;

  • иметь в поле зрения компании-конкуренты;

  • отслеживать технологические изменения;

  • следить за изменениями поведения клиентов;

  • плотнее общаться с сопряженными компаниями.

В качестве заключения Энди Гроув предлагает сравнить себя и свою карьеру с компанией. Тут есть над чем задуматься.

Для себя я выбрал следующие информационные каналы:

  • прошу обратную связь у ребят, с которыми работаю;

  • составил к прочтению список автобиографий успешных руководителей;

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

  • вступил в сообщество руководителей для обмена опытом.

Какие информационные каналы используете вы?

Подробнее..

Книга Роман с Data Science. Как монетизировать большие данные

31.03.2021 12:04:48 | Автор: admin
image Привет, Хаброжители! Мы сдали в типографию новую книгу Романа Зыкова rzykov. Она предназначена для думающих читателей, которые хотят попробовать свои силы в области анализа данных и создавать сервисы на их основе. Она будет вам полезна, если вы менеджер, который хочет ставить задачи аналитике и управлять ею. Если вы инвестор, с ней вам будет легче понять потенциал стартапа. Те, кто пилит свой стартап, найдут здесь рекомендации, как выбрать подходящие технологии и набрать команду. А начинающим специалистам книга поможет расширить кругозор и начать применять практики, о которых они раньше не задумывались, и это выделит их среди профессионалов такой непростой и изменчивой области.


Отрывок из книги


ОТЧЕТ, ДАШБОРД И МЕТРИКИ


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

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

Первые два относительно просты и делаются через специальные системы, которые могут генерировать отчеты по запросу. Я стараюсь максимально оставить эту задачу на откуп пользователям. Почему? Потому, что тратить на это время высококвалифицированных сотрудников значит стрелять из пушки по воробьям. Кстати, этим могут заняться стажеры-аналитики отличный способ наработать опыт и понять бизнес-контекст. Как мотивировать пользователей стараться самостоятельно? Во-первых, они сэкономят время, которое обычно тратят на постановку задачи и ожидание результата. Во-вторых, получат возможность самим вносить правки и изменения а значит творить. По моему опыту, обычно этим занимаются очень перспективные сотрудники, которые не бояться освоить новый инструмент, чтобы делать свою работу лучше. Остальным придется пройти через стандартный цикл планирования задач: а это время (дни, а иногда недели) и очень четкая формулировка технического задания. И кстати, все генеральные директора (Ozon.ru, Wikimart.ru, Ostrovok), с которыми я работал, пользовались OLAP-кубами со своих компьютеров. С их помощью они всегда могли ответить на простые вопросы, а если не получалось обращались к аналитикам.

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

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

  • Ключевой показатель (key performance indicator, KPI) это индикатор, который показывает, насколько далеко мы находимся от цели, например отставание/опережение плана.
  • Метрика это цифра, которая характеризует процесс, обычно используется как справочная информация.

Главное различие между метрикой и ключевым показателем наличие цели. В ключевых показателях она есть, в метриках обычно нет. Как правило, ключевые показатели используются в дашбордах компаний, где уже и продукт, и бизнес-процесс устоялись. Уже накоплено некоторое множество данных, что делает возможным прогнозирование целей. Метрики я обычно вношу туда, где нет достаточно устойчивых процессов. Их обычно ставят, когда цель пока не прогнозируема. Зрелость дашборда можно определить по соотношению количества ключевых показателей и метрик: чем метрик больше, тем более незрелый дашборд мы получаем на выходе.

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

  • не является простыней цифр;
  • показывает, где возникла проблема, но не дает ответа на вопрос почему.

Часто велико искушение сделать огромную простыню цифр, закрывающую все аспекты бизнеса. И я понимаю владельцев/менеджеров компаний на старте проекта по построению внутренней аналитической системы всегда хочется большего. Я наблюдал это и в Ozon.ru, и в Ostrovok.ru. К слову, эти строки написаны по мотивам письма, которое я писал восемь лет назад операционному директору Ostrovok.ru, он хотел получить от аналитиков ту самую простыню. А я считаю такое цифровым микроменеджментом, в нем легко запутаться, самые важные показатели похоронены среди второстепенных. С первого взгляда будет сложно понять, где возникла проблема, а это основная функция дашбордов. Бороться с этим можно, например, через внедрение OKR цели и ключевые результаты (Objectives and Key Results) [13] или системы сбалансированных показателей (Balanced Scorecard). В этой книге я не буду подробно останавливаться на этих методиках, но рекомендую вам с ними ознакомиться. Также можно чаще пользоваться графическими элементами, например, добавив на график линию тренда (с помощью семиточечного скользящего среднего, чтобы убрать недельную сезонность), будет легче заметить восходящий или нисходящий тренд.

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

Никакой дашборд не заменит интерактивный анализ, для которого нужны соответствующая аналитическая система (SQL, OLAP, Google Data Studio, Tableau) и знание контекста. Мы никогда не сможем придумать ограниченный набор отчетов, которые будут отвечать на вопрос почему. Максимум, что мы можем сделать, наращивать (но не слишком) объем правильных метрик, исходя из инцидентов, за которыми будем следить.

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

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

КОНФЛИКТ ИССЛЕДОВАТЕЛЯ И БИЗНЕСА


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

Я много раз проводил собеседования и с новичками, и с опытными людьми, и знаю, что поиск интересной работы главный тренд на рынке труда. Действующие специалисты говорят: Надоело заниматься рутиной и всякой ерундой, хочу заниматься моделями машинного обучения. Новички: Хочу заниматься компьютерным зрением и NLP (машинное обучение в лингвистике). В целом людей объединяет любовь к машинному обучению, но для меня это звучит как любовь строителя к молотку, который пытается построить дом лишь с его помощью.

Эндрю н (Andrew Ng), которого я считаю одним из главных исследователей и популяризаторов машинного обучения, автор моего любимого курса на Coursera, в своей рассылке deeplearning.ai писал:
Существует огромная разница между построением модели в блокноте Python (Jupyter Notebook) на компьютере в лаборатории и созданием реально работающих систем, которые создают ценность. Кажется, что сфера AI переполнена людьми, но по факту она широко открыта для профессионалов, которые знают, что делают.

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

Ноа Лоранг, аналитик данных из компании Basecamp, в своем блоге пишет:
Маленькая грязная тайна продолжающегося бума data science в том, что то, что обычно подразумевается под этим на самом деле, не нужно бизнесу. Бизнесу нужна точная и полезная информация для принятия решений: как тратить время и ресурсы компании. Очень небольшое подмножество задач в бизнесе может быть лучшим образом решено машинным обучением; большинство же из них нуждается в хороших данных и понимании их смысла, что может быть достигнуто простыми методами.

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

ОБ АВТОРЕ

Роман Владимирович Зыков, 1981 года рождения, в 2004 году получил степень бакалавра, а затем магистра прикладной физики и математики в МФТИ (Московском физико-техническом институте).

В 2002 году начал свой карьерный путь в аналитике данных (Data Science) в качестве технического консультанта в компании StatSoft Russia, российского офиса одноименной американской компании-разработчика пакета статистического анализа данных STATISTICA.

В 2004 году был принят на должность руководителя аналитического отдела интернет-магазина Ozon.ru, где создавал аналитические системы с нуля, в том числе веб-аналитику, аналитику баз данных, управленческую отчетность, внес вклад в систему рекомендаций.

В 2009 году консультировал ряд проектов инвестиционного фонда Fast Lane Ventures и гейм-индустрии.

В 2010 году возглавил отдел аналитики в интернет-ритейлере Wikimart.ru.

В конце 2012 года стал сооснователем и совладельцем маркетинговой платформы для интернет-магазинов RetailRocket.ru. Компания Retail Rocket занимает лидирующие позиции автоматизации маркетинга для интернет-магазинов. Среди клиентов: Сбер, Детский мир, Oysho, Decathlon. На текущий момент компания является безусловным лидером на рынке в России и успешно работает на рынках Чили, Голландии, Испании и других.

С 2007-го вел блог Аналитика на практике (KPIs.ru ныне не существует), где евангелизировал анализ данных в применении к бизнес-задачам в электронной коммерции. Выступал на отраслевых конференциях, таких как РИФ, iMetrics, Gec 2014 вместе с Аркадием Воложем (Yandex), бизнес-конференциях в Дублине и Лондоне, в посольстве США (AMC Center), университете Сбербанка. Печатался в технологическом прогнозе PwC, ToWave, Ведомостях, Секрете фирмы.

В 2016 году прочитал мини-лекцию в концертном зале MIT в Бостоне о процессах тестирования гипотез.

В 2020 году был номинирован на премию CDO Award.

Опыт работы аналитиком данных 18 лет.

Оформить предзаказ.
Подробнее..

Книга Работа с ядром Windows

06.04.2021 14:13:41 | Автор: admin
image Привет, Хаброжители! Ядро Windows таит в себе большую силу. Но как заставить ее работать? Павел Йосифович поможет вам справиться с этой сложной задачей: пояснения и примеры кода превратят концепции и сложные сценарии в пошаговые инструкции, доступные даже начинающим.

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

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

Глава 8


Уведомления потоков и процессов


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

В этой главе:

  • Уведомления процессов
  • Реализация уведомления процессов
  • Передача данных в пользовательский режим
  • Уведомления потоков
  • Уведомления о загрузке образов
  • Упражнения

Уведомления процессов


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

При создании процесса драйвер также получает возможность остановить создание процесса и вернуть ошибку стороне, инициировавшей создание процесса. Эта возможность доступна только в режиме ядра.
Windows предоставляет другие механизмы уведомления о создании или уничтожении процессов. Например, с механизмом ETW (Event Tracing for Windows) такие уведомления могут приниматься процессами пользовательского режима (работающими с повышенными привилегиями). Впрочем, предотвратить создание процесса при этом не удастся. Более того, у ETW существует внутренняя задержка уведомлений около 13 секунд (по причинам, связанным с быстродействием), так что процесс с коротким жизненным циклом может завершиться до получения уведомления. Если в этот момент будет сделана попытка открыть дескриптор для созданного процесса, произойдет ошибка.

Основная функция API для регистрации уведомлений процессов PsCreateSetProcessNotifyRoutineEx определяется так:

NTSTATUSPsSetCreateProcessNotifyRoutineEx (    _In_ PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine,    _In_ BOOLEAN Remove);

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

В первом аргументе передается функция обратного вызова драйвера, прототип которой выглядит так:

typedef void(*PCREATE_PROCESS_NOTIFY_ROUTINE_EX) (    _Inout_ PEPROCESS Process,    _In_ HANDLE ProcessId,    _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo);

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

Аргументы функции уведомления:

  • Process объект создаваемого или уничтожаемого процесса.
  • ProcessId уникальный идентификатор процесса. Хотя аргумент объявлен с типом HANDLE, на самом деле это идентификатор.
  • CreateInfo структура с подробной информацией о создаваемом процессе. Если процесс уничтожается, то этот аргумент равен NULL.

При создании процесса функция обратного вызова драйвера выполняется создающим потоком. При выходе из процесса функция обратного вызова выполняется последним потоком, выходящим из процесса. В обоих случаях обратный вызов вызывается в критической секции (с блокировкой нормальных APC-вызовов режима ядра).
В Windows 10 версии 1607 появилась другая функция для уведомлений процессов: PsCreateSetProcessNotifyRoutineEx2. Эта расширенная функция создает обратный вызов, сходный с предыдущим, но обратный вызов также активизируется для процессов Pico. Процессы Pico используются хост-процессами Linux для WSL (Windows Subsystem for Linux). Если драйвер заинтересован в таких процессах, он должен регистрироваться с расширенной функцией.

У драйвера, использующего эти обратные вызовы, должен быть установлен флаг IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY в заголовке PE (Portable Executable). Без установки флага вызов функции регистрации возвращает STATUS_ACCESS_DENIED (значение не имеет отношения к режиму тестовой подписи драйверов). В настоящее время Visual Studio не предоставляет пользовательского интерфейса для установки этого флага. Он должен задаваться в параметрах командной строки компоновщика ключом /integritycheck. На рис. 8.1 показаны свойства проекта при указании этого ключа.

image

Структура данных, предоставляемая для создания процесса, определяется следующим образом:

typedef struct _PS_CREATE_NOTIFY_INFO {   _In_ SIZE_T Size;   union {       _In_ ULONG Flags;       struct {            _In_ ULONG FileOpenNameAvailable : 1;            _In_ ULONG IsSubsystemProcess : 1;            _In_ ULONG Reserved : 30;        };     };     _In_ HANDLE ParentProcessId;     _In_ CLIENT_ID CreatingThreadId;     _Inout_ struct _FILE_OBJECT *FileObject;     _In_ PCUNICODE_STRING ImageFileName;     _In_opt_ PCUNICODE_STRING CommandLine;     _Inout_ NTSTATUS CreationStatus;} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;

Описание важнейших полей этой структуры:

  • CreatingThreadId комбинация идентификаторов потока и процесса, вызывающего функцию создания процесса.
  • ParentProcessId идентификатор родительского процесса (не дескриптор). Этот процесс может быть тем же, который предоставляется CreateThreadId.UniqueProcess, но может быть и другим, так как при создании процесса может быть передан другой родитель, от которого будут наследоваться некоторые свойства.
  • ImageFileName имя файла с исполняемым образом; доступен при установленном флаге FileOpenNameAvailable.
  • CommandLine полная командная строка, используемая для создания процесса. Учтите, что он может быть равен NULL.
  • IsSubsystemProcess этот флаг устанавливается, если процесс является процессом Pico. Это возможно только в том случае, если драйвер регистрируется PsCreateSetProcessNotifyRoutineEx2.
  • CreationStatus статус, который будет возвращен вызывающей стороне. Драйвер может остановить создание процесса, поместив в это поле статус ошибки (например, STATUS_ACCESS_DENIED).

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

Реализация уведомлений процессов


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

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

Собранные данные должны быть переданы в пользовательский режим, поэтому мы должны объявить стандартные структуры, которые будут строиться драйвером и получаться клиентом пользовательского режима. Мы добавим в проект драйвера стандартный заголовочный файл с именем SysMonCommon.h и определим несколько структур. Начнем со стандартного заголовка для всех информационных структур, который определяется следующим образом:

enum class ItemType : short {    None,    ProcessCreate,    ProcessExit};struct ItemHeader {    ItemType Type;    USHORT Size;    LARGE_INTEGER Time;};

Приведенное выше определение перечисления ItemType использует новую возможность C++ 11 перечисления с областью видимости (scoped enums). В таких перечислениях значения имеют область видимости (ItemType в данном случае). Также размер этих перечислений может быть отличен от int short в данном случае. Если вы работаете на C, используйте классические перечисления или даже #define.

Структура ItemHeader содержит информацию, общую для всех типов событий: тип события, время события (выраженное в виде 64-разрядного целого числа) и размер полезных данных. Размер важен, так как каждое событие имеет собственную информацию. Если позднее вы захотите упаковать массив таких событий и (допустим) предоставить его клиенту пользовательского режима, клиент должен знать, где заканчивается каждое событие и начинается новое.

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

struct ProcessExitInfo : ItemHeader {    ULONG ProcessId;};

Для события выхода из процесса существует только один интересный фрагмент информации (кроме заголовка) идентификатор завершаемого процесса.
Если вы работаете на C, наследование вам недоступно. Впрочем, его можно имитировать создайте первое поле типа ItemHeader, а затем добавьте конкретные поля; структура памяти остается одинаковой.

struct ExitProcessInfo {    ItemHeader Header;    ULONG ProcessId;};

Для идентификатора процесса используется тип ULONG. Использовать тип HANDLE не рекомендуется, так как в пользовательском режиме он может создать проблемы. Кроме того, тип DWORD не используется, хотя в заголовках пользовательского режима тип DWORD (32-разрядное целое без знака) встречается часто. В заголовках WDK тип DWORD не определен. И хотя определить его явно нетрудно, лучше использовать тип ULONG он означает то же самое, но определяется в заголовках как пользовательского режима, так и режима ядра.


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

В новом файле с именем SysMon.h определяется параметризованная структура, в которой хранится поле LIST_ENTRY с основной структурой данных:

template<typename T>struct FullItem {    LIST_ENTRY Entry;    T Data;};

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

struct FullProcessExitInfo {     LIST_ENTRY Entry;     ProcessExitInfo Data;};

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

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

Заголовок связанного списка должен где-то храниться. Мы создадим структуру данных для хранения всего глобального состояния драйвера (вместо набора отдельных переменных). Определение структуры выглядит так:

struct Globals {    LIST_ENTRY ItemsHead;    int ItemCount;    FastMutex Mutex;};


В определении используется тип FastMutex, который был разработан в главе 6. Также в определении встречается RAII-обертка AutoLock на C++ (тоже из главы 6).

Функция DriverEntry


Функция DriverEntry для драйвера SysMon похожа на одноименную функцию драйвера Zero из главы 7. В нее нужно добавить регистрацию уведомлений процессов и инициализацию объекта Globals:

Globals g_Globals;extern "C" NTSTATUSDriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING) {    auto status = STATUS_SUCCESS;    InitializeListHead(&g_Globals.ItemsHead);    g_Globals.Mutex.Init();    PDEVICE_OBJECT DeviceObject = nullptr;    UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\??\\sysmon");    bool symLinkCreated = false;    do {        UNICODE_STRING devName = RTL_CONSTANT_STRING(L"\\Device\\sysmon");        status = IoCreateDevice(DriverObject, 0, &devName,            FILE_DEVICE_UNKNOWN, 0, TRUE, &DeviceObject);        if (!NT_SUCCESS(status)) {            KdPrint((DRIVER_PREFIX "failed to create device (0x%08X)\n",               status));               break;          }           DeviceObject->Flags |= DO_DIRECT_IO;          status = IoCreateSymbolicLink(&symLink, &devName);          if (!NT_SUCCESS(status)) {              KdPrint((DRIVER_PREFIX "failed to create sym link (0x%08X)\n",                 status));              break;          }          symLinkCreated = true;          // Регистрация для уведомлений процессов          status = PsSetCreateProcessNotifyRoutineEx(OnProcessNotify, FALSE);          if (!NT_SUCCESS(status)) {              KdPrint((DRIVER_PREFIX "failed to register process callback\ (0x%08X)\n",              status));          break;         }    } while (false);    if (!NT_SUCCESS(status)) {        if (symLinkCreated)             IoDeleteSymbolicLink(&symLink);        if (DeviceObject)             IoDeleteDevice(DeviceObject);     }     DriverObject->DriverUnload = SysMonUnload;     DriverObject->MajorFunction[IRP_MJ_CREATE] =     DriverObject->MajorFunction[IRP_MJ_CLOSE] = SysMonCreateClose;     DriverObject->MajorFunction[IRP_MJ_READ] = SysMonRead;     return status;}

Функция диспетчеризации для чтения позднее будет использоваться для возвращения информации о событиях пользовательскому режиму.

Обработка уведомлений о выходе из процессов


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

void OnProcessNotify(PEPROCESS Process, HANDLE ProcessId,    PPS_CREATE_NOTIFY_INFO CreateInfo) {    if (CreateInfo) {       // Создание процесса    }    else {      // Завершение процесса    }}

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

auto info = (FullItem<ProcessExitInfo>*)ExAllocatePoolWithTag(PagedPool,   sizeof(FullItem<ProcessExitInfo>), DRIVER_TAG);if (info == nullptr) {   KdPrint((DRIVER_PREFIX "failed allocation\n"));   return;}

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

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

auto& item = info->Data;KeQuerySystemTimePrecise(&item.Time);item.Type = ItemType::ProcessExit;item.ProcessId = HandleToULong(ProcessId);item.Size = sizeof(ProcessExitInfo);PushItem(&info->Entry);

Сначала мы обращаемся к самому элементу данных (в обход LIST_ENTRY) через переменную info. Затем заполняется информация заголовка: тип элемента хорошо известен, так как текущей является ветвь, обрабатывающая уведомления о завершении процессов; время можно получить при помощи функции KeQuerySystemTimePrecise, возвращающей текущее системное время (UTC, не местное время) в формате 64-разрядного целого числа, с отчетом от 1 января 1601 года. Наконец, размер элемента величина постоянная, равная размеру структуры данных, предоставляемой пользователю (а не размеру FullItem).
Функция API KeQuerySystemTimePrecise появилась в Windows 8. В более ранних версиях следует использовать функцию API KeQuerySystemTime.

Дополнительные данные при завершении процесса состоят из идентификатора процесса. В коде используется функция HandleToULong для корректного преобразования объекта HANDLE в 32-разрядное целое без знака.

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

void PushItem(LIST_ENTRY* entry) {    AutoLock<FastMutex> lock(g_Globals.Mutex);    if (g_Globals.ItemCount > 1024) {       // Слишком много элементов, удалить самый старый       auto head = RemoveHeadList(&g_Globals.ItemsHead);       g_Globals.ItemCount--;       auto item = CONTAINING_RECORD(head, FullItem<ItemHeader>, Entry);       ExFreePool(item);     }     InsertTailList(&g_Globals.ItemsHead, entry);     g_Globals.ItemCount++;}

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

Кроме того, драйвер ограничивает количество элементов связного списка. Такая предосторожность необходима, потому что ничто не гарантирует, что клиент будет быстро потреблять эти события. Драйвер не должен допускать неограниченное потребление данных, так как это может повредить системе в целом. Значение 1024 выбрано совершенно произвольно. Правильнее было бы читать это число из раздела драйвера в реестре.
Реализуйте это ограничение с чтением из реестра в DriverEntry. Подсказка: используйте такие функции API, как ZwOpenKey или IoOpenDeviceRegistryKey, а также ZwQueryValueKey.

Если счетчик элементов превысил максимальное значение, самый старый элемент удаляется; фактически связанный список рассматривается как очередь (RemoveHeadList). При освобождении элемента его память должна быть освобождена. Указателем на элемент не обязательно должен быть указатель, изначально использованный для выделения памяти (хотя в данном случае это так, потому что объект LIST_ENTRY стоит на первом месте в структуре FullItem<>), поэтому для получения начального адреса объекта FullItem<> используется макрос CONTAINING_RECORD. Теперь элемент можно освободить вызовом ExFreePool.

На рис. 8.2 изображена структура объектов FullItem.

image


Наконец, драйвер вызывает InsertTailList, чтобы добавить элемент в конец списка, а счетчик элементов увеличивается на 1.
Использовать атомарные операции инкремента/декремента в функции PushItem не обязательно, потому что операции со счетчиком элементов всегда выполняются под защитой быстрого мьютекса.

Обработка уведомлений о создании процессов


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

struct ProcessCreateInfo : ItemHeader {    ULONG ProcessId;    ULONG ParentProcessId;    WCHAR CommandLine[1024];};

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

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

А можно ли использовать решение следующего вида:

struct ProcessCreateInfo : ItemHeader {    ULONG ProcessId;    ULONG ParentProcessId;    UNICODE_STRING CommandLine; // Будет работать?};

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

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

struct ProcessCreateInfo : ItemHeader {     ULONG ProcessId;     ULONG ParentProcessId;     USHORT CommandLineLength;     USHORT CommandLineOffset;};

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

С таким объявлением можно приступить к построению реализации для создания процесса:

USHORT allocSize = sizeof(FullItem<ProcessCreateInfo>);USHORT commandLineSize = 0;if (CreateInfo->CommandLine) {    commandLineSize = CreateInfo->CommandLine->Length;    allocSize += commandLineSize;}auto info = (FullItem<ProcessCreateInfo>*)ExAllocatePoolWithTag(PagedPool,    allocSize, DRIVER_TAG);if (info == nullptr) {    KdPrint((DRIVER_PREFIX "failed allocation\n"));return;}

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

auto& item = info->Data;KeQuerySystemTimePrecise(&item.Time);item.Type = ItemType::ProcessCreate;item.Size = sizeof(ProcessCreateInfo) + commandLineSize;item.ProcessId = HandleToULong(ProcessId);item.ParentProcessId = HandleToULong(CreateInfo->ParentProcessId);

Размер элемента должен вычисляться с учетом базовой структуры и длины командной строки.

Затем необходимо скопировать командную строку по адресу за базовой структурой, а также обновить длину и смещение:

if (commandLineSize > 0) {    ::memcpy((UCHAR*)&item + sizeof(item), CreateInfo->CommandLine->Buffer,        commandLineSize);    item.CommandLineLength = commandLineSize / sizeof(WCHAR); // Длина в WCHAR    item.CommandLineOffset = sizeof(item);}else {    item.CommandLineLength = 0;}PushItem(&info->Entry);

Добавьте в структуру ProcessCreateInfo имя файла образа по той же схеме, что и для командной строки. Будьте внимательны при вычислении смещения.

Передача данных в пользовательский режим


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

Начнем обработку запроса чтения с получения адреса пользовательского буфера с применением прямого ввода/вывода (настраивается в DriverEntry):

NTSTATUS SysMonRead(PDEVICE_OBJECT, PIRP Irp) {    auto stack = IoGetCurrentIrpStackLocation(Irp);    auto len = stack->Parameters.Read.Length;    auto status = STATUS_SUCCESS;    auto count = 0;    NT_ASSERT(Irp->MdlAddress); // Используем прямой ввод/вывод    auto buffer = (UCHAR*)MmGetSystemAddressForMdlSafe(Irp->MdlAddress,        NormalPagePriority);     if (!buffer) {        status = STATUS_INSUFFICIENT_RESOURCES;}else {

Теперь необходимо обратиться к связанному списку и извлечь элементы из заголовка:

AutoLock lock(g_Globals.Mutex); // C++ 17while (true) {    if (IsListEmpty(&g_Globals.ItemsHead)) // также можно проверить                                       // g_Globals.ItemCount        break;    auto entry = RemoveHeadList(&g_Globals.ItemsHead);    auto info = CONTAINING_RECORD(entry, FullItem<ItemHeader>, Entry);    auto size = info->Data.Size;    if (len < size) {        // Пользовательский буфер заполнен, вставить элемент обратно        InsertHeadList(&g_Globals.ItemsHead, entry);        break;    }    g_Globals.ItemCount--;    ::memcpy(buffer, &info->Data, size);    len -= size;    buffer += size;    count += size;    // Освободить данные после копирования    ExFreePool(info);}

Сначала мы захватываем быстрый мьютекс, так как уведомления процессов продолжают поступать. Если список пуст, то делать нечего, и выполнение цикла прерывается. После этого извлекается заголовочный элемент, и если его размер не превышает размер оставшейся части пользовательского буфера, копируется его содержимое (без поля LIST_ENTRY). Далее цикл продолжает извлекать элементы от заголовка списка, пока список не опустеет или пользовательский буфер не заполнится.

Наконец, запрос завершается с текущим статусом, а в поле Information сохраняется значение переменной count:

Irp->IoStatus.Status = status;Irp->IoStatus.Information = count;IoCompleteRequest(Irp, 0);return status;

К функции выгрузки также стоит присмотреться повнимательнее. Если в связном списке присутствуют элементы, они должны быть освобождены явно; в противном случае возникнет утечка ресурсов:

void SysMonUnload(PDRIVER_OBJECT DriverObject) {    // Отмена регистрации уведомлений процессов    PsSetCreateProcessNotifyRoutineEx(OnProcessNotify, TRUE);    UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\??\\sysmon");    IoDeleteSymbolicLink(&symLink);    IoDeleteDevice(DriverObject->DeviceObject);    // Освобождение оставшихся элементов    while (!IsListEmpty(&g_Globals.ItemsHead)) {       auto entry = RemoveHeadList(&g_Globals.ItemsHead);       ExFreePool(CONTAINING_RECORD(entry, FullItem<ItemHeader>, Entry));}}

Клиент пользовательского режима


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

Функция main вызывает ReadFile в цикле с небольшой приостановкой, чтобы поток не потреблял ресурсы процессора постоянно. Поступившие данные отправляются для вывода:

int main() {    auto hFile = ::CreateFile(L"\\\\.\\SysMon", GENERIC_READ, 0,         nullptr, OPEN_EXISTING, 0, nullptr);    if (hFile == INVALID_HANDLE_VALUE)         return Error("Failed to open file");    BYTE buffer[1 << 16]; // 64-килобайтный буфер    while (true) {         DWORD bytes;         if (!::ReadFile(hFile, buffer, sizeof(buffer), &bytes, nullptr))            return Error("Failed to read");         if (bytes != 0)            DisplayInfo(buffer, bytes);         ::Sleep(200);     }}

Функция DisplayInfo должна разобраться в структуре полученного буфера. Так как все события начинаются с общего заголовка, функция различает события по значению ItemType. После того как событие будет обработано, поле Size в заголовке указывает, где начинается следующее событие:

void DisplayInfo(BYTE* buffer, DWORD size) {    auto count = size;    while (count > 0) {        auto header = (ItemHeader*)buffer;        switch (header->Type) {        case ItemType::ProcessExit:        {             DisplayTime(header->Time);             auto info = (ProcessExitInfo*)buffer;             printf("Process %d Exited\n", info->ProcessId);             break;         }         case ItemType::ProcessCreate:         {              DisplayTime(header->Time);              auto info = (ProcessCreateInfo*)buffer;              std::wstring commandline((WCHAR*)(buffer +                                           info->CommandLineOffset),                     info->CommandLineLength);               printf("Process %d Created. Command line: %ws\n",                                               info->ProcessId,                      commandline.c_str());                break;           }           default:               break;     }     buffer += header->Size;     count -= header->Size;   }}

Для правильного извлечения командной строки в коде используется конструктор класса C++ wstring, который может построить строку по указателю и длине строки. Вспомогательная функция DisplayTime форматирует время в виде, удобном для чтения:

void DisplayTime(const LARGE_INTEGER& time) {    SYSTEMTIME st;    ::FileTimeToSystemTime((FILETIME*)&time, &st);    printf("%02d:%02d:%02d.%03d: ",           st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);}

Драйвер устанавливается и запускается так, как было описано в главе 4.

sc create sysmon type= kernel binPath= C:\Book\SysMon.syssc start sysmon

Пример вывода, полученного при запуске SysMonClient.exe:

C:\Book>SysMonClient.exe12:06:24.747: Process 13000 Exited12:06:31.032: Process 7484 Created. Command line: SysMonClient.exe12:06:42.461: Process 3128 Exited12:06:42.462: Process 7936 Exited12:06:42.474: Process 12320 Created. Command line: "C:\$WINDOWS.~BT\                                                    Sources\mighost.\exe" {5152EFE5-97CA-4DE6-BBD2-4F6ECE2ABD7A} /InitDoneEvent:MigHost.                                                    {5152EFE5-97CA-4D\E6-BBD2-4F6ECE2ABD7A}.Event /ParentPID:11908 /LogDir:"C:\$WINDOWS.~BT\Sources\                                                     Panthe\r"12:06:42.485: Process 12796 Created. Command line: \??\C:\WINDOWS\system32\                                                     conhost.e\xe 0xffffffff -ForceV112:07:09.575: Process 6784 Created. Command line: "C:\WINDOWS\system32\cmd.exe"12:07:09.590: Process 7248 Created. Command line: \??\C:\WINDOWS\system32\                                                     conhost.ex\e 0xffffffff -ForceV112:07:11.387: Process 7832 Exited12:07:12.034: Process 2112 Created. Command line: C:\WINDOWS\system32\                                                     ApplicationFra\meHost.exe -Embedding12:07:12.041: Process 5276 Created. Command line: "C:\Windows\SystemApps\                                                     Microsoft.M\icrosoftEdge_8wekyb3d8bbwe\MicrosoftEdge.exe" -ServerName:MicrosoftEdge.                                                     AppXdnhjhccw\3zf0j06tkg3jtqr00qdm0khc.mca12:07:12.624: Process 2076 Created. Command line: C:\WINDOWS\system32\                                                     DllHost.exe /P\rocessid:{7966B4D8-4FDC-4126-A10B-39A3209AD251}12:07:12.747: Process 7080 Created. Command line: C:\WINDOWS\system32\                                                     browser_broker\.exe -Embedding12:07:13.016: Process 8972 Created. Command line: C:\WINDOWS\System32\                                                        svchost.exe -k\LocalServiceNetworkRestricted12:07:13.435: Process 12964 Created. Command line: C:\WINDOWS\system32\                                                     DllHost.exe /\Processid:{973D20D7-562D-44B9-B70B-5A0F49CCDF3F}12:07:13.554: Process 11072 Created. Command line: C:\WINDOWS\system32\                                                     Windows.WARP.\JITService.exe 7f992973-8a6d-421d-b042-6afd93a19631S-1-15-2-3624051433-2125758914-1\423191267-1740899205-1073925389-3782572162-737981194S-1-5-21-4017881901-586210945-2\666946644-1001 51612:07:14.454: Process 12516 Created. Command line: C:\Windows\System32\RuntimeBroker.exe -Embedding12:07:14.914: Process 10424 Created. Command line: C:\WINDOWS\system32\                                                    MicrosoftEdge\SH.exe SCODEF:5276 CREDAT:9730 APH:1000000000000017 JITHOST /prefetch:212:07:14.980: Process 12536 Created. Command line: "C:\Windows\System32\                                                    MicrosoftEdg\eCP.exe" -ServerName:Windows.Internal.WebRuntime.ContentProcessServer12:07:17.741: Process 7828 Created. Command line: C:\WINDOWS\system32\                                                    SearchIndexer.\exe /Embedding12:07:19.171: Process 2076 Exited12:07:30.286: Process 3036 Created. Command line: "C:\Windows\System32\                                                    MicrosoftEdge\CP.exe" -ServerName:Windows.Internal.WebRuntime.ContentProcessServer12:07:31.657: Process 9536 Exited

Уведомления потоков


Ядро предоставляет обратные вызовы создания и уничтожения потоков, аналогичные обратным вызовам процессов. Для регистрации используется функция API PsSetCreateThreadNotifyRoutine, а для ее отмены другая функция, PsRemoveCreateThreadNotifyRoutine. В аргументах функции обратного вызова передается идентификатор процесса, идентификатор потока, а также флаг создания/уничтожения потока.

Расширим существующий драйвер SysMon, чтобы он получал не только уведомления процессов, но и уведомления потоков. Начнем с добавления значений перечисления и структуры, представляющей информацию, все это добавляется в заголовочный файл SysMonCommon.h:

enum class ItemType : short {    None,    ProcessCreate,    ProcessExit,    ThreadCreate,    ThreadExit};struct ThreadCreateExitInfo : ItemHeader {    ULONG ThreadId;    ULONG ProcessId;};

Затем можно добавить вызов регистрации в DriverEntry, непосредственно за вызовом регистрации уведомлений процессов:

status = PsSetCreateThreadNotifyRoutine(OnThreadNotify);if (!NT_SUCCESS(status)) {    KdPrint((DRIVER_PREFIX "failed to set thread callbacks (status=%08X)\n", status)\);   break;}

Сама функция обратного вызова весьма проста, так как структура события имеет постоянный размер. Полный код функции обратного вызова для потока:

void OnThreadNotify(HANDLE ProcessId, HANDLE ThreadId, BOOLEAN Create) {   auto size = sizeof(FullItem<ThreadCreateExitInfo>);   auto info = (FullItem<ThreadCreateExitInfo>*)ExAllocatePoolWithTag(PagedPool,        size, DRIVER_TAG);    if (info == nullptr) {        KdPrint((DRIVER_PREFIX "Failed to allocate memory\n"));        return;    }    auto& item = info->Data;    KeQuerySystemTimePrecise(&item.Time);    item.Size = sizeof(item);    item.Type = Create ? ItemType::ThreadCreate : ItemType::ThreadExit;    item.ProcessId = HandleToULong(ProcessId);    item.ThreadId = HandleToULong(ThreadId);    PushItem(&info->Entry);}

Большая часть кода выглядит довольно знакомо.

Чтобы завершить реализацию, мы добавим в клиент код для вывода информации о создании и уничтожении потоков (в DisplayInfo):

case ItemType::ThreadCreate:{    DisplayTime(header->Time);    auto info = (ThreadCreateExitInfo*)buffer;    printf("Thread %d Created in process %d\n",         info->ThreadId, info->ProcessId);    break;}case ItemType::ThreadExit:{     DisplayTime(header->Time);     auto info = (ThreadCreateExitInfo*)buffer;     printf("Thread %d Exited from process %d\n",          info->ThreadId, info->ProcessId);     break;}

Пример вывода с обновленным драйвером и клиентом:

13:06:29.631: Thread 12180 Exited from process 1197613:06:29.885: Thread 13016 Exited from process 882013:06:29.955: Thread 12532 Exited from process 856013:06:30.218: Process 12164 Created. Command line: SysMonClient.exe13:06:30.219: Thread 12004 Created in process 1216413:06:30.607: Thread 12876 Created in process 10728...13:06:33.260: Thread 4524 Exited from process 448413:06:33.260: Thread 13072 Exited from process 448413:06:33.263: Thread 12388 Exited from process 448413:06:33.264: Process 4484 Exited13:06:33.264: Thread 4960 Exited from process 577613:06:33.264: Thread 12660 Exited from process 577613:06:33.265: Process 5776 Exited13:06:33.272: Process 2584 Created. Command line: "C:\$WINDOWS.~BT\Sources\                                                      mighost.e\xe" {CCD9805D-B15B-4550-94FB-B2AE544639BF} /InitDoneEvent:MigHost.                                                     {CCD9805D-B15B-455\0-94FB-B2AE544639BF}.Event /ParentPID:11908 /LogDir:"C:\$WINDOWS.~BT\Sources\                                                      Panther\"13:06:33.272: Thread 13272 Created in process 258413:06:33.280: Process 12120 Created. Command line: \??\C:\WINDOWS\system32\                                                               conhost.e\xe 0xffffffff -ForceV113:06:33.280: Thread 4200 Created in process 1212013:06:33.283: Thread 4400 Created in process 1212013:06:33.284: Thread 9632 Created in process 1212013:06:33.284: Thread 6064 Created in process 1212013:06:33.289: Thread 2472 Created in process 12120

Добавьте в клиент код вывода имени образа процесса при создании и завершении потока.

Уведомления о загрузке образов


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

Функция API PsSetLoadImageNotifyRoutine регистрируется для получения этих уведомлений, а функция PsRemoveImageNotifyRoutine отменяет регистрацию. Функция обратного вызова имеет следующий прототип:

typedef void (*PLOAD_IMAGE_NOTIFY_ROUTINE)(    _In_opt_ PUNICODE_STRING FullImageName,    _In_ HANDLE ProcessId, // pid, с которым связывается образ    _In_ PIMAGE_INFO ImageInfo);

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

Аргумент FullImageName не так прост. Как указывает аннотация SAL, он необязателен и может содержать NULL. Но даже если он отличен от NULL, он не всегда содержит точное имя файла образа.

Причины кроются глубоко в ядре и выходят за рамки книги. В большинстве случаев решение работает нормально, а путь использует внутренний формат NT, начинающийся с \Device\HadrdiskVolumex\ вместо c:\. Преобразование может быть выполнено разными способами. Тема более подробно рассматривается в главе 11.

Аргумент ProcessId содержит идентификатор процесса, в котором загружается образ. Для драйверов (образов режима ядра) это значение равно нулю.

Аргумент ImageInfo содержит дополнительную информацию об образе; его объявление выглядит так:

#define IMAGE_ADDRESSING_MODE_32BIT 3typedef struct _IMAGE_INFO {    union {      ULONG Properties;      struct {         ULONG ImageAddressingMode : 8; // Режим адресации         ULONG SystemModeImage : 1; // Образ системного режима         ULONG ImageMappedToAllPids : 1; // Образ отображается во все процессы         ULONG ExtendedInfoPresent : 1; // Доступна структура IMAGE_INFO_EX         ULONG MachineTypeMismatch : 1; // Несоответствие типа архитектуры         ULONG ImageSignatureLevel : 4; // Уровень цифровой подписи         ULONG ImageSignatureType : 3; // Тип цифровой подписи         ULONG ImagePartialMap : 1; // Не равно 0 при частичном                                                       отображении         ULONG Reserved : 12;     };   };   PVOID ImageBase;   ULONG ImageSelector;   SIZE_T ImageSize;   ULONG ImageSectionNumber;} IMAGE_INFO, *PIMAGE_INFO;

Краткая сводка важных полей структуры:

  • SystemModeImage флаг устанавливается для образа режима ядра и сбрасывается для образа пользовательского режима.
  • ImageSignatureLevel уровень цифровой подписи (Windows 8.1 и выше). См. описание констант SE_SIGNING_LEVEL_ в WDK.
  • ImageSignatureType тип сигнатуры (Windows 8.1 и выше). См. описание перечисления SE_IMAGE_SIGNATURE_TYPE в WDK.
  • ImageBase виртуальный адрес, по которому загружается образ.
  • ImageSize размер образа.
  • ExtendedInfoPresent если флаг установлен, IMAGE_INFO является частью большей структуры IMAGE_INFO_EX:

typedef struct _IMAGE_INFO_EX {    SIZE_T Size;    IMAGE_INFO ImageInfo;    struct _FILE_OBJECT *FileObject;} IMAGE_INFO_EX, *PIMAGE_INFO_EX;

Для обращения к большей структуре драйвер использует макрос CONTAINING_RECORD:

if (ImageInfo->ExtendedInfoPresent) {    auto exinfo = CONTAINING_RECORD(ImageInfo, IMAGE_INFO_EX, ImageInfo);    // Обращение к FileObject}

В расширенной структуре добавляется всего одно осмысленное поле объект файла, используемый для управления образом. Драйвер может добавить ссылку на объект (ObReferenceObject) и использовать его в других функциях по мере надобности.
Добавьте в драйвер SysMon уведомления о загрузке образов; драйвер должен собирать информацию только для образов пользовательского режима. Клиент должен выводить путь образа, идентификатор процесса и базовый адрес образа.

Упражнения


1. Напишите драйвер, который отслеживает создание процессов и позволяет клиентскому приложению настроить пути к исполняемым файлам, для которых выполнение должно быть запрещено.

2. Напишите драйвер (или расширьте драйвер SysMon), который будет обнаруживать удаленное создание потоков, то есть создание потоков в процессе, отличном от текущего. Подсказка: первый поток в процессе всегда создается удаленно. Уведомите клиента пользовательского режима об этом событии. Напишите тестовое приложение, которое использует функцию CreateRemoteThread для тестирования.

Итоги


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

Более подробно с книгой можно ознакомиться на сайте издательства
Оглавление
Отрывок

Для Хаброжителей скидка 25% по купону Windows

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Подробнее..

Как айтишнику издать свою книгу. Часть первая куда податься

31.05.2021 22:09:30 | Автор: admin

Пожалуй, многих хотя бы раз посещала мысль поделиться своим опытом. Помочь коллегам и подрастающему поколению собранными граблями, изложить сообществу любопытные (а может и поворотные, как знать!) идеи, оставить что-то после.

Книга, опыт выпуска которой и послужил источником данного материала, в статье ранее http://personeltest.ru/aways/habr.com/ru/post/512460/ набрала тысячи скачиваний и десятки благодарных отзывов.

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

Для начала: спасибо всем, кто поддержал. С тех пор книга прошла путь от бесплатного самиздата до книжных магазинов, заинтересовав крупные издательства. Забавное стечение обстоятельств и айтишное упорство привели к созданию новой дополненной версии уже от Эксмо/Бомбора.

А теперь к делу.

Уверена, у многих случались события, достойные книг. Так, где и как простому айтишнику опубликовать свою книгу?

Часть 1. Куда податься с книгой.

Есть два пути: площадки самиздата и традиционные книжные издательства.

Конечно, еще третий полная самодеятельность. Можно разместить, например, в соцсетях, на своем сайте или Гитхабе. Но если хочется пойти дальше, чем бесплатная электронная версия: получить физическую печатную книгу, продавать на популярных маркетплейсах или, зайдя в ближайший книжный, видеть ее на полках, то по мне для простого работающего айтишника продираться на своем велосипеде получается долго или дорого либо долго и дорого :) Честно попытавшись осознать масштаб полной независимости: отсмотрев десятки портфолио, найти фриланс-художников обложки, корректоров, верстальщиков, договориться с типографиями, затем разбираться с выкладкой в каждый магазин и налоговой, остановилась на готовых площадках самиздата или сотрудничестве с издательствами.

Плюсы и минусы первого варианта самиздата:

+ быстрый результат: не нужно ждать рассмотрения до нескольких месяцев издательствами. При том, что риск отказа высок, а пол года ожидания в IT губительны для актуальности ваших материалов;

+ свобода: можно обойтись без договоров с исключительными лицензиями, сохранить все права на распространение за собой. Печатать, раздавать сколько хотите;

+ название книги, дизайн обложки на ваш вкус. Никаких сюрпризов от издательства;

+ никакой редактуры, искажающей ваш авторский текст;

+ услуги печати по требованию (print-on-demand) на основных площадках самиздата: при размещении через них в магазинах (Ozon, My-shop, Москва, Буквоед и др.) книга печатается при поступлении заказа. А значит можно продавать и печатные версии, нет перебоев с отсутствием тиражей, нет затрат автора на их подготовку и отправку в магазины или покупателям;

- денежные затраты: оплата художников/дизайнеров, верстальщиков, корректоров, печать тиражей за свой счет, а затем и реклама;

- временные затраты: поиск вышеупомянутых специалистов книжного дела и формулирования ТЗ, или выбор издательских сервисов и самостоятельная верстка в них, общение с поддержкой;

- сложность попадания в сетевые серьезные книжные офлайн-магазины;

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

Плюсы и минусы издательств*:

*(в случае наиболее традиционного сотрудничества на бесплатной основе по договору исключительной лицензии):

+ все делается издательством за их счет;

+ профессионализм и опыт. Знают, как сделать лучше и продать (крутые обложки, цепляющие названия,...);

+ заинтересованность в успехе. Продажи и популярность вашей книги их прибыль. Точка же монетизации самиздатов, например, Ридеро, скорее смещена в сторону денег с вас (подписки, платные выставки, недешевая оплата корректуры, тиражей и проч.), а не с потенциальных читателей;

+ масштаб больше печатные тиражи (~2000-3000 экз. на старте), больше крупных магазинов;

+ солидность: сотрудничество в классическом книжном флоу вызывает вау-эффект, добавляет веса и серьезности;

+ больше каналов продвижения, специальные маркетинговые отделы;

+ как следствие проще попасть на полки книжных, в т.ч. офлайн, получить классический книжный путь.

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

- получаете, как правило, меньший процент роялти (авторских отчислений);

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

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

Площадки самиздата

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

Плюсы и минусы Ридеро:

+ меньше багов, приятнее интерфейс;

+ больше услуг. Заказать художнику свою обложку, перевод, аудиоверсию, отправку в офлайн-магазины или выкладку в аэропортах;

+ список магазинов релевантнее под IT-аудиторию (например, продажа печатной версии print-on-demand в Ozon, а не в My-shop как на ЛитРес);

+ оперативная поддержка;

- зависимость от посредничества и подсаживание на платные услуги. Например, скачать 1 раз сверстанную книгу в pdf 250 руб., fb2 еще 250 руб., для безлимита покупать подписку в 1000-1500 руб./мес. Поправить аннотацию в магазинах 2 мес. ожидания или доплата;

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

Отступление про бестселлеры в Ozon:

Однажды, зайдя на страницу своей книги в Ozon, я увидела на ней метку бестселлер. Предвкусила масштабы продаж Дарьи Донцовой. Дождавшись следующего месяца, получила статистику от Ridero 2 продажи. На вопрос в Ozon, а по какой логике книги получают метку бестселлер, получила политкорректный ответ как товары, наиболее популярные и продаваемые среди остальных. Уточнения, сколько нужно продаж и как определяются товары сравнения, остались без ответа. Так что стать бестселлером не сложно и за 1-2 книги (правда, ненадолго метка пропала через день-два), либо же, реальные продажи были чуть больше. Но к бестселлерам в Ozon стала относиться настороженнее.

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

Плюсы и минусы ЛитРес:

+ оперативная статистика без задержек в 1-2 мес. по самому ЛитРес-у, а это все же основная площадка электронных книг;

+ больший контроль за отображение книги на ЛитРес;

- сырость, на момент выбора не удалось загрузить, говорящих ошибок не было;

- свой дизайн обложки возможен только для лицевой стороны;

- только дефолтная верстка книги. Сделать на свой вкус более стильную по шрифтам и отступам (боль фронтендера!) верстку для печатной книги нельзя;

- медленнее поддержка;

- меньше привлекательных целевой айтишной аудитории каналов продажи. Например, нет Amаzon, нет продаж печатной версии на Ozon, Aliexpress;

- нет управления списком площадок для публикации книги: нельзя выбрать куда публиковать (и, вероятно, откуда удалять при желании потом), видимо кроме как во все текущие партнеры.

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

Мой путь на данном этапе

Мне как щепетильному айтишнику было важно выпустить в люди авторский текст, под исходным названием и нарисовать собственную придуманную обложку, без котов в мешке от издательств.

Изучив сайты МИФа, Эксмо/Бомборы, Альпины, Питера, ДМК-Пресса и прочих основных и не очень игроков книжного рынка, сроки рассмотрения, % одобрений, процессы, включая в том же МИФе требования дописывания глав под заказ редакторов по потребностям аудитории, прочие условия и веющее от них пренебрежительное и бесправное отношение к авторам поняла, что пока хочу сохранить свободу.

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

В то же время хотелось попасть в крупные сетевые книжные офлайн магазины вроде Читай-Город и Буквоед. Просто был такой пунктик :) Как метрика серьезности результата, качества контента и легкий вызов себе не каждое написанное в сети оказывается на полках классических книжных. И главное, как еще один сложнодоступный своим ходом канал распространения: чтобы студенты и начинающие могли зайти, увидеть и купить. Ведь главное для автора, чтобы его книги читали и использовали себе во благо как можно большее число людей.

А посему убедилась, что выбранная площадка самиздата прав на самостоятельное распространение меня не лишает (т.е. готова принять от меня и неисключительную лицензию) и позволяет безболезненно расстаться, перейдя на сотрудничество с издательством. Хотя существуют и варианты с исключительной лицензией (т.е. передачей всех прав на распространение только им) и большими роялти.

С другой стороны, заранее уточнила у интересующих серьезных издательств:

  • будут ли рассматривать рукопись, ранее открыто размещенную в сети?

  • ранее опубликованную на ресурсах ЛитРес и аналогах для продажи?

  • распечатанную за счет автора малым тиражом?

  • смогу ли сохранить за собой права (и какие) на распространение (т.е. исключительная или неисключительная лицензия предполагается сотрудничеством)?

Краткая сводка ответов:

Почти все ответившие рассмотреть были готовы. Только БХВ сразу предупредил, что как правило не рассматривает открыто размещенные, и работает только по исключительным лицензиям. Но если книга выкладывалась для продажи/печаталась малым тиражом, и права у других площадок на книгу закончились, то возможно.

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

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

Небольшая правовая ремарка

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

К слову, несмотря на положительные ответы по первому пункту, на практике, субъективно, выкладка в сеть снизила шансы.

В ответ на присланную рукопись, руководитель отдела компьютерной литературы БХВ, отреагировал в ключе зачем выложили, как нам на этом теперь заработать? В целом резко и не очень дружелюбно (хотя местами по рыночному справедливо) прокомментировал присланные вводные, а затем сразу перешел к делу. Мол, хотят одну книгу выпустить, как бы им ее назвать, какие технологии вынести на обложку, что сейчас популярно во фронтенде. С лихой овцы хоть шерсти клок :) Естественно, после получения бесплатной консультации, инициативы по связи о моей книге не последовало. Интереса ради, я поинтересовалась сама позже, получив ответ о готовности сотрудничества только за деньги автора.

А еще, забегая вперед, не каждое предложение о сотрудничестве даже за счет издательства сейчас ведет к созданию бумажной версии и заветным полкам сетевых книжным. Все больше авторам рассылаются (вплоть до автоответов) письма счастья о готовности выпустить их произведение... Окрыленные признанием крупного издательства, будущие Джоан Роулинги спешат принять условия и перейти к изданию бестселлера. Однако договоры предполагают, как правило, закидывание электронной книги на ЛитРес и партнеров, что почти ничего не стоит издательству. В лучшем случае обещается аудио, а печатная если пойдут продажи электронной, что почти всегда рано никогда. Итого, вы просто дарите пассивный доход, лишая себя прав, шансов издаться на бумаге с другими серьезными игроками и большего роялти, размести вы книгу сами. Но об этом и прочих тонкостях работы с издательствами в следующих частях.

Текущий итог: выбор самиздата (Ридеро) для выпуска авторской версии с гарантией себе существования книги в бумаге и цель на сотрудничество с издательствами для попадания на полки книжных и большей популяризации.

Продолжение в следующих частях:

Часть 2. Самиздат: сколько стоит свобода. Денежные и временные затраты на выпуск электронной и печатной книги.

Часть 3. Издательства: как попасть на полки книжных магазинов. Шансы на интерес к вам, опасные договоры и процесс выпуска книги.

Часть 4. Запись аудиоверсии книги.

Часть 5. Сколько получают авторы.

Подробнее..

Как айтишнику издать свою книгу. Часть 2 Самиздат сколько стоит свобода

13.06.2021 16:20:24 | Автор: admin

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

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

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

Первая часть о выборе между традиционнымиздательствоми площадками самиздата, плюсах/минусах и личном опыте в посте: Как айтишнику издать свою книгу.Часть 1: куда податься.

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

А теперь к делу.

Основной набор действий посозданию книги примерно одинаков, что в классических издательствах, что на площадках самиздата или в ином аналогичном свободном плаванье.

Краткое флоу, как сделать книгу в самиздате (на примереRidero, выбранном по описанным в предыдущей статье плюсам/минусам):

О каждом шаге в деталях:

Загрузка

Ресурсозатратностьзависит от выбранной площадки. НаРидероможно загрузить свою книгу как файл(DOC, DOCX, TXT, RTF и ODT; в т.ч. с иллюстрациями, до 40Mb), импортировать изGoоgleDocsили даже получить тексты по ссылке изBlogger, LiveJournal,Стихи.ру,Проза.руи ряда других онлайн-ресурсов. Для любителей экстримаможно набирать онлайн в ихсобственном редакторе. На практике проблем с импортом .docxне возникло.

Литрес: Самиздат поддерживает загрузку файлов DOCX и FB2, до 70Mb. Выдвигает при этом жесткие требования к оформлению файлов: структура, переносы и символы концов абзацев, настройки форматирования в Microsoft Word,...многостраничная инструкция прилагается. Просто так скормить имевшийся .docx-файл книги не удалось.

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

Редактура

Призвана сделать слог гармоничнее, текст без речевых ошибок, стилистику автора усилить, предложения переформулироватьв целом, предполагает более серьезные вмешательства, чем правки запятых и орфографии. Пунктуация и прочие школьные правила выправляются позже корректором. Услуги же редактора гораздо дороже,варьируютсяот жанров и предполагают его экспертизу в данной литературной области. Поскольку мне было важносохранить свой авторский стиль, и были небезосновательные опасения станет хужеданный этап мною был опущен. В противном случае, при ценахРидеров 3 800 5000 руб. за 1 авторский лист (40 000 знаков с пробелами), редактура моей книги обошлась бы мне в 38 000 50 000 руб.

Корректура

Субъективно, единственныйнеисключаемыйшаг перед любым обнародованием текста: что с заделом на печатную версию, что для выпуска только электронной книги. Подразумевает проверку на орфографию, пунктуацию, грамматику и опечатки. И хотя я сама при написании не пренебрегала исправлениями от GoogleDocs, уповала на 5-ку по русскому с набором прочно усвоенных правил, а также несколько раз внимательно читала текст постфактумна каждой странице нашлось, что поправить, а то и не раз. Об этом догадываются и площадки самиздата, а поскольку вычитка все еще делается не нейронными сетями, а реальными людьмиудовольствие недешевое. Цена за 1 авторский листварьируется от 990руб.вЛитРес: Самиздате до1300руб. вРидеро. В типографиях или фрилансе можно поискать дешевле, держа в голове поправку на качество.

Мне корректура книги объемом 10а.л. (немного выше среднего в своем жанре нон-фикшена) обошлась на тот момент в 11 000руб. дорожепечати небольшого тиража в 35 экз.

ВРидероправки предлагают внести либо на их сайте в онлайн-редакторе текста загруженной книги, но в нем вы не увидитеdiff, либо, если хотите отсмотреть правки,могут сделать в .docx. Затем в режиме рецензирования через MS Word или GoogleDocsможно принять/отклонить предложенные изменения.

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

Вычитка заняла 11 дней. Общий срок вРидеробыл заявлен до 16 дней.

Сложные тексты рекомендуют вычитывать хотя бы 2 раза. То есть время-деньги повторить.

Отступление: RIP ё

Корректура убрала все старательно расставленные мною буквы ё, заменив их на е. Изсоображений поддержки меньшинств, незамедлительно обеспокоившисьеЁсудьбой у саппорта, выяснила, чтосогласносовременным нормам употребления писать ё следует:

  • когда нужно предупредить неверное прочтение (узнаём -> узнаем,совершённый ->совершенный);

  • для указания произношения малоизвестных слов;

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

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

Дизайн обложки

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

Первый вариант с шаблонами отпадал ввиду своей невзрачности. Продающая обложкаполовина успеха. Да и в голове давносозрел образ желаемой картинки. Здесь начались сложности. Если вы хотите (а я хотела) оформить дизайн и задней частито есть разместить на ней что-то вместо текста аннотации от сервисанайти художника и подружить его результат с площадкой самиздата выглядело проблематично.

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

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

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

Цены от 2900 руб. за оформить вариант с имеющейсяу автора картинкой до 13 900 руб. за детализированную отрисовку уникальной картинки с 4+ персонажами. Мне обошлось в 9 550руб., за несложный сюжет по жесткому ТЗ, включая корректорскую вычитку текстов обложки. Но понравилось.

ТЗ лицевой части, картинки для оборотной стороны и результатТЗ лицевой части, картинки для оборотной стороны и результат

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

Верстка

Как верстальщикфронтендерверстала сама в онлайн редактореRidero. Есть готовые довольно сбалансированные стили: наборы шрифтов и размеров. В основном время уходит на их выбор, корректную разбивку структуры, применение стилейзаголовкови удаление лишних отступов. А ещеборьбу с несовершенствамимира.

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

В копилку магии онлайн редактораRidero(а может и корректуры) пропали пустые скобки у методаtoString().

Скачивание электронной книги

Если до текущего момента был шанс попользоваться площадкой бесплатно, то при попытке получить сверстанную книгу, ждал грамотно подготовленный сюрприз. Скачивание ссохранением верстки в PDF 250руб. за раз, то же для MOBI и FB2. Либо 700 руб. за все. Поправил опечаткуплати еще раз. Либо оформляй подписку 1000-1500 руб./мес. забезлимит. Бесплатно доступен EPUB, но им (и самостоятельными конвертациями в FB2 и MOBI) можно обойтись, если версия с версткой вам не важна.

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

Печать тиража

Стоимость экземпляра зависит от количества в тираже, большедешевле каждый, от числа страниц и параметров печати. На площадках самиздата все красивокалькуляторы, настройки типа обложки, формата. В обычных типографиях возможностей (форматов, типов тиснений, ламинирования и прочих вариаций) гораздо больше. Меня вполне устраивали предлагаемые вRideroмягкая обложка с матовойламинациейи черно-белый текстовый блок с креплением клеем. Пробный тираж в 30 экз. обошелся в 8 334 руб. Шитый блокдороже, твердая обложкаеще дороже. К слову, по запросу в поддержкуRideroбыли готовы декорировать обложку тиснением или выборочным лаком, что на сайте явно не предлагается, но и порядок цен становился уже другим.

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

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

От заказа услуги до коробки с тиражом в руках прошло 19 дней. Непосредственно исполнение без доставки заявлено в 5 рабочих дней.

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

Размещение в онлайн-магазинах

Жирный плюс площадок самиздатавозможность одной кнопкой отправить свою книгу вЛитРес,Ozon, Amazon,AliExpress,Bookmateили другие партнерские магазины.Не нужно разбираться с тонкостями выкладки на каждый сервис. На Amazon, например, нужно конвертировать книгу их инструментами в спец. формат.

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

К плюсам:
+ агрегация прибыли в одном месте. На каждом сервисе есть минимальная сумма вывода в 1000-3000 руб., которую вы можете и не достичь при скромных продажах. Накопить на вывод вRidero, где суммируются доходы от всех площадок, проще.
+ уплата налогов.

Т.к. по закону в РФдоходы от профессиональной писательской деятельности подлежат налогообложению, приразмещениив магазинах самому или через сервисы самиздата важно обращать внимание, являются ли они налоговым агентом. Например,Rideroявлялся, уЛитРес: Самиздата налоги автор выплачивает самостоятельно. Есть возможность оформить налоговый вычет в 20% засоздание произведений литературы.

В ряде магазинов (Ozon,AliExpress,MyShop) поддерживается печать по требованиют.е. можно продавать свою книгу и в бумаге. Площадка самиздата распечатает ее только при оформлении покупки.

Можно установить отдельные цены для электронной и печатных версий. Итоговая цена рассчитывается автоматически исходя из желаемого и явно выставляемого роялти.

Раскатку до магазинов любой правки/опечатки в описании книги черезRideroпридется ждать пару месяцев или платить для ускорения.

Сетевые книжные и офлайн

Для простого автора самиздата здесь выглядит всебесперспективноили разорительно. Книжные не стремятсясотрудничать с подобными писателями.Rideroпредлагает включить вашу книгу в списки, предоставляемые магазинам. Заинтересует закажут. Попробовала, включила. Результат: ожидаемая тишина.

За 90 000 руб. можно заказать размещение на 1 мес. книги в 10 московских магазинах, лицевой выкладкой на полке. За 145 000 руб. есть возможность выбрать размещение в других городах и уже на 2 мес. А за 310 000 руб. книга может полежать 2мес., выложенной на кубе в тематическом отделе нескольких магазинов (не в каждом из сети).

Можно даже заказать выкладку брошюр с фрагментом книги в аэропорты. Всего 115 000 125 руб. за 1 мес. В зависимости от зала и числаэкземпляров.

Денежные и временные затраты на выпуск книгиДенежные и временные затраты на выпуск книги

Дополнительные мероприятия

Перевод книги на английский

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

На площадкеRideroсейчас стоимость перевода начинается от 1690 руб./стр. Страницей при этом обычно считается 1800 знаков с пробелами. Для моей книги выходило тогда порядка 370 000 руб.

Стремясь получить перевод по более адекватной для себя цене, попросила помощи одного знакомого Бюро. Несмотря на сильную лояльность по ценам на тот момент в 400 руб./стр., меня сразу просветили, что лучше книгу или сразу переводить носителем языка читателя либо вычитывать перевод профессиональным редактором, желательно также носителем. Хороший редактор, предупредили, стоил бы 43$/час, около 2х дней работы. Получалось процентов на 35% дешевлеRidero, но все равно, прилично. На фрилансе от 4$/час, держа в голове качество.

Запись аудиоверсии

В самиздате можно заказать за деньги(Ridero), наЛитРесеесть отдельный проект по записиЛитРес: Чтец.Про мой опыт подробнее в последующейЧасти 4. Запись аудиоверсии книги.

Выставки

Следуя желаниям автора из самиздата быть замеченным иобрестипопулярность,Rideroпредлагает участие на ежегодной Московской Международной Книжной ярмарке,выставкеNon/fictionи прочих.

На практике с точки зрения привлечения читателей и продаж смысла участия мало. За пакет в 19 000 руб. на ММКЯ, предполагавший печать 10 экземпляров, выкладку книги на стенде и их продажу, реализовалось 2 штуки и никакого дополнительного внимания к книге неощутилось. Можно выступить на ярмарке с презентацией своей книги, но и порядок цены будет уже другой. На фото с итогами людей на отдельных презентациях мало, опять же чувствуется смещение точки монетизации в сторону денег с авторов, а не читателей.

Депубликация

Самостоятельно убрать книгу из магазинов в том жеRideroнельзя: никаких элементов по ее удалению в интерфейсе не предусмотрено. Все делается опять же запросом через поддержку.

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

Дополнительные мероприятияДополнительные мероприятия

Итого, получить в самиздате тираж в 30 экз. с приятной вёрсткой, своей обложкой и продаваться онлайн обошлось в (без дополнительных услуг и рекламы) 2 месяца и 28 900 руб.

Но... хотелось попасть и в сетевые книжные офлайн-магазины. Продолжение про работу с традиционными издательствамив следующей части.

Далее:

Часть 3. Издательства: как попасть на полки книжных магазинов. Шансы на интерес к вам, опасные договоры и процесс выпуска книги.

Часть 4. Запись аудиоверсии книги.

Часть 5. Сколько получают авторы.


Подробнее про книгурезультатсамиздата.

Текущая версия результат работы сиздательством(Эксмо/Бомбора) и их дизайн.

Подробнее..

Издательство Питер. Колонка редактора

03.06.2021 12:19:11 | Автор: admin
image

Привет, Хаброжители! Предлагаем ознакомиться с краткими обзорами сданных в типографию новинок.

image

JavaScript для глубокого обучения: TensorFlow.js


Пора научиться использовать TensorFlow.js для построения моделей глубокого обучения, работающих непосредственно в браузере!

Умные веб-приложения захватили мир, а реализовать их в браузере или серверной части позволяет TensorFlow.js. Данная библиотека блестяще портируется, ее модели работают везде, где работает JavaScript.

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

В этой книге:

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

Оформить предзаказ.

image

Делай как в Google. Разработка программного обеспечения


Автор(ы): Титус Винтерс, Том Маншрек, Хайрам Райт

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

В чем же разница между программированием и программной инженерией? Как разработчик может управлять живой кодовой базой, которая развивается и реагирует на меняющиеся требования на всем протяжении своего существования?

Основываясь на опыте Google, инженеры-программисты Титус Винтерс и Хайрам Райт вместе с Томом Маншреком делают откровенный и проницательный анализ того, как ведущие мировые практики создают и поддерживают ПО. Речь идет об уникальной инженерной культуре, процессах и инструментах Google, а также о том, как эти аспекты влияют на эффективность разработки.

Вы изучите фундаментальные принципы, которые компании разработчиков ПО должны учитывать при проектировании, разработке архитектуры, написании и сопровождении кода.

Оформить предзаказ.

image

Программируем на C# 8.0. Разработка приложений


Автор(ы): Иэн Гриффитс

C# универсальный язык, который может практически всё! Иэн Гриффитс рассказывает о его возможностях с точки зрения разработчика, перед которым стоит задача быстро и эффективно создавать приложения любой сложности.

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

В этой книге вы:

  • Узнаете, как C# поддерживает классы, настраиваемые типы, коллекции и обработку ошибок.
  • Сможете создавать высокопроизводительный код с эффективным использованием памяти с помощью типов Span<Т> и Memory<Т>.
  • Научитесь запрашивать и работать с объектными моделями, базами, потоками данных и XML документами.
  • Примените многопоточность, чтобы задействовать всю мощь параллельной обработки.
  • Узнаете, как функции асинхронного языка помогают улучшить скорость отклика и масштабируемость приложений.

Оформить предзаказ.

image

Распределенные данные. Алгоритмы работы современных систем хранения информации


Автор(ы): Алекс Петров

Когда дело доходит до выбора, использования и обслуживания базы данных, важно понимать ее внутреннее устройство. Как разобраться в огромном море доступных сегодня распределенных баз данных и инструментов? На что они способны? Чем различаются?

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

Вы узнаете о принципах и концепциях, используемых во всех типах СУБД, с акцентом на подсистеме хранения данных и компонентах, отвечающих за распределение. Эти алгоритмы используются в базах данных, очередях сообщений, планировщиках и в другом важном инфраструктурном программном обеспечении. Вы разберетесь как работают современные системы хранения информации, и это поможет взвешенно выбирать необходимое программное обеспечение и выявлять потенциальные проблемы.

В этой книге вы углубитесь в:

  • Механизмы хранения: классификация и таксономия хранилищ, механизмы хранения на основе B-дерева и неизменяемые лог-структуры.
  • Строительные блоки хранилища: организация файлов баз данных, позволяющая создавать эффективные хранилища с использованием вспомогательных структур (кэш страниц и пулы буферов).
  • Распределенные системы: пошаговое руководство по подключению узлов и процессов и построение сложных схем взаимодействия.
  • Кластеры баз данных: модели согласованности в современных базах данных и согласованность распределенных систем хранения.

Оформить предзаказ.

image

Безопасность контейнеров. Фундаментальный подход к защите контейнеризированных приложений


Автор(ы): Лиз Райс

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

Лиз Райс исследует вопросы построения контейнерных систем в Linux. Узнайте, что происходит при развертывании контейнеров и научитесь оценивать возможные риски для безопасности развертываемой системы. Приступайте, если используете Kubernetes или Docker и знаете базовые команды Linux.

В этой книге:

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

Оформить предзаказ.

image

Python, например


Автор(ы): Никола Лейси

Это Python, например! Познакомьтесь с самым быстрорастущим языком программирования на сегодняшний день.

Легкое и увлекательное руководство поможет шаг за шагом прокачать навыки разработки. Никаких архитектур компьютера, теорий программирования и прочей абракадабры больше практики! В книге 150 задач, которые плавно перенесут читателя от изучения основ языка к решению более сложных вещей. Руководство подойдет всем, у кого голова идет кругом от технического жаргона и пространных объяснений автор уверен, что учить можно и без этого.

Оформить предзаказ.
Подробнее..

Летняя распродажа

21.06.2021 12:17:59 | Автор: admin
image

Привет, Хаброжители! Стартовала летняя распродажа от издательства Питер.

image


В хронологическом порядке представлены книги, вызвавшие интерес читателей за последние 3 мес.

Отдельные категории на сайте Бестселлеры O'Reilly, Head First O'Reilly, Manning, No Starch Press, Packt Publishing, Классика Computer Science, программирование для детей, научно-популярная серия New Science.

Книги по бизнесу, психологии, детский ассортимент.

Условия акции: 21 июня27 июня, скидка 40% на все бумажные книги по купону Бумажная книга, скидка 50% на все электронные книги по купону Электронная книга
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru