Мой профиль...

Search This Blog

Thursday, August 27, 2015

Бортовой журнал разработчика

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

Из бортового журнала разработчика:

1. Иногда достаточно лишь не опускать рук. Как говорил Шайа Лабаф — «Если ты устал начинать сначала, перестань сдаваться». С кривой обучения человек сталкивается практически в любой области новых знаний, и программирование — не исключение. Потом усвоенное будет казаться чем-то самим собой разумеющимся, но не всё сразу. Сначала придется пройти через период сомнений, страхов, ощущения себя круглым идиотом и даже бездарью. Протяженность этого времени у каждого своя, но его важно пережить, чтоб не оказалось, что ты бросил дело на полпути без серьезных на то оснований. Для этого полезно обозначать для себя контрольные точки в духе «Несмотря ни на что я продержусь ещё минимум полгода, а там будет видно».
2. Плато. Это будет следующий неизбежный отрезок на кривой обучения. Когда ты на плато, то прогресс не ощущается даже при регулярных занятиях. Напоминает блуждания в густом тумане, когда неясно, сколько ты прошел. Здесь снова выручат метрики, нужно лишь взять диапазон пошире — не недели, а месяцы. Если навыки сегодня круче, чем N месяцев назад, значит, прогресс есть. Учеба, как и многие другие процессы в нашей жизни, нелинейна, поэтому лучше сразу распрощаться с иллюзиями, что затратив время T, ты обязательно получишь конкретный результат X. Вспомните, как по несколько часов из-за невнимательности не могли найти лишнюю запятую или пробел. Или сколько времени вам потребовалось, чтобы понять и принять ООП; и как странно видеть человека, которому вроде и объяснишь на пальцах — а он всё равно продолжает плавать?
3. Страх перед неизведанным. Он будет всегда (разве что заблаговременно тяпнуть стопочку коньяку): первый коммит, первый откат, первый упущенный дедлайн и деплоймент на продакшн — такие вещи редко проходят без потеющих ладоней и учащенного сердцебиения. Бояться, когда не уверен — это нормально и говорит хотя бы о том, что вам не всё равно. Страх не нужно побеждать, с ним лучше заключить союз. Делая то, чего боишься, получаешь для себя больший результат, чем занимаясь привычными вещами. Но для команды такой подход почти наверняка аукнется выгребанием твоих ошибок.
4. Много работать — не значит хорошо работать. Как и морщить лоб, цокать языком или ходить взад-вперёд у whiteboard’a. Легко впасть в соблазн почитать себя за героя, если засиделся на работе. Но часы, насиженные пятой точкой — это одно, а работающий код (ещё точнее — результат) — это другое. Кто знает, может, лучше было прийти на работу пораньше, чем уходить последним? Тем более, что даже при одинаковых зарплатах, ценность времени каждого разработчика всё равно различается. Разница в продуктивности может бытьболее чем десятикратной — когда, например, твой день работы равняется одному часу работы вон того тихого парня в углу, который никогда не вылазит из наушников.
5. Не стоит хвастаться, что работаешь больше других. По этому поводу высказался сооснователь Facebook Дастин Московиц: «Я часто слышу, как молодые разработчики хвалятся своими 48-часовыми спринтами. Такое отношение к работе не только вредит молодым работникам, которые хотят соответствовать ожиданиям, но и порождает возрастную и половую дискриминацию — ведь не каждый сотрудник способен поддерживать такой рабочий график». При этом дискриминация проходит не только по линии возраста и пола, но и вообще по всему живому в офисе, что уходит домой раньше срока. Волей-неволей, уходя с работы на пару часов позже остальных, ты выставляешь остальных коллег в менее «трудолюбивом» свете, забирая себе их лавры труженников. Никто не любит выскочек с геройским выражением лица.
6. Самообман. В глубине души каждый знает что он сделал, а что — нет, где он постарался на 100%, а где протунеядил. Но это знание скрывается под покровом лжи, сотканной из изощреннейших нитей самообмана. Всегда приятней убедить себя, что ты трудолюб, раз N часов подряд искал баг, чем признать, что сам же его и породил или что найти его можно было и за пять минут. Всегда есть соблазн скорчить умную рожу на собрании, обманув тем самым не только начальство и коллег, но и себя. Не надо. Как говорил Мюнхгаузен, «Умное лицо — это ещё не признак ума. Все глупости на земле делаются именно с этим выражением лица.»
7. Ментальное рабство — не повод для гордости. Многие разработчики бахвальствуют о том, что их мозг работает над задачей и в нерабочее время, выполняя, по сути, двойную работу по восьмичасовому тарифу. Скажите об этом соседу с удочкой, который уставился на поплавок и ни о чем не думает, или своей жене во время выполнения супружеского долга. Как вариант можно прийти в гости к друзьям и вместо участия в разговорах и настольных играх, развернуть ноут и срочно начать работать — потому что вас осенило. Посмотрите на их реакцию (конечно, если у вас друзья не на морозе). Поводом для гордости могла бы быть как раз обратная привычка — на работе думать только о работе, в свободное время — об остальном.
8. Здоровье важнее. Для Facebook 2006-й год был одним из лучших, но для того же Дастина Московица — одним из худших:
«Неделю назад я общался с талантливыми студентами из Беркли. Некоторые из них задали мне вопросы о том, что бы я хотел узнать или сделать в своей жизни раньше; о сожалениях, касающихся раннего периода моей карьеры. Снова и снова я прихожу к мысли, что мне следовало жить иначе. Больше спать, регулярно заниматься спортом, следить за тем, что я ем и пью — ведь были времена, когда я потреблял энергетиков и газировки больше, чем воды; Тогда бы у меня было не только меньше панических приступов, но и не было бы серьезных проблем со здоровьем, когда в свои 20 с лишним лет спину от боли хоть на свалку выбрасывай; Думаю, я был бы не только более уравновешенным, но и работал бы эффективнее».
9. Являть себя. Или, как говорил Вуди Аллен, «Являться — это 80% жизни. Иногда проще прятаться дома на диване».
Потом он добавил: «По моим наблюдениям, стоило человеку таки закончить пьесу или роман, как он существенно продвигался на пути к её постановке или публикации, в отличие от подавляющего большинства людей, которые говорят мне, что они хотят писать, при этом никогда не пишут ни одной пьесы или книги, и таким образом терпят неудачу на самой первой ступеньке». Являть себя можно как физически — например, посещая работу, вечеринки, мероприятия или тренировки (где само появление в любом случае приводит к результату), так и через свой труд — например, написанием приложений или композиций, созданием продукта или сервиса. Таким образом, сидеть дома и ничего не делать — значит расписаться в собственном отсутствии в мире.
10. Не молчать. Как говорил мой тренер из ЮАР, который является не только топовым бойцом, но и успешным бизнесменом, «Важно говорить о том, что ты делаешь. Минимум 50% твоего успеха — это то, что ты говоришь о себе и то, что люди думают о тебе». Можно быть сколько угодно продуктивным разработчиком, но если ты всё время молчишь (в письмах ли, в дисскуссиях ли), тебя начинают потихоньку забывать. Ещё и премию твою отдадут какому-нибудь холеному выскочке в костюме с улыбкой на миллион. Можно сколько угодно усердно искать работу, но упустить свой шанс лишь потому, что люди вокруг не в курсе. Это относится и ко многим другим сферам жизни, будь то нужда сплавить котят, сдать квартиру или найти подругу.

Thursday, August 20, 2015

Howto rename branch in mercurial?

hg update old_name
hg branch new_name
hg commit -m "Changing old_name branch to new_name."
hg update old_name
hg commit --close-branch -m "use new_name instead."
hg push --new-branch

Wednesday, March 18, 2015

MySQL logging - Логируем запросы к MySQL

Рано или поздно возникает необходимость логированя запросов, которые попадают на MySQL сервер. Это могут быть как slow query так и все запросы.

До версии 5.1.12 дожно было запустить mysql с параметром log
mysqld --log=log_file_name
или же записать в my.cnf параметр
log = log_file_name
Начиная с версии >= 5.1.12 имеем три параметра:
  • --log-output=TABLE,FILE
  • --general_log
  • --slow-query-log
Либо же выполнив следующий запросы:
SET global general_log = 1;
SET global log_output = 'table';
Table - это таблица в mysql.general_log, имеющая следующую структуру:
CREATE TABLE `general_log` (
   `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
                          ON UPDATE CURRENT_TIMESTAMP,
   `user_host` mediumtext NOT NULL,
   `thread_id` bigint(21) unsigned NOT NULL,
   `server_id` int(10) unsigned NOT NULL,
   `command_type` varchar(64) NOT NULL,
   `argument` mediumtext NOT NULL
  ) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log'
Для slow-query-log структура будет следующей:
CREATE TABLE `slow_log` (
   `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP 
                          ON UPDATE CURRENT_TIMESTAMP,
   `user_host` mediumtext NOT NULL,
   `query_time` time NOT NULL,
   `lock_time` time NOT NULL,
   `rows_sent` int(11) NOT NULL,
   `rows_examined` int(11) NOT NULL,
   `db` varchar(512) NOT NULL,
   `last_insert_id` int(11) NOT NULL,
   `insert_id` int(11) NOT NULL,
   `server_id` int(10) unsigned NOT NULL,
   `sql_text` mediumtext NOT NULL,
   `thread_id` bigint(21) unsigned NOT NULL
  ) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log'

Если же нужна генерация в файл, то можно выполнить следующие запросы:
SET global log_output = 'FILE';
SET global general_log_file='/home/slava/mysql_queries.log';
SET global general_log = 1;

Sunday, March 15, 2015

Блог переезжает на новый домен - blog move to www.sundrop.info

Уважаемые читатели!

В связи с тем что 22-го марта истекает срок регистрации предыдущего домена, а регистрационные данные, увы, принадлежали не мне (будет мне уроком) и способа продлить домен я не нашел (ну не хотят GoDaddy брать деньги с меня) было принято решение переехать просто на новое доменное имя.

Итого, вместо www.sundrop.name имеем www.sundrop.info
У меня все!

Thursday, December 11, 2014

Многопоточность в MFC (multithreading)

Поток – отдельная ветвь выполнения программы. Имеет свой стек и работает независимо от других потоков приложения.

Создание простейшего потока
AfxBeginThread(ProcName,param,priority)
ProcName – имя функции, которая будет выполнятся в новом потоке
param – указатель типа LPVOID или void* на аргумент ProcName
priority – константа, определяющая приоритет нового потока по отношению к основному

Может принимать одно из следующих значений:
THREAD_PRIORITY_ABOVE_NORMAL  // на один пункт ниже нормального
THREAD_PRIORITY_BELOW_NORMAL  //на один пункт выше нормального
THREAD_PRIORITY_HIGHEST  //на два пункта выше нормального
THREAD_PRIORITY_IDLE  //базовый приоритет равный 1
THREAD_PRIORITY_LOWEST  //на два пункта ниже нормального
THREAD_PRIORITY_NORMAL  //нормальный приоритет
THREAD_PRIORITY_TIME_CRITICAL  //приоритет равный 15
Приоритет потока определяет, как часто по отношению к другим выполняющимся потокам система будет передавать управление данному потоку
UINT ThreadProc(LPVOID param)  //Создание потоковой функции
{
    ::MessageBox((HWND)param, ”Thread activated”,”Message from Thread” ,MB_OK);
    return 0;
}

SomeFunc()
{
    AfxBeginThread(ThreadProc,GetSafeHwnd()); //Запуск потока
}
Синхронизация работы потоков.

1. Глобальная переменная
bool bThreadstop;  //контрольная переменная

UINT ThreadProc(LPVOID param)  //Создание потоковой функции 
{
    ::MessageBox((HWND)param, ”Thread activated”,”Message from thread”,MB_OK);
    while(!bThreadstop)
    {
         //Выполнение опреаций
    }

    ::MessageBox((HWND)param, ”Thread ended”,”Message from thread”,MB_OK);
    return 0;
}

SomeFunc()
{
    bThreadstop=false;
    AfxBeginThread(ThreadProc,GetSafeHwnd());  //Запуск потока
}

StopThread()
{
    bThreadstop=true;  //остановка потока
} 
2. Взаимодействие с помощью сообщений 
const WM_THREADENDED = WM_USER+1;  //Это надо добавить в катры сообщений

afx_msg LONG OnThreadEnded(WPARAM wParam,LPARAM lParam);

ON_MESSAGE(WM_THREADENDDED,OnThreadEnded)

bool bThreadstop;  //контрольная переменная 

UINT ThreadProc(LPVOID param)  //Создание потоковой функции 
{
    ::MessageBox((HWND)param, ”Thread activated”,”Message from thread”,MB_OK);
    while(!bThreadstop)
    {
         //Выполнение опреаций
    }

    ::PostMessage((HWND)param,WM_THREADENDED,(WPARAM)param,0); //Сообщение
    return 0;
} 

SomeFunc()
{
    bThreadstop=false;
    AfxBeginThread(ThreadProc,GetSafeHwnd()); //Запуск потока
}

StopThread()
{
    bThreadstop=true;  //остановка потока
}

LONG OnThreadEnded(WPARAM wParam, LPARAM lParam)
{
    ::MessageBox((HWND)wParam,”Thread Ended”,”Message from thread”, MB_OK);
}

//Данный пример закрывает главное окно после выполнения потоковой функции
3. Взаимодействие с помощью объектов событий

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

ThreadStart.SetEvent();  //установка состояния сигнализации
Отслеживание состояния объекта осуществляется с помощью функции WinAPI WaitForSingleObject();
:: WaitForSingleObject(ThreadStart.m_hObject,INFINITE);
- первый параметр – дескриптор отслеживаемого события.
- второй параметр – время отслеживания. INFINITE – бесконечно.

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

Это можно сделать следующим способом:
::WaitForSingleObject(ThreadStart.m_hObject,0);
Время 0 говорит о том, что надо опросить событие.
Если результат вызова этой функции равен WAIT_OBJECT_0, то объект в остоянии сигнализации. В других случаях – молчит.
CEvent ThreadStart;  //Объект начала работы потока
CEvent ThreadEnd;  //Объект окончания работы потока

UINT ThreadProc(LPVOID param)  //Создание потоковой функции
{
    :: WaitForSingleObject(ThreadStart.m_hObject,INFINITE);  //ожидание запуска потока
    ::MessageBox((HWND)param, ”Thread activated”,”Message from thread”,MB_OK);
    bool Running=true;
    int result;
    while(Running)
    {
         //Выполнение опреаций

        result=:: WaitForSingleObject(ThreadEnd.m_hObject,0);  //проверка завершения
        if(result==WAIT_OBJECT_0)
            Running=false;
    }

    ::PostMessage((HWND)param,WM_CLOSE,0,0); //Сообщение

    return 0;
}

Start()  //запуск потока
{
    ThreadStart.SetEvent();
}

End()  //завершение потока
{
    ThreadEnd.SetEvent();
}
Поток нужно создавать независимо от состояния событий.


Синхронизация работы нескольких потоков

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

1. Критические секции.

Критические секции используются для контроля доступа к защищенным данным.

Их можно использовать внутри одного класса для синхронизации чтения-доступа к данным.
class cls
{
private:
    int val;
    CCriticalSection section;
public:
    void write(int);
    void read(int*);
}

void cls::write(int n)
{
    section.Lock();
    val=n;
    section.Unlock();
}

void cls::read(int * n)
{
    section.Lock();
    *n=val;
    section.Unlock();
}
При вызове метода Lock() происходит блокировка секции, и последующие вызовы этого метода не возвратят управление вызывающему потоку до тех пор, пока секция не будет освобождена.
Из данного примера видно, что при записи нового значения невозможно прочитать старое. Соответственно при чтении значения его невозможно изменить. Если в работе участвуют большие объемы данных, то для предотвращения сбоя необходим контроль. Критические секции обеспечивают минимальную защиту от сбоев.

2. Защелки(MUTEXes) 

Использование защелок CMutex при синхронизации потоков одного приложения не отличается от использования критических секций. Работа с ними осуществляется с использованием следующих объектов: CSingleLock и CMultiLock. Для получения доступа к защелке используется методо Lock(). Для освобождения защелки нужно вызвать метод Unlock()
CMutex mutex;  //создание защелки

CSingleLock sLock(&mutex);  //захват защелки

sLock.Lock();

sLock.Unlock();  //освобождение защелки

class cls
{
private:
    int val;
    CMutex mutex;
public:
    void write(int);
    void read(int*);
}

void cls::write(int n)
{
    CSingleLock sLock(&mutex);

    sLock.Lock();
    val=n;
} 

void cls::read(int * n)
{
    CSingleLock sLock(&mutex);

    sLock.Lock();
    *n=val;
}
Использование метода Unlock() в данном случае необязательно т.к. при вызове деструктора sLock защелка автоматически освобождается.

3. Семафор

Использование этого объекта ничем не отличается от использования предыдущих. Разница заключается в том, что семафор дает право на использование контролируемых параметров определенному числу потоков. В семафоре хранится количество объектов, которые в данный момент имеют доступ к данным. 
CSemaphore semaphore(2,2);  //создание семафора
При создании семафора указывается начальное и максимальное значение счетчика 
CSingleLock sLock(&semaphore);  //Захват семафора
sLock.Lock(); 
При вызове метода Lock() значение счетчика внутри семафора уменьшается. Когда оно достигнет нуля, метод Lock() будет ждать освобождения семафора. После этого захватит семафор и вернет управление вызывающей функции
sLock.Unlock();  //Освобождение семафора

Tuesday, December 9, 2014

Закон Конвея - Conway's law

Итак, Джон Конвей когда-то заявил что:
Organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations
что можно перевести как:
Организация которая разрабатывает систему ... вынуждена делать систему по структуре повторяющую структуру коммуникаций внутри организации
В общем если в компании разрабатывающей ПО есть 3 отдела, которые занимаются этим проектом, то он, с точки зрения архитектуры, будет представлять из себя 3 больших модуля.

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

Причем если эти команды тесно общаются, например устраивая ежедневные skype митинги и вообще, то и модули будут тесно связаны — например единая сборка, репозиторий, документация, трекер, но разные библиотеки лежащие рядом. Но если общаются лишь переписываясь по email, то получите связь через какой нибудь RESTful API.
Десятки раз видел подобные примеры.

Или, как сказал Эрик Реймонд:
Если у вас есть 4 команды разрабатывающие один компилятор — вы получите компилятор работающий в 4 прохода (4-pass compiler)
См. закон на википедии: Conway's law

Релевантные посты...

Related Posts with Thumbnails