Информационные технологии — Дмитрий [KP0H] Пелевин https://pelevin.pro Сохраняю тишину в голове Tue, 13 Mar 2018 20:36:30 +0000 ru-RU hourly 1 48722140 Про искусственный интеллект и творчество https://pelevin.pro/2018/03/creativityai/ https://pelevin.pro/2018/03/creativityai/#respond Wed, 14 Mar 2018 07:00:52 +0000 https://pelevin.pro/?p=115740 Вроде бы было много интересных тем, на которые можно было бы поговорить, но как до дела, все не уходило дальше нескольких строк. Но тут я наткнулся на это видео, музыка сочинененная искуственным интеллектом. Лишних строк не требуется.

 

 

 

]]>
https://pelevin.pro/2018/03/creativityai/feed/ 0 115740
Hype Driven Development https://pelevin.pro/2016/11/hypedrivendevelopment/ https://pelevin.pro/2016/11/hypedrivendevelopment/#comments Wed, 30 Nov 2016 13:18:27 +0000 http://pelevin.pro/?p=115656 Hype Header

Перевод одноименной статьи Marek Kirejczyk из daftcode.pl.

Команды разработчиков программного обеспечения часто принимают решения о программной архитектуре или базовом технологическом стеке на основе спорных мнений из социальных медиа, да и в целом выбирая то, что считается «горяченьким», вместо того, чтобы провести скрупулезное исследование и серьезно рассмотреть возможный эффект от их применения на своих проектах. Я называю эту тенденцию Hype Driven Development (прим. разработка управляемая беззастенчивой рекламой или обманом, но обман… в общем я склонен считать что хайп это хайп, но в переводе иногда буду использовать другие слова), считаю ее вредной и выступаю за более профессиональный подход, который называю «Solid Software Enginering». Приглашаю узнать больше о том, как это работает, и выяснить, что можно сделать вместо этого [HDD].

Новая технология — новая надежда

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

Hype Driven Development

Hype Driven Development (HDD) имеет множество оттенков и может коснуться вашего проекта по-разному:

Reddit Driven Development — когда команда или кто-то конкретный принимает решение по технологии / архитектуре / дизайну, основываясь на том, что об этом написал популярный блоггер, или это очень жарко обсуждается на Reddit, hackernews, Twitter, facebook, GitHub или других социальных медиа.

Conference Driven Development — присмотритесь к тому, что происходит после того, как люди вернулись с конференции. Люди вдохновляются. И это палка о двух концах. Переходя на новейшие «горячие» библиотеки/фреймворки/архитектурные парадигмы без должного их исследования можно попасть прямиком на шоссе из песни AC/DC (прим. Highway to hell).

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

howaboutno

Loudest guy driven decisions —  это когда у нас есть один парень, который все время говорит об этой клевой новой штуке, в которой у него нет никакого опыта, но говорит он безостановочно и в итоге команда принимает решение использовать её.

Gem/lib/plugin driven development —  особенно сильна в комьюнити Ruby On Rails, где время от времени я могу встретить такой длинный Gemfile, что длиннее будет только загрузка приложения. Это явление происходит от идем о том, что каждая проблема в Rail должна быть решена с помощью gem’а. Иногда самостоятельное решение стоило бы всего нескольких строк кода. Но мы просто решаем проблемы добавлением библиотек, плагинов, гемов или фреймфорков.

Что-то похожее встречается при работе со сборщиками в «новых» концепциях asp.net и т.п. В общем подобную историю можно встретить довольно часто, а временами, кроме прочего еще и наткнуться на Dependency Hell, в общем путей в ад много.

И, пожалуй, я хотел бы упомянуть здесь поведение, популярное среди HDD-разработчиков —  Stack Overflow driven development  —  когда разработчики копипастят решения со Stackoverflow (или в принципе откуда-то с просторов интернета) без реального понимания их сути.

HDD это о том, как команды несут погибель сами себе

Проблема хайпа в том, что он легко приводит к неверным решениям. Плохие архитектурные решения или неудачный выбор технологического стека зачастую преследуют команду месяцами или даже годами. А в самом худшем случае они могут привести к другой весьма проблематичной ситуации: The Big Rewrite. Что практически никогда не помогает.

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

Анатомия обмана

Большая часть хайпа имеет сходую структуру. Она на картинке:

howhypelook

Шаг 1: Реальная проблема и решение

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

Шаг 2: Презентация, шумиха и «ключевые слова»

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

Шаг 3: Мания

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

Rewrite everithing

прим. Я лично неоднократно сталкивался с подобным. А вы?

Шаг 4: Разочарование

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

Шаг 5: Осознание!

Наконец, команда делает ретроспективу и понимает, что именно несет новая технология и с какой целью ее использование было бы более уместным. Они становятся мудрее … ну, по крайней мере до следующего хайпа. ^_^

Примеры хайпов:

Давайте исследуем некоторые примеры хайпов и посмотрим как это было.

Пример 1: React.js

Шаг 1: У Facebook была проблема — сложные одностраничные веб-приложения, каким является Facebook, имеют множество различных событий изменяющих состояние в следствии чего становится сложно отслеживать происходящее и последовательно изменять состояние.

Шаг 2: Facebook представил новую парадигму с шумихой вокруг ключевых слов: functional, virtual DOM, components.

Шаг 3: Мания: Facebook создал фреймворк переднего-конца будущего (прим. простите, «front-end framework»)! Давайте всё писать на React!

Шаг 4: Погодите ка, работы много, но возврат инвестиций совсем не быстрый.

Шаг 5: React отлично подходит для продвинутых одностраничных приложений с большим количеством изменений/уведомлений в режиме реального времени странице, но не обязательно окупится для простых приложений.

Пример 2: TDD мертв благодаря DHH

Шаг 1: David Heinemeier Hansson (DHH, создатель фремворка Ruby on Rails)  осознает что трудно использовать TDD с Rails поскольку этот фреймворк не поддерживает в должной мере OOP. Делает прагматичный выбор — не писать тестов заранее.

Шаг 2: Хайп начинается с сообщения в блоге DHH blog post и разговора на конференции conference talk. Ключевые слова: TDD мертв.

Шаг 3: Давайте пропустим тесты. Наш Гуру так сказал. Мы все равно их не писали, теперь мы по крайней мере не делаем вид, мы наконец-то честны.

Шаг 4: Подождите! Намного меньше вещей стало работать по сравнению с тем что было раньше. Мы написали какой-то очень глючный код!

Шаг 5: “TDD не жив или мертв. TDD зависит от принимаемых компромиссов, например риск изменения API, навыки участников и существующий дизайн” — Кент Бек.

Пример 3: Микросервисы

Шаг 1: Большие монолитные приложение сложно масштабируемы. Вот почему наступает момент когда мы разбиваем их на сервисы. Так будет легче масштабировать с точки зрения количества запросов в секунду и разделения зоны ответственности между несколькими командами.

Шаг 2: Ключевые слова: масштабируемость, слабосвязность, монолит.

Шаг 3: Давайте перепишем все на сервисы! У нас тут «спагетти код» потому что у нас монолитная архитектура! Мы должны переписать все на микросервисы!

Шаг 4: Дерьмо! Теперь мы разрабатываем медленнее, у нас сложности с развертыванием и мы тратим массу времени на отслеживание багов между несколькими системами.

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

umustbethistall

Пример 4: NoSQL

Шаг 1: SQL базы данных имеют большие проблемы с высокой загрузкой и неструктурированными данными. Команды по всему миру начинают разрабатывать новое поколение баз данных.

Шаг 2: Ключевые слова: масштабируемость, BigData, высокая производительность.

Шаг 3: Наши базы данных слишком медленным и не недостаточно вместительны! Нам нужен NoSql!

Шаг 4: Нам нужно связать таблицы? Ну нет. Простые SQL операции становятся все более сложными. Разработка замедляется, а ключевые проблемы так и не решены.

Шаг 5: NoSql это иструмент для решения очень специфичных проблем (чрезвычайно большие объемы данных, неструктурированные данные или очень высокая нагрузка). SQL на самом деле является отличным инструментом и справляется с высокой нагрузкой и огромными объемам данных, если его использовать с умом. Варианты для NoSQL по прежнему крайне редки в 2016 году.

Пример 5: Elixir and Phoenix (или поставьте сюда пару своих любимых языков/фреймворков)

Шаг 1: Веб-фреймворки типа Ruby On Rails плохо справляются в случаях когда нужно иметь дело с высоконагруженными приложениями, распределенными приложениями или веб-сокетами.

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

Шаг 3: О, мой хороший, (прим. я почти уверен, что у автора опечатки и он имел ввиду О боже мой!) наше приложение медленное и наш чат не масштабируется!

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

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

Можно продолжать и продолжать:

В JavaScript новые фреймворки рождаются каждый день. Node.js (ключевые слова: программирование событий), реактивное программирование, Meteor.js (ключевые слова: shared state), передний конец MVC, React.js. В программной инженерии рождаются новые архитектуры: Domain Driven Development, Hexagon, DCI. А какой хайп предпочитаете вы?

Хорошие практики

Итак, если не стоит полагаться на мнения высказанные другими людьми в интернетах, то как принять разумное решение? Здесь несколько хороших практик:

Тестируй и исследуй до принятия решения:

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

Когда?

  • В принципе, когда ожидается значительная отдача от инвестиций. Большинство технологий создаются для решения конкретной задачи. Есть ли проблема? Это большая проблема? Будет ли сэкономлено много времени? Окупится ли использование новой технологии с учетом входа в нее и переписывания кода? Что делать, если мы изначально замедлились в два раза? А если четыре? Является ли она по-прежнему стоящей?
  • Великим командам разрешено больше — некоторые команды просто быстрее чем другие приносят ценность. Им становится скучно с тем, что им дается очень легко. Эти команды могут внедрять новые технологии все чаще. Это не повод, чтобы не использовать Spikes и не делать Хакатоны. С другой стороны, если у команды есть проблемы  — действовать с осторожностью.

Нанимайте на работу правильных людей:

  • Сильный технический бэкграунд это ваш друг  — люди знающие различные парадигмы, понимающие теорию программирования (алгоритмы, параллелизм)  и имеющие хорошую инженерную культуру, как правило, меньше подвержены хайпу.
  • Опыт —  хайп сильнее у молодых разработчиков. С годами, люди, видевшие много технологий и сталкивавшиеся с трудностями много раз более рассудительно подходят к выбору технологий.thehypeisstrongНу и конечно, ссылка на первоисточник для страждущих оригинал.
]]>
https://pelevin.pro/2016/11/hypedrivendevelopment/feed/ 2 115656
Про git flow в разработке https://pelevin.pro/2016/04/gitflow/ https://pelevin.pro/2016/04/gitflow/#respond Mon, 18 Apr 2016 10:49:34 +0000 http://pelevin.pro/?p=82695 В общем-то история будет о том, на что стоит обратить внимание, когда решился использовать git-репозиторий, как его удобно приготовить и зачем нужны все эти плюшки.

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

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

Хватит лирики

В общем-то давайте к практике.

.gitignore

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

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

Типичные файлы .gitignore в зависимости от языка или среды разработки вы сможете найти на GitHub в соответствующем проекте.

Git Flow

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

Bjarne Stroustrup

Фраза отца С++ в мире разработки характеризует многое. Собственно git это такая штука, которой стрелять в ногу можно  бесконечно огромным количеством способом, зависящим в основном от вашей фантазии и психических отклонений.

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

Если кратко, то зовется это все Git Flow, и описано множество раз на просторах безграничного интернета.

Git-flow — это набор расширений git предоставляющий высокоуровневые операции над репозиторием для поддержки модели ветвления Vincent Driessen.

Установка Git flow

Для начала нужно иметь установленный git;

Если с Git все хорошо, то в зависимости от используемой операционной системы можно использовать следующие способы установить git flow.

OS X — Homebrew
$ brew install git-flow
OS X — Macports
$ port install git-flow

Linux

$ apt-get install git-flow
Windows

Все сложно

Windows SourceTree

Данный клиент поддерживает Git Flow и позволяет весьма просто управлять им из Gui-интерфейса «из коробки».

Начало работы

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

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

git flow init

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

Feature

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

Ветка типа Feature создается из основной ветки разработки (по умолчанию develop).

git flow feature start featurename

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

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

  • Выполнить слияние ветки фичи в ветку разработки (feature/featurename в develop в моем примере).
  • Переключиться обратно в ветку разработки.
  • Удалить ветки фичи.
git flow feature finish featurename

Если работа над фичей идет совместно с коллегами — опубликуйте ёё на удаленном севере.

git glow feature publish featurename

Соответственно чтобы получить кем-то опубликованную фичу необходимо выполнить

git flow feature pull origin featurename

Можно отслеживать фичу в репозитории origin выполнив

git flow feature track featurename

Release

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

Для начала релиза

git flow release
git flow release start RELEASE [BASE]

Где [BASE] вы можете указать при желании в виде sha-1 хеша коммита из которого нужно начать релиз. Этот коммит должен обязательно принадлежать ветки разработки.

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

git flow release publish RELEASE

И так же по аналогии для отслеживания нужно использовать

git flow release track RELEASE

Завершение релиза один из наиболее сложных и важных шагов всего процесса ветвления в ходе которого происходят следующие действия:

  • Ветка релиза сливается в ветку мастер
  • Рализ помечается тегом равным его имени
  • Ветка рилаза сливается обратно в ветку разработки
  • Ветка релиза удаляется
git flow release finish RELEASE

Чтобы опубликовать тэги

git push --tags

Исправления

Исправления нам необходимы в том случае, когда требуется срочное изменение состояния продакшн-версии разрабатываемого продукта. Как вы понимаете она у нас находится в ветке master и помечена тэгом версии, соответственно мы ветвим hotfix от тега на ветке мастер.

git flow hotfix start VERSION [BASENAME]

Version — определяет имя нового исправленного релиза.

[Basename] — не обязательный аргумент, указывающий на коммит, от которого произойдет ветвление.

Завершение исправления выглядит так:

git flow hotfix finish VERSION

В этот момент оно сливается в ветки develop и master, коммит в ветке master помечается тегом с версией исправления.

Резюме

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

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

git-model

Думаю в ближайшее время подготовлю перевод этой статьи.

 

]]>
https://pelevin.pro/2016/04/gitflow/feed/ 0 82695
Про автоматизацию https://pelevin.pro/2015/07/%d0%bf%d1%80%d0%be-%d0%b0%d0%b2%d1%82%d0%be%d0%bc%d0%b0%d1%82%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8e/ https://pelevin.pro/2015/07/%d0%bf%d1%80%d0%be-%d0%b0%d0%b2%d1%82%d0%be%d0%bc%d0%b0%d1%82%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8e/#respond Tue, 21 Jul 2015 09:32:42 +0000 http://pelevin.pro/?p=2206 — Смотрите, мы уже 100 лет рубим лес стальными топорами. Нам нужно усовершенствовать инструменты, чтобы мы могли заготавливать больше леса.

— Хорошо, вот супер-новая пила, работающая на холодном синтезе, заряда хватит на несколько сотен лет.

— Эта ваша пила совершенно не удобная и плохо работает.

— Почему неудобная, ведь с её помощью можно заготавливать больше леса и она не требует ни топлива, ни подзарядки?

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

— Но это пила, ей не надо махать, просто уприте её вот так и направляйте.

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

]]>
https://pelevin.pro/2015/07/%d0%bf%d1%80%d0%be-%d0%b0%d0%b2%d1%82%d0%be%d0%bc%d0%b0%d1%82%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8e/feed/ 0 2206
Создание простейшей WCF-службы. Часть 3. https://pelevin.pro/2014/12/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%b5%d0%b9%d1%88%d0%b5%d0%b9-wcf-%d1%81%d0%bb%d1%83%d0%b6%d0%b1%d1%8b-%d1%87%d0%b0%d1%81%d1%82%d1%8c-3/ https://pelevin.pro/2014/12/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%b5%d0%b9%d1%88%d0%b5%d0%b9-wcf-%d1%81%d0%bb%d1%83%d0%b6%d0%b1%d1%8b-%d1%87%d0%b0%d1%81%d1%82%d1%8c-3/#respond Tue, 02 Dec 2014 18:04:52 +0000 http://pelevin.pro/?p=1896 Примечание автора: эта статья была написана в районе 2008 года, и, скорее всего, она уже морально устарела. Однако, судя по отзывам, все еще кому-то полезна. Статья разделена на несколько частей.

Часть 1, Часть 2, Часть 3

Создание клиентского приложения WCF

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

Добавим в наше решение новый проект — консольное приложение Windows и назовем его CalcClient.

Консольное клиентское приложение

Консольное клиентское приложение

К созданному проекту нужно добавить ссылку на службу (Add ServiceReference).

Добавление ссылки на сервис

Добавление ссылки на сервис

В появившемся диалоге нужно нажать кнопку «Discover» (после чего в списке появится наша служба), дать имя ссылке на службу (напрмер, ServiceReference) и нажать Ok (не забываем запустить студию от имени администратора в Висте):

Диалоговое окно добавления ссылки на сервис

Диалоговое окно добавления ссылки на сервис

Примечание

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

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

Теперь перейдем в тело метода Main (точки входа нашего консольного приложения) и напишем следующий код:

Main

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

Сделаем оба проекта — библиотеку службы и наш новый клиент — стартовыми (это делается в свойствах решения).

Диалоговое окно выбора стартовых проектов

Диалоговое окно выбора стартовых проектов

Готово! Можно запускать решение. Вот какой результат мы получили:

Результат обращения к WCF службе

Результат обращения к WCF службе

Что логично — 1 + 2 = 3.

Изменим теперь код вызова метода службы на следующий:

CalcOperationResult res = client.Calc(1, 0, CalcOperationType.Div);

И запустим приложение. В результате получаем информацию об исключении (деление на ноль):

Результат обращения к WCF-службе — произошла ошибка

Результат обращения к WCF-службе — произошла ошибка

Заключение

Помните, в связи с выходом нового Framework’а материал статьи может быть устаревшим.

Не забывайте запускать VS с правами Администратора.

]]>
https://pelevin.pro/2014/12/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%b5%d0%b9%d1%88%d0%b5%d0%b9-wcf-%d1%81%d0%bb%d1%83%d0%b6%d0%b1%d1%8b-%d1%87%d0%b0%d1%81%d1%82%d1%8c-3/feed/ 0 1896
Создание простейшей WCF-службы. Часть 2. https://pelevin.pro/2014/12/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%b5%d0%b9%d1%88%d0%b5%d0%b9-wcf-%d1%81%d0%bb%d1%83%d0%b6%d0%b1%d1%8b-%d1%87%d0%b0%d1%81%d1%82%d1%8c-2/ https://pelevin.pro/2014/12/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%b5%d0%b9%d1%88%d0%b5%d0%b9-wcf-%d1%81%d0%bb%d1%83%d0%b6%d0%b1%d1%8b-%d1%87%d0%b0%d1%81%d1%82%d1%8c-2/#respond Tue, 02 Dec 2014 18:04:42 +0000 http://pelevin.pro/?p=1889 Примечание автора: эта статья была написана в районе 2008 года, и, скорее всего, она уже морально устарела. Однако, судя по отзывам, все еще кому-то полезна. Статья разделена на несколько частей.

Часть 1, Часть 2, Часть 3

Реализация сервиса

Итак, мы создали контракт нашей службы, теперь нужно этот контракт реализовать. Сразу переименуем файл Service1.cs в CalcService.cs (VS спросит, хотите ли вы переименовать тип, хранящийся в файле — нужно согласиться) и откроем его.

В xml-комментарии перед описанием класса сервиса видим то же самое предупреждение, что и в случае с интерфейсом. Удаляем его, а также все автоматически сгенерированное содержимое класса — оно нам не понадобится.

Теперь переводим курсор на имя наследуемого интерфейса, нажимаем Alt+Shift+F10 и в появившемся меню выбираем Implement interface ‘ICalcService’. Осталось лишь реализовать наш метод Calc:

Код метода Calc — Реализация службы CalcService

Код метода Calc — Реализация службы CalcService

WcfTestClient и WcfServiceHost

В состав .NET Framework 3.5 входит пара замечательных утилит для тестирования WCF-приложений: это WcfTestClient и WcfServiceHost. Расскажу о них поподробнее.

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

Примечание

Тестовый клиент, к сожалению, не поддерживает сеансы (о них подробнее в одной из следующих статей) и передачу композитных типов данных.

Так как тестовый клиент оперирует только с простыми типами данных, мы не сможем с помощью него проверить действие функции Calc.

Вторая утилита — это универсальное хост-приложение для WCF-сервисов. Она автоматически запускается студией при нажатии клавиши F5, когда стартовым проектом является библиотека WCF-службы. WcfServiceHost использует параметры сервиса из файла app.config библиотеки службы и, при наличии ошибок, сообщает об этом.

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

WCF Service Host

WCF Service Host

В списке служб находится только одна служба — наш CalcService. Статус у него — «запущен», значит никаких ошибок на стороне службы не возникло. Если в статусе стоит «error» (ошибка), можно выбрать службу в списке и в поле Additional Information просмотреть подробное описание ошибки.

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

WCF Test Client

WCF Test Client

Конфигурация службы

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

Открываем файл app.config из проекта библиотеки службы и находим раздел <system.serviceModel>.

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

«<!— When deploying the service library project, the content of the config file must be added to the host’s app.config file. System.Configuration does not support config files for libraries. —>»

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

Сейчас в разделе <system.serviceModel> видим только один подраздел — <services>, а в нем только один сервис — наш CalcService. У конфигурации службы есть два основных атрибута — это name, в котором нужно указать полное имя класса нашей службы (WcfCalcService.CalcService), и behaviorConfiguration — имя конфигурации поведения службы. Внутри описания службы объявлено две точки соединения — для самого сервиса и для его метаданных.

По умолчанию для точки соединения не указан адрес — установим его в «http://localhost/CalcService». В качестве привязки (binding) выберем пока basicHttpBinding (это привязка, которая обеспечивает просто транспорт по протоколу HTTP). В качестве контракта (contract) указан наш интерфейс — WcfCalcService.ICalcService. Также у точки соединения службы есть дочерний элемент <identity>, который служит для идентификации веб-приложения. Мы его пока проигнорируем.

Следующая точка соединения — это точка метаданных. Она используется для получения информации о контракте службы и сигнатурах ее методов. В качестве адреса у нее установлено значение «mex», без указания типа протокола. Это — относительный адрес, и для того, чтобы он работал, необходимо указание для него базового адреса. Что и сделано студией по умолчанию: в дочернем элементе точки соединения host\baseAddresses содержится элемент «add» с атрибутом baseAddress. Его значение мы установим в «http://localhost/CalcService». Теперь, при обращении по адресу «http://localhost/CalcService» клиент будет попадать к нашей службе, а по адресу «http://localhost/CalcService/mex» — к точке, обслуживающей метаданные.

Примечание

Заметьте, что точка соединения для метаданных использует специальные привязку и контракт — mexHttpBinding и IMetadataExchange соответственно. Менять эти значения не нужно.

Следующим за разделом <services> идет раздел <behaviors>, который описывает поведения служб. Для нашей службы там уже создан элемент «<behavior name=”WcfCalcService.Service1Behavior”>» (помните, в качестве значения атрибута behaviorConfiguration нашей службы как раз установлено «WcfCalcService.Service1Behavior»). В этом разделе содержится два элемента, перед каждым из которых видим увесистый комментарий:

1. To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment — Чтобы избежать раскрытия метаданных, установите значение ниже в false и точки соедидения метаданных перед развертыванием

2. To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information — Чтобы получать информацию об исключениях при возникновении ошибок в целях отладки, установите значение ниже в true. Установите значение ниже в false перед развертыванием для избежания раскрытия информации об исключительных ситуациях.

Нам до развертывания приложения еще далеко, поэтому пока оставляем все как есть.

Примечание

При возникновении необработанной исключительной ситуации на стороне службы, независимо от того, передаем мы подробную информацию об исключительной ситуации или нет, клиентский объект перейдет в состояние Faulted (об этом подробнее в одной из следующих статей), и соединение нужно будет создавать заново. Это очень неудобно, когда используются пошаговые сценарии с поддержкой сеансов, поэтому, для наглядности дальнейших демонстраций возможностей WCF мы не выкидываем Exception в нашем методе Calc, а включаем его в состав «результирующего» объектаCalcOperationResult.

Ниже приведен полный код файла app.config библиотеки службы:

WCF Service app.config file

WCF Service app.config file

 

 

 

 

Примечание

Если вы работаете в операционной системе Windows Vista, и попробуете сейчас запустить службу, появится окно приложения WcfSvcHost с сообщением об ошибке для службы калькулятора:

«System.ServiceModel.AddressAccessDeniedException: HTTP could not register URL http://+:80/CalcService/. Your process does not have access rights to this namespace (seehttp://go.microsoft.com/fwlink/?LinkId=70353 for details). → System.Net.HttpListenerException: Access is denied»

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

]]>
https://pelevin.pro/2014/12/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%b5%d0%b9%d1%88%d0%b5%d0%b9-wcf-%d1%81%d0%bb%d1%83%d0%b6%d0%b1%d1%8b-%d1%87%d0%b0%d1%81%d1%82%d1%8c-2/feed/ 0 1889
Создание простейшей WCF-службы. Часть 1. https://pelevin.pro/2014/12/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%b5%d0%b9%d1%88%d0%b5%d0%b9-wcf-%d1%81%d0%bb%d1%83%d0%b6%d0%b1%d1%8b-%d1%87%d0%b0%d1%81%d1%82%d1%8c-1/ https://pelevin.pro/2014/12/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%b5%d0%b9%d1%88%d0%b5%d0%b9-wcf-%d1%81%d0%bb%d1%83%d0%b6%d0%b1%d1%8b-%d1%87%d0%b0%d1%81%d1%82%d1%8c-1/#respond Tue, 02 Dec 2014 18:04:33 +0000 http://pelevin.pro/?p=1880

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

Часть 1, Часть 2, Часть 3

Введение

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

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

Создание службы

Для создания нашего приложения мы будем использовать Visual Studio 2008. Итак, вызовем диалоговое окно создания нового проекта и выбираем шаблон проекта под названием «WCF Service Library» и дадим ему имя «WcfCalcService».

Проект сейчас состоит из трех основных файлов. Посмотрим, за что каждый из них отвечает.

1. App.config — файл конфигурации приложения. В этом файле также находятся настройки службы;

2. IService1.cs — файл с интерфейсом (контрактом) службы;

3. Service1.cs — файл с классом, реализующим интерфейс (т.е. функционал службы).

Контракт службы

Изначально VS открывает перед нами файл IService1.cs. Это вполне оправдано, ведь разработка любой службы должна начинаться с определения того, что же она все-таки будет делать. Поменяем имя интерфейса на ICalcService (а также переименуем файл в ICalcService.cs). Заметьте, что перед объявлением интерфейса стоит атрибут ServiceContract. Это-то как раз и означает, что данный интерфейс является контрактом WCF-службы.

Примечание:

В комментарии перед кодом интерфейса написано:

// NOTE: If you change the interface name “IService1″ here, you must also update the reference to “IService1″ in App.config.

Что означает: «Если вы измените имя интерфейса «IService1» здесь, вам также нужно будет обновить ссылку на «IService1» в файле App.config». Мы это сделаем чуть позже, а этот комментарий можно удалить.

Примечание:

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

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


OperationContract

Примечание

Ниже описания интерфейса находится описание типаCompositeType, который VS создает для примера. Его можно удалить.

Итак, теперь файл ICalcService.cs выглядит следующим образом:


ServiceContract

Вы, наверное, уже заметили, что мы нигде не описали типыCalcOperationResult и CalcOperationType. Этим мы сейчас и займемся — эти типы будут использоваться для обмена данными между клиентом и службой.

Примечание

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

Вообще, я рекомендую все, используемые для обмена типы, выделять в отдельную сборку, особенно, если вам нужен еще и какой-то общий функционал этих типов. Существует еще один вариант — описать интерфейсы типов, а реализацию сделать различной на клиенте и сервере. Такой вариант хорош при создании более-менее больших и сложных систем. Есть и третья возможность. Студия, при создании ссылки на сервис (Service Reference, это мы рассмотрим подробнее в статье про создание клиентских приложений), автоматически скачивает метаданные (описание структуры и функционала сервиса в специальном формате — WSDL) и по ним генерирует все контрактные типы, но у этого подхода есть два минуса. Первый — у нас нет доступа к методам сгенерированного типа (VS их просто не создает). Второй — для автоматического создания ссылки на службу нужна работающая служба с открытыми метаданными. Это встречается очень редко, если вы хотите создать клиентское приложение для существующей чужой службы. Поэтому, думаю, моя точка зрения по этому вопросу вполне ясна.

CreateProject

Создание проекта с общими типами

Мы воспользуемся первым вариантом: создадим еще одну сборку, добавив в решение новый проект с шаблоном «ClassLibrary» и дав ему имя «CalcCommon».


Добавление ссылки на System.Runtime.Serialization

Добавление ссылки на System.Runtime.Serialization

Чтобы в нашей общей сборке были доступны атрибуты для контрактов, нужно добавить ссылку на сборку System.Runtime.Serialization (правой кнопкой по проекту — Add reference).

Теперь удалим из нового проекта все лишнее, создадим новый файл класса (для этого можно нажать сочетание клавиш Alt+Shift+C) и назовем его CalcOperationResult.cs. Так выглядит описание типа CalcOperationResult:

DataContract

Атрибут DataContract говорит о том, что данный тип используется для описания контракта данных службы и будетсериализуемым специальным диспетчером сериализации (System.Runtime.Serialization.DataContractSerializer). Соответственно DataMember говорит, что данный член класса относится к описанию контракта данных и будет сериализован тем же DataContractSerializer’ом.

Создадим еще один файл, где опишем перечисление CalcOperationType:

EnumDataContract

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

Примечание

Не забывайте в список используемых модулей добавлять строку:
using System.Runtime.Serialization;

AddReference

Добавление ссылки на общую сборку

Отлично! Осталось подключить к проекту службы сборку CalcCommon (правой кнопкой по проекту — Add Reference — закладка Projects) и наш интерфейс полностью готов (не забываем про using CalcCommon).


Продолжение следует — во второй части статьи.

]]>
https://pelevin.pro/2014/12/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%b5%d0%b9%d1%88%d0%b5%d0%b9-wcf-%d1%81%d0%bb%d1%83%d0%b6%d0%b1%d1%8b-%d1%87%d0%b0%d1%81%d1%82%d1%8c-1/feed/ 0 1880
А как Вам метод, тело которого начинается с return? https://pelevin.pro/2014/07/%d0%b0-%d0%ba%d0%b0%d0%ba-%d0%b2%d0%b0%d0%bc-%d0%bc%d0%b5%d1%82%d0%be%d0%b4-%d1%82%d0%b5%d0%bb%d0%be-%d0%ba%d0%be%d1%82%d0%be%d1%80%d0%be%d0%b3%d0%be-%d0%bd%d0%b0%d1%87%d0%b8%d0%bd%d0%b0%d0%b5%d1%82/ https://pelevin.pro/2014/07/%d0%b0-%d0%ba%d0%b0%d0%ba-%d0%b2%d0%b0%d0%bc-%d0%bc%d0%b5%d1%82%d0%be%d0%b4-%d1%82%d0%b5%d0%bb%d0%be-%d0%ba%d0%be%d1%82%d0%be%d1%80%d0%be%d0%b3%d0%be-%d0%bd%d0%b0%d1%87%d0%b8%d0%bd%d0%b0%d0%b5%d1%82/#respond Mon, 07 Jul 2014 15:03:38 +0000 http://pelevin.pro/?p=1377 Друг похвастал какие чудеса он пишет в коде, на работе. Хороший пункт в тему того, почему у разработчика нельзя оставлять наедине с кодом, ему нужен хотя бы еще один в команду, чтобы попинывал и мотивировал.

Готов поиграть в игру: Кто сможет дать максимально подробное описание или комментарии к данному коду или переписать его максимально просто для человеческого прочтения? И сколько на это понадобится времени?

private List<BlankComposition> GetBlankInfo(SKDREntities db, Requisition inz, int deliveryType, long? languageId)
        {
            return db.RuleDescriptions
                .Where(rd => rd.OrganizationId == inz.ReqUnit && rd.IsActive)
                .ToList()
                .Where(rd => rd.DeliveryTypes.Split(',').Select(int.Parse).Contains(deliveryType))
                .DefaultIfEmpty()
                .SelectMany(or => db.RuleDescriptions
                    .Where(rd => rd.OrganizationId == inz.RequisitionOrg.OrgID && rd.IsActive)
                    .ToList()
                    .Where(rd => rd.DeliveryTypes.Split(',').Select(int.Parse).Contains(deliveryType)).DefaultIfEmpty(), (org, lab) => new { org, lab })
                .Select(rule => new[] { rule.org, rule.lab }.Where(r => r != null).ToList())
                .Select(rule => new
                    {
                        HeadHeight = rule.Select(r => r.Composition.HeaderHeight).FirstOrDefault(hh => hh != null) ?? "3cm",
                        FooterHeight = rule.Select(r => r.Composition.FooterHeight).FirstOrDefault(fh => fh != null) ?? "4.5cm",
                        DemographyDescriptionId = rule.Select(r => r.DemographyDescriptionId).FirstOrDefault(),
                        Suffix = rule.Select(r => r.Suffix).FirstOrDefault(),
                        Elements = rule
                                    .SelectMany(
                                        re => re.Composition.CompositionElements,
                                        (rd, element) => new { element, priority = rd == rule.First(), langPriority = element.LanguageId == languageId }
                                    )
                                    .GroupBy(g => g.element.ElementTypeId)
                                    .SelectMany(g => g
                                        .OrderByDescending(e => e.priority)
                                        .ThenByDescending(e => e.langPriority)
                                        .Take(1)
                                        .Select(e => e.element)
                                    )
                                    .Where(e => e.ElementId != null)
                                    .ToList()
                    }
                ).Select(item => new BlankComposition
                    {
                        HeaderHeight = item.HeadHeight,
                        FooterHeight = item.FooterHeight,
                        BlankElements = item.Elements.Select(e => new BlankElement
                        {
                            Width = e.Element.Width,
                            Height = e.Element.Height,
                            Left = e.Element.Left,
                            Top = e.Element.Top,
                            Image = e.Element.ImageId == null ? null : e.Element.Image.Data,
                            Text = e.Element.Text,
                            Placing = e.Placing
                        }).ToList(),
                        Demography = db.DemographyDescriptions
                            .Single(dd => dd.Id == item.DemographyDescriptionId)
                            .DemographyTables
                            .Select(dt => new DemographyInfo
                            {
                                Placing = dt.Placing,
                                Height = dt.Height,
                                Left = dt.Left,
                                Top = dt.Top,
                                Width = dt.Width,
                                Lines = DemographyFormatter.GetDemographyInfo(inz, dt.DemographyType.DemographyContents.OrderBy(o => o.SortOrder).ToList())
                            })
                            .ToList(),
                        Suffix = item.Suffix,
                        AddHyperlinks = item.Elements.Any(hy => hy.ElementTypeId == 6 && hy.ElementId != null)
                    }
                ).ToList();
        }
]]>
https://pelevin.pro/2014/07/%d0%b0-%d0%ba%d0%b0%d0%ba-%d0%b2%d0%b0%d0%bc-%d0%bc%d0%b5%d1%82%d0%be%d0%b4-%d1%82%d0%b5%d0%bb%d0%be-%d0%ba%d0%be%d1%82%d0%be%d1%80%d0%be%d0%b3%d0%be-%d0%bd%d0%b0%d1%87%d0%b8%d0%bd%d0%b0%d0%b5%d1%82/feed/ 0 1377
Цифровые показатели https://pelevin.pro/2014/03/%d1%86%d0%b8%d1%84%d1%80%d0%be%d0%b2%d1%8b%d0%b5-%d0%bf%d0%be%d0%ba%d0%b0%d0%b7%d0%b0%d1%82%d0%b5%d0%bb%d0%b8/ https://pelevin.pro/2014/03/%d1%86%d0%b8%d1%84%d1%80%d0%be%d0%b2%d1%8b%d0%b5-%d0%bf%d0%be%d0%ba%d0%b0%d0%b7%d0%b0%d1%82%d0%b5%d0%bb%d0%b8/#respond Wed, 05 Mar 2014 08:00:46 +0000 http://pelevin.pro/?p=1197 Можно сказать «случайно» я решил посмотреть сколько и чего создалось с помощью инструментов разработанных нашей командой за время работы в OTTO Group Russia.

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

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

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

Больше всего мне нравится база данных размером в ~320 Гб со статистикой за год.

А вообще такой пересмотр статистики позитивная вещь, куча идей появилась.

]]>
https://pelevin.pro/2014/03/%d1%86%d0%b8%d1%84%d1%80%d0%be%d0%b2%d1%8b%d0%b5-%d0%bf%d0%be%d0%ba%d0%b0%d0%b7%d0%b0%d1%82%d0%b5%d0%bb%d0%b8/feed/ 0 1197
Мониторинг сеансов в LiveJournal https://pelevin.pro/2013/03/%d0%bc%d0%be%d0%bd%d0%b8%d1%82%d0%be%d1%80%d0%b8%d0%bd%d0%b3-%d1%81%d0%b5%d0%b0%d0%bd%d1%81%d0%be%d0%b2-%d0%b2-livejournal/ https://pelevin.pro/2013/03/%d0%bc%d0%be%d0%bd%d0%b8%d1%82%d0%be%d1%80%d0%b8%d0%bd%d0%b3-%d1%81%d0%b5%d0%b0%d0%bd%d1%81%d0%be%d0%b2-%d0%b2-livejournal/#respond Mon, 18 Mar 2013 13:40:19 +0000 http://pelevin.pro/?p=804 Пришло гениальное сообщение от сервиса LJ, примерно со следующим содержанием:

«Здравствуйте, kp0h

Кто-то вошел в ваш аккаунт ЖЖ с нового устройства. Информация о сеансе:

Страна: RU

Интернет провайдер: MTS OJSC

IP-адрес: ***.***.***.***

…»

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

http://www.livejournal.com/manage/logins.bml

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

]]>
https://pelevin.pro/2013/03/%d0%bc%d0%be%d0%bd%d0%b8%d1%82%d0%be%d1%80%d0%b8%d0%bd%d0%b3-%d1%81%d0%b5%d0%b0%d0%bd%d1%81%d0%be%d0%b2-%d0%b2-livejournal/feed/ 0 804