пятница, 30 мая 2014 г.

SECR 2013

Был на SECR 2013 в качестве докладчика. По теме поста из этого блога. Результатом доволен, людей было много, никто не ушел, в конце еще минут 50 задавали вопросы.

Ссыль как все было.

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

пятница, 20 сентября 2013 г.

Не надо путать ЧТО и КАК

Иными словами цель и средство её достижения. Каждый раз когда менеджер приходит рассказывает разработчикам КАК нужно что-то делать, его можно и нужно посылать. Лучше вежливо. А надо посылать его узнавать ЧТО нужно сделать. Потому что КАК это сделать -программистам должно быть виднее. Некоторое время веду примерно такой диалог с заказчиками. Новые, неопытные. Мучаются, меня мучают. Как пьеса.

ЭКСКАВАТОР

Действующие лица:
ЗАКАЗЧИК - клиент строительной фирмы
ИСПОЛНИТЕЛЬ - прораб
Сцена первая и единственная. Офис продаж строительной фирмы.

ЗАКАЗЧИК: Итак, какие наши дальнейшие действия по плану строительства?
ИСПОЛНИТЕЛЬ: В настоящее время все идет по плану, но нам требуются некоторые детали проекта, которые еще до конца не формализованы, не утверждены. Мы можем перейти к внешней отделке, но там работы не так много, люди и техника будут частично простаивать.

З: Хм, странно. Мы кажется упоминали что на этой стадии проекта нам нужен экскаватор. Мы можем на это рассчитывать?
И: Конечно. Мы можем организовать экскаватор, у нас есть первоклассные рабочие-экскаваторщики которые могут сделать достаточно сложную работу на нем. Но зачем он нам нужен? Что мы собираемся сделать с помощью него?

З: То есть, у нас будет экскаватор? Отлично. Значит люди и техника будут заняты?
И: Да, если мы придумаем что за работу нужно выполнить на этом экскаваторе.

З: Как что за работу? Разве сам экскаватор не подразумевает определенную работу?
И: Нет. Это всего лишь инструмент. Вот что вам нужно? Яму выкопать там, или котлован? Может быть старый дом снести? Это все можно сделать с помощью него. А может быть можно и каким-нибудь другим способом, возможно дешевле, бульдозером, например.

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

З: Ну так давайте организуем!
И: И что он будет делать? На строй площадке стоять?

З: Ну да. А когда он (вдруг) нам понадобится он рядом будет, под рукой. И мы им воспользуемся.
И: Так давайте когда он понадобится тогда и воспользуемся? Он ведь будет стоять на площадке, мешаться будет. И аренду за него платить придется. Кстати, для чего он может пригодится-то?

З: Как для чего? Выполнять свои экскаваторские действия. На стройке. Как рекомендуют.
И: Понятно. Вы сами поедете на стройку проверять есть он там или нет?

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

З: Дом построить.
Занавес

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

среда, 17 июля 2013 г.

Бэкап в облака - музыка

Продолжаю автоматизировать рутину. На этот раз проблема не столько в рутине как таковой, сколько в несовершенстве мира (да-да, немного немало).
Я большой любитель музыки. В смысле, слушатель. Как и всякий человек, что-то люблю больше, что-то меньше. Для сохранения моих вкусовых пристрастий современное программное обеспечение хочет мне в этом помочь. А именно - Winamp и iTunes позволяют расставлять рейтинги для композиций в своей библиотеке. Чтобы потом по ним можно было формировать умные плейлисты (например, хранить в iPhone / iPod только высокорейтинговые песни добавленные за последние 4 года). Вроде бы все хорошо.

Проблема

Вступает в силу закон дырявых абстракций и функционал "медиа-библиотека" начинает "течь". А именно:
  1. Рейтинг привязывается к конкретному файлу, а не песне как таковой (а точнее - триплету "артист - альбом - песня"). Что приводит к потере рейтинга песни при физическом перемещении файла песни с одного диска/папки/компа на другой.
  2. При хранении двух версий одной и той же песни (например lossless и lossy) рейтинг надо проставлять для каждой в отдельности
  3. Никакого способа автоматически сохранить / бекапить информацию о рейтингах. Есть только ручные операции "экспортировать медиа-библиотеку" и "импортировать медиа-библиотеку". Которые могут сломаться по тем же причинам что и в п.1. Кроме того, операция мануальная и требует, чтобы человек (то есть я), про это вспоминал и куда-то файл с инфой о рейтингах сохранял.
Пару раз я так уже с трудом и любовью выставленные рейтинги терял. То RAID рассыплется, то Windows надо обновлять.

Решение

  1. С помощью AutoIt экспортировать медиа-библиотеку winamp в файл iTunes-xml файл. Рейтинги я расставляю в winamp, поэтому именно он первоисточник.
  2. Питоном разбираю этот XML (он очень тривиальный) и сохраняю в LastFM информацию о рейтинге композиции.
  3. Еще раз прохожу по XML и обновляю рейтинг исходя из LastFM рейтинга. Этот шаг позволит расставить рейтинг в "дубликатах песен" в случае когда рейтинг проставлен для FLAC песни и не проставлен для её mp3 версии.
  4. Тем же AutoIt импортирую получившийся iTunes XML файл в winamp.
  5. Импортировать тот же файл непосредственно в iTunes
Если периодически запускать скрипт который описан выше, в LastFm всегда будет вся информация о рейтингах, которую можно будет легко восстановить при различных катаклизмах с музыкальными файлами или системой.

Детали

Рейтинг будет сохраняться в LastFm в виде тега "N-stars" к каждой песне. N - количество звезд на песне в библиотеке winamp. Благо, LastFm позволяет любое количество тэгов для пользователей. Причем тэги можно как добавлять, так и удалять через LastFm API.  Эта особенность нам нужна, если рейтинг песни будет меняться (разонравилась). Натуральным ограничением для тэга является использование только латиницы и всего пары знаков пунктуации в названии.

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

В процессе работы пришлось дописать lastfmapi (на который я уже ссылался). Дело в том, что pyLast (другой пакет для работы с lastfm) для авторизации методов записи просит md5 пользовательского пароля. Что меня сильно смутило. Кроме того, этот метод признан в LastFm устаревшим и, видимо, скоро его совсем выключат.
Пришлось реализовывать поддержку методов записи в lastfmapi. Это не заняло много времени и не потребовало много изменений. Мою версию lastfmapi можно найти на гитхабе (надеюсь автор замержится обратно). Ну и чтобы два раза не вставать, сделал еще пару write вызовов: композиции с рейтингом 3+ будут скроблиться в LastFm, а композиции с рейтингом "5" - добавляться в категорию "любимых".

Код ниже работает в 2х режимах:
  • обновить LastFm рейтингами из iTunes xml (при этом LaftFm рейтинг не может понизится) - т.н. "бэкап"
  • обновить iTunes xml рейтингами из LastFm (рейтинги из winamp xml перезапишутся) - т.н. "восстановление"
А вот собственно "вкусо-БД".
Код для AutoIt смотрите в следующих сериях.

smogmusicdb.py

1    # coding: utf-8 
2    __author__ = 'Smog' 
3     
4    import re, logging, sys, lastfmapi, time 
5    from xml.dom.minidom import parse 
6     
7    API_KEY = "" 
8    API_SECRET = "" 
9    SESS_KEY = '' 
10   USERNAME = '' 
11   TIME = {'time' : int(time.time())} 
12    
13    
14   def updateLastFmFromiTunesXML(finput): 
15       log = logging.getLogger('mdb') 
16       log.info('Updating ' + USERNAME + ' LastFm library with iTunes data from ' + finput + ' file') 
17    
18       log.info('LastFm is beining initialized') 
19       api = lastfmapi.LastFmApi(API_KEY, API_SECRET) 
20       log.info('LastFm initialized') 
21    
22       log.info('Parsing iTunes media library file: ' + finput) 
23       d = parse(finput) 
24       log.info('Parsed') 
25    
26       root = d.getElementsByTagName('plist')[0].getElementsByTagName('dict')[0].getElementsByTagName('dict')[0] 
27       tracks = root.getElementsByTagName('dict') 
28       log.info('Found ' + str(len(tracks)) + ' tracks in iTunes XML library file') 
29    
30       inc = 0 
31       for t in tracks: 
32           inc += 1 
33           tt = None 
34           ta = None 
35           tal = None 
36           trt = None 
37    
38           for i in range(0, len(t.childNodes)): 
39               node = t.childNodes[i] 
40               if (node.nodeName == u'key'): 
41                   if (node.childNodes[0].nodeValue == u'Name'): 
42                       tt = t.childNodes[i + 1].childNodes[0].nodeValue 
43                   if (node.childNodes[0].nodeValue == u'Artist'): 
44                       ta = t.childNodes[i + 1].childNodes[0].nodeValue 
45                   if (node.childNodes[0].nodeValue == u'Album'): 
46                       tal = t.childNodes[i + 1].childNodes[0].nodeValue 
47                   if (node.childNodes[0].nodeValue == u'Rating'): 
48                       trt = t.childNodes[i + 1].childNodes[0].nodeValue 
49    
50           if (tt != None and ta != None and tal != None and trt != None and int(trt) > 59): 
51               log.debug(str(inc) + ': ' + ta + ' - ' + tt + ' with rating ' + trt + ' found') 
52               uploadTrackToLastFm(api, ta, tt, tal, trt) 
53    
54       log.info('Done.') 
55    
56    
57   def uploadTrackToLastFm(api, artist, track, album, rating): 
58       log = logging.getLogger('mdb') 
59    
60    
61       lastfmTagsJSON = api.track_getTags(artist=artist, track=track, user=USERNAME) 
62       tags = getTags(lastfmTagsJSON['tags']) 
63       lastfmRating = getRating(tags) 
64    
65       if lastfmRating > 0 and int(lastfmRating) < int(rating): 
66           log.info(artist + ' - ' + track + ' (' + album + "): local rating (" + str(rating) + ") is bigger than lastfm (" + 
67                    str(lastfmRating) + "). Remove old rating and albums.") 
68           clearTags(api, tags, artist, track) 
69           lastfmRating = 0 
70    
71       if lastfmRating == 0:     #new track 
72           log.info(artist + ' - ' + track + ' (' + album + "): rating (" + str(rating) + ") be added to LastFm") 
73           addRatingTag(api, artist, track, rating) 
74           addAlbumTag(api, artist, track, album) 
75    
76           api.track_scrobble(artist=artist, track=track, sk=SESS_KEY, timestamp=str(TIME['time'])) 
77           TIME['time']=TIME['time']-300 
78           return 
79    
80       if int(lastfmRating) == int(rating): #existing track 
81           if not isAlbumInTags(album, tags):  #same rating - check album exists 
82               log.info(artist + ' - ' + track + ' (' + album + "): album to be added to LastFm") 
83               addAlbumTag(api, artist, track, album) 
84    
85    
86   def getTags(tags): 
87       if not tags.has_key('tag'): 
88           return set([]) 
89    
90       if isinstance(tags['tag'], dict): 
91           return {tags['tag']['name']} 
92    
93       return set(map(lambda x: x.get('name').lower(), tags['tag'])) 
94    
95    
96   def getRating(tags): 
97       if '5-stars' in tags: 
98           return 100 
99       if '4-stars' in tags: 
100          return 80 
101      if '3-stars' in tags: 
102          return 60 
103      if '2-stars' in tags: 
104          return 40 
105      if '1-stars' in tags: 
106          return 20 
107      return 0 
108   
109   
110  def addRatingTag(api, artist, track, rating): 
111      api.track_addTags(artist=artist, track=track, tags=str(int(rating) / 20) + "-stars", sk=SESS_KEY) 
112      if (rating == '100'): 
113          api.track_love(artist=artist, track=track, sk=SESS_KEY) 
114   
115   
116  def addAlbumTag(api, artist, track, album): 
117      api.track_addTags(artist=artist, track=track, tags=normalizeAlbumName(album), sk=SESS_KEY) 
118   
119   
120  def isAlbumInTags(album, tags): 
121      return normalizeAlbumName(album) in tags 
122   
123   
124  def normalizeAlbumName(album): ##только буквы, цифры, дефисы, пробелы или двоеточия 
125      rus2lat = { 
126          u'й': 'i', 
127          u'ц': 'ts', 
128          u'у': 'u', 
129          u'к': 'k', 
130          u'е': 'e', 
131          u'н': 'n', 
132          u'г': 'g', 
133          u'ш': 'sh', 
134          u'щ': 'sch', 
135          u'з': 'z', 
136          u'х': 'h', 
137          u'ъ': '', 
138          u'ф': 'f', 
139          u'ы': 'y', 
140          u'в': 'v', 
141          u'а': 'a', 
142          u'п': 'p', 
143          u'р': 'r', 
144          u'о': 'o', 
145          u'л': 'l', 
146          u'д': 'd', 
147          u'ж': 'zh', 
148          u'э': 'e', 
149          u'я': 'ya', 
150          u'ч': 'ch', 
151          u'с': 's', 
152          u'м': 'm', 
153          u'и': 'i', 
154          u'т': 't', 
155          u'ь': '', 
156          u'б': 'b', 
157          u'ю': 'u', 
158          u'ё': 'e' 
159      } 
160      allowedChars = re.compile('[a-z0-9\\- :]') 
161      res = '' 
162   
163      for a in album.lower(): 
164          if (allowedChars.match(a) == None): 
165              if (rus2lat.has_key(a)): 
166                  res += rus2lat[a] 
167          else: 
168              res += a 
169   
170      return res 
171   
172   
173  def clearTags(api, tags, artist, track): 
174      for t in tags: 
175          api.track_removeTag(artist=artist, track=track, tag=t, sk=SESS_KEY) 
176   
177   
178  def updateiTunesXMLFromLastFm(finput, foutput): 
179      log = logging.getLogger('mdb') 
180      log.info('Updating iTunes data (' + finput + ' file) with ' + USERNAME + ' LastFm library ratings') 
181   
182      log.info('LastFm is beining initialized') 
183      api = lastfmapi.LastFmApi(API_KEY, None) 
184      log.info('LastFm initialized') 
185   
186      log.info('Parsing iTunes library file:' + finput) 
187      d = parse(finput) 
188      log.info("Parsed") 
189   
190      root = d.getElementsByTagName('plist')[0].getElementsByTagName('dict')[0].getElementsByTagName('dict')[0] 
191      tracks = root.getElementsByTagName('dict') 
192      log.info('Found ' + str(len(tracks)) + ' tracks in iTunes XML library file') 
193   
194      inc = 0 
195      for t in tracks: 
196          inc += 1 
197          tt = None 
198          ta = None 
199          tal = None 
200          ratingValue = None 
201   
202          for i in range(0, len(t.childNodes)): 
203              node = t.childNodes[i] 
204              if (node.nodeName == u'key'): 
205                  if (node.childNodes[0].nodeValue == u'Name'): 
206                      tt = t.childNodes[i + 1].childNodes[0].nodeValue 
207                  if (node.childNodes[0].nodeValue == u'Artist'): 
208                      ta = t.childNodes[i + 1].childNodes[0].nodeValue 
209                  if (node.childNodes[0].nodeValue == u'Album'): 
210                      tal = t.childNodes[i + 1].childNodes[0].nodeValue 
211                  if (node.childNodes[0].nodeValue == u'Rating'): 
212                      ratingValue = t.childNodes[i + 1].childNodes[0] #.nodeValue 
213   
214          if (tt != None and ta != None and tal != None): 
215              log.debug(str(inc) + ": " + ta + ' - ' + tt + ' (' + tal + '). Loading LastFm info...') 
216              lastfmTagsJSON = api.track_getTags(artist=ta, track=tt, user=USERNAME) 
217              tags = getTags(lastfmTagsJSON['tags']) 
218              newrating = getRating(tags) 
219              log.debug('Got ' + str(newrating) + ' rating in ' + unicode(tags)) 
220   
221              if (newrating > 0 and isAlbumInTags(tal, tags)): 
222                  if (ratingValue == None): 
223                      log.info(ta + ' - ' + tt + ' (' + tal + '). Rating created.') 
224                      addRatingXMLEntries(d, t, str(newrating)) 
225                  else: 
226                      log.info(ta + ' - ' + tt + ' (' + tal + '). Rating updated.') 
227                      ratingValue.nodeValue = str(newrating) 
228   
229      log.info('Saving results to: ' + foutput) 
230      f = open(foutput, 'wb') 
231      f.write(d.toprettyxml(indent='', newl='', encoding='utf-8')) 
232      f.close() 
233      log.info('Done.') 
234   
235   
236  def addRatingXMLEntries(xmlDocument, trackElement, rating): 
237      ratingK = xmlDocument.createElement('key') 
238      ratingK.appendChild(xmlDocument.createTextNode('Rating')) 
239      trackElement.appendChild(ratingK) 
240   
241      ratingV = xmlDocument.createElement('integer') 
242      ratingV.appendChild(xmlDocument.createTextNode(rating)) 
243      trackElement.appendChild(ratingV) 
244   
245   
246  #------------------------- MAIN ---------------------------------------------------------------------------------------- 
247   
248   
249  def initializeLogging(): 
250      logger = logging.getLogger('mdb') 
251      logger.setLevel(logging.DEBUG) 
252   
253      h = logging.FileHandler('log.txt') 
254      logger.addHandler(h) 
255      h.setLevel(logging.DEBUG) 
256      h.setFormatter(logging.Formatter('%(asctime)s %(funcName)s %(levelname)s\t%(message)s')) 
257   
258      h = logging.StreamHandler(sys.stdout) 
259      h.setLevel(logging.INFO) 
260      logger.addHandler(h) 
261   
262  if __name__ == "__main__": 
263      initializeLogging() 
264   
265      if (sys.argv[1] == '--lastFm2iTunes'): 
266          updateiTunesXMLFromLastFm(sys.argv[2], sys.argv[3]) 
267   
268      if (sys.argv[1] == '--iTunes2LastFm'): 
269          updateLastFmFromiTunesXML(sys.argv[2]) 
270  

воскресенье, 14 апреля 2013 г.

Software people 2013

Совершенно случайно вышло что почти сразу после Agile Days я попал на Software people. Расскажу о впечатленях.

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

Два пленарных доклада в начале дня были просто провальными. Эдвард Йордон рассказал много биографических данных и почти ничего по теме. Да, человек уважаемый, но аудиторию тоже нужно уважать. Интересный факт я услышал один - когда-то IBM увольнял худших 10% сотрудников. Ежегодно.

Дэвид Гарлан рассказывал домохозяйкам аудитории что такое архитектура и как её готовить.

Александр Лесневский оттачивал на участниках конференции навыки психотерапевта. Получилось не очень. На главный вопрос "Что сильнее мотивации?" ответил в стиле кэпа - "бессознательное".

Артем Кумпель наверное был первым человек в этот день, кто рассказал интересную информацию и подтвердил её цифрами. Некоторые из них правда вызывали сомнения. В сухом остатке - чистый заработок в Москве и США примерно одинаков. Эмиграция за большим рублем долларом больше не актуальна. Средние зарплаты (по вакансиям) в районе 90-100 тыс руб чистыми для middle java developer.

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

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

Докладчики из Стратоплана тоже затронули тему мотивации, но прошлись по паре соседних тем (видимо чтобы показать свою компетентность :). Регулярные встречи один-на-один помогают синхронизировать ожидание оценки действий сотрудника и саму оценку от менеджера. Техника проективных вопросов - определенно скилл который надо отращивать. Предположим, есть какое-то качество, которое требуется проверить. Или выяснить позицию по определенному вопросу. Если начать выяснять это напрямую (например "Что заставляет вас работать когда начальника нет на рабочем месте?"), можно с высокой вероятностью нарваться на социально-ожидаемый ответ ("Моя личная ответственность за результат работы"). Чтобы узнать, что человек думает по-настоящему, нужно спросить не о нем, а о других людях. Рассказывая от других, он будет рассказывать о себе. Такие вопросы формулировать сложнее и отвечать на них тоже будет сложнее поэтому важно задать 7-8 вопросов на одну тему и в хорошем темпе (необязательно подряд).

Второй день открывала Наталья Руколь. Было много очевидных моментов которые компенсировались позитивом и харизмой докладчицы. Несколько интересных вещей которые я отметил:
  • Крутизна (периодически делать что-то на очень высоком уровне - чтобы могли оценить)
  • Соответствие слова и дела (доказывать на личном примере)
  • Разговор по душам (уже говорилось об этом вчера. Без нерабочей части жизни сотрудника его сложнее мотивировать)
  • Стигматы (недостатки с которыми не сил/смысла/желания бороться. Выход - их открыто признать и заставить всех к ним подстроиться)
Очень рекомендовала книжку "Надо нарушить все правила".

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

Максим Дорофеев и Алексей Пименов оправдали ожидания. Рассказали и показали как применять несложный математический инструмент (контрольные карты Шухарта) для оценки производительности программистов. По сути, мастер класс являлся экспериментом к статье на Хабре, только под другим углом. Ребята молодцы - было весело и продуктивно. 

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

Владимир Железняк (видимо) на своем примере рассказал историю развивающейся компании и о том как разные социальные роли (да, да - еще одна классификация) в ней взаимодействуют. Роли следующие: Родитель-Взрослый-Дитя. 


понедельник, 1 апреля 2013 г.

Agile Days 2013

Посчастливилось поучаствовать в Agile days 2013.
Здесь хочу выложить мыслекарты, которые я набросал будучи на интересных докладах (на неинтересных докладах мыслекарты почему-то не составлялись).

День первый


Jeff Patton Co-making Great Products
Посыл был достаточно простым - парни, со всеми вашими гибкими методологиями, не забывайте что ваша цель - делать мир лучше. А не листочки на стенки клеить.

Сергей Рогачев (Астерос Лабс) Усвоенные уроки одной кроссфункциональной команды разработки
Ребята просто делились опытом. Очень старались, хотя местами диалог выглядел натянуто. Таких докладов надо больше - искренних, с реальным опытом и без консалтингового лоска.

Кирилл Климов (Люксофт) СанФранциско-Киев: история внедрения распределенного проекта 100+
Типичный Люксовый доклад про то, как у них получился Эджайл при аутсорсинговой работе. Всё получилось, все молодцы.

Прошу прощения у докладчидцы за ошибку организаторов, назвавших несуществующую страну "Чехословакия" как место, откуда она прибыла. Английский мог бы быть и получше. Было тяжеловато слушать. Приведенные примеры впечатлили: 
  • ролик, где парень покупал 4500$ кольцо за пачку бумаги
  • интерактивная сессия которая показавшая, что люди встают на сторону начальника при прочих равных
  • как продать эджайл боссу, если он...
Было интересно, но видимо я подразумевал под "communication" другое...

Блиц доклады 
Мне очень понравились. Докладчик не тратил время на обертку (кто он, откуда, что делает, как он любит эджайл, какой умный Асхат Уразбаев и т.п.), просто выкладывает суть и уходит. Никакой сессии с дурацкими вопросами (типа "а у вас стендапы сколько длятся по времени?"). Вышел - рассказал - следующий.
Как всегда зарядил позитивом Стас Фомин. Определенно его нужно выпускать в первой половине дня - чтобы заряжать участников :)

Михаил Заборов (Custis), Асхат Уразбаев (ScrumTrek) Долой догматы SCRUM
То, что мне не понравилось от слова совсем. Было видно, что парням наскучило вторую пятилетку одно и тоже рассказывать. Поэтому, чтобы не остаться без работы, они выдумали себе вызов - "а давайте откажемся от одной из аксиом, которые у нас в фундаменте, и посмотрим куда здание поведет и где нужно будет конструкцию укреплять". Видение того, как и где нужно укреплять у докладчиков разнились, что порождало еще больший конфуз. Аудитории это, правда, казалось смешным, но я склонен считать это нервным смехом от замешательства, нежели самоиронией. Ну, и конечно 2 фразы войдут в анналы:
  • Что вы делаете когда фейлите интерацию? - Начинаем новую!
  • Скрамтурбация - специальное слово означающее "культ карго про скрам". Синоним - скрамно (ударение на О).

День второй


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

Очень харизматичный докладчик. В консультанты пойдет :) Всего две мысли - но очень полезные.

Андрей Ребров (ScrumTrek) DevOps - очередное красивое слово или следующая ступень эволюции?
Не в первый раз слышал про DevOps. В общем, доклад наполовину пересказывал то, что я уже знал.

Блиц доклады в этот день были бледной тенью вчерашних. Могу выделить только
Игорь Клейнер (Майкрософт) Гибкая разработка - психология и псевдопсихология?
Зона Лосада - надо раскапывать что там и как.

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

Напоследок - самая важная мыслекарта. То, что я буду пробовать применять. То, что стоит поизучать. То, как возможно решить проблемы. По понятным причинам, прочитать вы ее не сможете :)



В целом конференция мне понравилась больше чем в 2011 году. Место проведения тоже хорошее. Мелкие недостатки оставались мелкими для конференции такого масштаба (так что даже упоминать их не буду). Ребята-организаторы молодцы. Спасибо!