вторник, 31 марта 2015 г.

Объявление. Ищу сотрудника для реализации проекта

Ищу сотрудника для реализации проекта - http://programmingmindstream.blogspot.ru/2014/11/mindstream.html

Скажем так - на "пол-ставки" во внерабочее время.

БЕЗ официального оформления.

Если кому-то сильно надо ОФИЦИАЛЬНОЕ оформление - это тоже можно устроить.

Наверное не из Москвы. Ибо московских расценок - я не потяну. Желательно откуда-нибудь из Твери/Можайска. Чтобы несложно было встретиться лично. Хотя личные встречи - необязательны.

Хотя и "более дальние регионы" - тоже годятся. Также Украина/Белоруссия - приветствуются.

Конкретно о цене - будем договариваться лично. Я - не жадный. Но у меня есть лимит.

Требования:

1. Delphi.
2. UML желательно.
3. Git (ну или CVS/SVN). Что-то одно - ОБЯЗАТЕЛЬНО.
4. Знакомство с GoF желательно.
5. Понимание анонимных функций (лямбд) и обобщений (Generic'ов) желательно.
6. Знакомство с DUnit желательно.
7. Умение работать с баг-треккерами.

Занятость - 2-4 часа в день.

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

Если вы делаете, то что надо, то потраченное время работы - меня вообще не интересует.

Могу выдать тестовое задание. А можем просто "плавно начать" втягиваться.

И ещё - Коротко. Чтобы "писать код".... Надо садиться и "писать код".

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

Адрес для связи - lulinalex@gmail.com.

(+) https://freelance.ru/projects/mindstream-uml-498115.html

Лицензией на Delphi (XE7) и AraxisMerge - я обеспечу. Всё остальное - по личной договорённости.

Да и ещё. Если "вдруг" проект продастся кому-нибудь и начнёт "приносить прибыль", то я готов обещать "долю в прибыли" тем участникам с кем "сработаемся".

Ссылка. Работаем с Compound File

http://alexander-bagel.blogspot.ru/2015/03/compound-file.html

Ну а я в свою очередь отмечу, писал собственную реализацию IStorage. И она у нас до сих пор с успехом используется.

MindStream. Оглавление


На русском:

MindStream. Как мы пишем ПО под FireMonkey
MindStream. Как мы пишем ПО под FireMonkey. Часть 2
MindStream. Как мы пишем ПО под FireMonkey. Часть 3. DUnit + FireMonkey
MindStream. По мотивам GUIRunner
MindStream. Как мы пишем ПО под FireMonkey. Часть 4 Serialization
MindStream. Как мы пишем ПО под FireMonkey. Часть 5. Тестирование

MindStream, Windows version. Pre-Alpha
MindStream. preAlpha2
MindStream. preAlpha3
MindStream Scroll. Pre-Alpha
MindStream. Всё ещё preAlpha. Как мы умеем танцевать :)
Ещё один скриншот того, что мы делаем

Репозиторий
И ещё один репозитарий
И ещё репозитарий

In English:

MindStream. How we develop software for FireMonkey
MindStream. How we develop software for FireMonkey. Part 2
MindStream. How we develop software for FireMonkey. Part 3. Firemonkey + DUnit
MindStream. How we develop software for FireMonkey. Part 3.1. Inspired by GUIRunner
MindStream. How we develop software for FireMonkey. Part 4. Serialization
MindStream. How we develop software for FireMonkey. Part 5. Testing


Сопутствующие материалы:

Draft
Коротко. Контроль за созданием/освобождением объектов. Только код
Коротко. Контроль за созданием/освобождением объектов. Только код. №2
Коротко. Контроль за созданием/освобождением объектов. Только код. №3
Коротко. Контроль за созданием/освобождением объектов. Только код. №4
Коротко. Размножение тестов относительно параметра. Только код
MindStream в движении. Развиваем "предметную область". Только код
MindStream в движении. Развиваем "предметную область". Только код №2
MindStream в движении. Развиваем "предметную область". Только код №3
MindStream в движении. Развиваем "предметную область". Только код №4
MindStream. Ещё один скриншот
MindStream. Ещё скриншот
MindStream актуальная версия. Всё ещё preAlpha
MindStream. Коротко. Статистика использования объектов
Коротко. MindStream. TmsSVGShape. Только код
Паттерны проектирования использованные при разработке нашего приложения

Сопутствующие "заметки":

И ещё раз про "примеси". Теперь - "серьёзно"
И ещё про "примеси". Только код

Коротко. Про афинные преобразования. Только код

Коротко. Про TDD и "догматику". Только код

Коротко. MindStream. Как мы пишем ПО под FireMonkey. Часть 4 Serialization

Ещё про примеси. Выделяем класс TmsIvalidator. Только код
Ещё про примеси. Отвязываем данные от View. Только код

MindStream. Вспоминаем школьную тригонометрию. Только код. Что тут написано?
Коротко. Ссылка на коммит. Примешиваем примесь к Generic'у (обобщению)
Коротко. "Вкусности" Delphi XE7. На примере TPointF и TPolygon
Коротко. MindStream. Используем Cleanup вместо Destroy
Коротко. DUnit не освобождает свои тесты. НИКОГДА
Коротко. MindStream. Движемся к мета-модели. Только ссылка на коммит
Только коммит. Иногда тривиальные ошибки лежат не на поверхности
Черновик. Вариации на тему TDD
Прямо скажем... Delphi для Android "восторга не вызывает"...
Как я дружил Delphi XE7 с устройствами Samsung
Запуск на эмуляторе


"Похожие":

http://programmingmindstream.blogspot.ru/2015/02/blog-post_5.html
Офигенная ссылка
Ссылка. drive.draw.io
Ссылка. Scratch
Ссылка. UML Design

понедельник, 30 марта 2015 г.

Коротко. Чтобы "писать код".... Надо садиться и "писать код"

Чтобы "писать код".... Надо садиться и "писать код".

А не тереотизировать на тему "как будет здорово построить мост".

"Тупо" САДИТЬСЯ и ПИСАТЬ. БЕЗ затей.

Просто "тупо писать".

И СТРЕМИТЬСЯ "выполнить поставленную задачу".  И не думать про "постройку моста".

"Код не понравился" - это НЕ ПОВОД не писать код вообще.

ЗАДАЧУ, надо СНАЧАЛА закрыть "как есть", а ПОТОМ - написать ЗАДАЧУ на РЕФАКТОРИНГ особенно, когда ТЕРЯЕТЕ ТЕМП.

А не тянуть вола за хвост.

И НЕ НАДО "сферических коней" на "будущее". Будущего у сферических коней - НЕТ.

Есть код, есть тесты, есть рефакторинг. Есть ТЗ в конце-концов. Всё.

НИКАКИХ "коней".

ВСЕ "фреймворки" и "обобщения" ДОЛЖНЫ БЫТЬ выстраданы в ЕЖЕДНЕВНОЙ разработке и БОРЬБЕ с РЕАЛЬНО повторяющимся кодом.

Ну и если "забываете" - ЗАПИСЫВАЙТЕ,

И ещё - "в НАЧАЛЕ дня СТАВИМ себе ЦЕЛЬ, в КОНЦЕ дня - ОЦЕНИВАЕМ насколько мы эту цель выполнили".

Собственно всё.

P.S. если "задача сложная", то ТЩАТЕЛЬНО и РЕГУЛЯРНО коммитим и ТЩАТЕЛЬНО документируем КАЖДЫЙ коммит - Черновик. Вариации на тему TDD.

И ОЦЕНИВАЕМ тот факт - КАК МЫ ДВИЖЕМСЯ к цели. И ДВИЖЕМСЯ ЛИ.

P.P.S. Это всё "напоминает" Agile. Но! Лишь "напоминает".

Ибо "водопадную модель" - НИКТО НЕ ОТМЕНЯЛ.

Процитирую: "ТЗ — это большое БЛАГО для программиста. „Водопад“ — возможность творчески работать, не загоняя себя в угол."".

Но!

"Огонь и движение" (и Agile) - ЛОКАЛЬНО, и "водопадная модель" - ГЛОБАЛЬНО.

P.P.P.S. И ещё...

Пишите тесты.

Процитирую самого себя:

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

P.P.P.P.S. И ещё...
Если кнопка называлась "Выделить", а стала называться "actSelectAll" (в результате "рефакторинга"), и вы ПОКОММИТЕЛИ "это" и "это" ПРОДОЛЖАЕТСЯ несколько НЕДЕЛЬ, то вы ПЛОХО сделали своё дело.

суббота, 28 марта 2015 г.

Бумажки. Бумажки. Надо обязательно написать пост про бумажки

Бумажки. Бумажки. Надо обязательно написать пост про бумажки.

И чем они СИЛЬНО ЛУЧШЕ, чем всякая "электронная автоматизация".

Мысль банальна - "бумажку не жалко и выкинуть или ПЕРЕПИСАТЬ", а "электронный таск" - жалко. Ну типа "силы потрачены".

Как никак - артефакт планирования и проектирования....

Такие "простые бумажки".. Формата 8х8.

Взял ручку и написал.

И у тебя на столе - "пасьянс из бумажек".

Тасуй как хочешь.

Сделал - ВЫКИНУЛ в УРНУ.

Никаких "закрытий тасков".

Не сделал - "тасуешь дальше".

Забыл о чём речь - ВЫКИДЫВАЙ в урну БЕЗ СОЖАЛЕНИЯ.

Ибо "проблема того не стоит".

ВСПОМНИЛ - "заводишь НОВУЮ бумажку".

Всё банально...

Микро-анализ и микро-менеджмент.

БУМАЖКИ это круче чем CQ, QualityCentral или MSProject.

Они гибче информативнее.

Ссылка. Игры разума

https://ru.wikipedia.org/wiki/%D0%98%D0%B3%D1%80%D1%8B_%D1%80%D0%B0%D0%B7%D1%83%D0%BC%D0%B0

"«Игры разума» (англ. A Beautiful Mind  «Прекрасный ум» (разум)[2]) — биографическая драма Рона Ховарда по одноимённой книге С. Назар, рассказывающей о жизни Джона Форбса Нэша, лауреата Нобелевской премии по экономике[3]. Книга в 1998 году была номинирована на Пулитцеровскую премию. Сценарий к фильму был написан Акивой Голдсманом. Главную роль в картине исполнил Рассел Кроу; также снялись Дженнифер Коннелли, Эд Харрис,Кристофер Пламмер и Пол Беттани. Фильм получил четыре «Оскара» (лучший фильм, адаптированный сценарий, режиссура, актриса второго плана — Дженнифер Коннелли), награду «Золотой глобус» (в частности, приз получил Рассел Кроу за лучшую мужскую роль) и был отмечен несколькими премиямиBAFTA. Премьера фильма состоялась 21 декабря 2001 года в США[4]. Премьера в России состоялась 3 июля 2002 года. Фильм был положительно воспринят критиками и собрал более 300 млн долларов по всему миру.
История начинается с ранних лет молодого гения Джона Нэша. У него начинает развиваться параноидная шизофрения, сопровождающаяся галлюцинациями, и прогрессирует до тех пор, пока не ставит под удар его работу и отношения с женой и друзьями.
Фильм был подвергнут критике за неточное изображение на экране некоторых аспектов жизни Нэша. Фильм представил его галлюцинации как зрительными, так и слуховыми, тогда как в реальной жизни они были исключительно слуховыми[5]."

четверг, 26 марта 2015 г.

Коротко Implicit и Explicit и опять про Implicit. И про Equal

По мотивам - Коротко. Про контроль типов.

Так вот вам "идейка":

// TmsShapeClassName

type
 TmsShapeClassName = record
  rValue : String;
  class operator Implicit(const aValue: String): TmsShapeClassName;
  class operator Explicit(const aSelf: TmsShapeClassName): String;
 end;//TmsShapeClassName

...

class operator TmsShapeClassName.Implicit(const aValue: String): TmsShapeClassName;
begin
 Result.rValue := aValue;
end;

class operator TmsShapeClassName.Explicit(const aSelf: TmsShapeClassName): String;
begin
 Result := aSelf.rValue;
end;

Пока - всё.

Заготовочка - https://bitbucket.org/ingword/mindstream/commits/8d43980ff7c2bf1825c1e0dc60e7db36499e7c37

Так сказать - "следите за обновлениями".

P.S. Ну и ещё там есть:

 TmsColorRec = record
  rIsSet : Boolean;
  rValue : TAlphaColor;
  class operator Implicit(aValue: TAlphaColor): TmsColorRec;
 end;//TmsColorRec

 TmsPixelRec = record
  rIsSet : Boolean;
  rValue : Pixel;
  class operator Implicit(aValue: Pixel): TmsPixelRec;
 end;//TmsPixelRec

 TmsRadiusRec = record
  rIsSet : Boolean;
  rValue : Pixel;
  class operator Implicit(aValue: Pixel): TmsRadiusRec;
 end;//TmsRadiusRec

 TmsStrokeDash = record
  rIsSet : Boolean;
  rValue : TStrokeDash;
  class operator Implicit(aValue: TStrokeDash): TmsStrokeDash;
 end;//TmsStrokeDash

...

(+) https://bitbucket.org/ingword/mindstream/commits/4c28381d98f5a01d82b7e01b2e4456f81b05a72a

(+) https://bitbucket.org/ingword/mindstream/commits/1734dc8f4d07510e62190294de535347a7672493

И ещё:

type
 TmsShapeClassName = record
  rValue : String;
  class operator Implicit(const aValue: String): TmsShapeClassName;
  class operator Explicit(const aSelf: TmsShapeClassName): String; overload;
  class operator Implicit(const aSelf: TmsShapeClassName): String; overload;
  function EQ(const aValue: String): Boolean; overload;
  function EQ(const aValue: TmsShapeClassName): Boolean; overload;
 end;//TmsShapeClassName
...
// TmsShapeClassName

class operator TmsShapeClassName.Implicit(const aValue: String): TmsShapeClassName;
const
 cPref = 'Tms';
begin
 Result.rValue := aValue;
 if ANSIStartsText(cPref, Result.rValue) then
  Result.rValue := Copy(Result.rValue, Length(cPref) + 1, Length(Result.rValue) - Length(cPref));
end;

class operator TmsShapeClassName.Explicit(const aSelf: TmsShapeClassName): String;
begin
 Result := aSelf.rValue;
end;

class operator TmsShapeClassName.Implicit(const aSelf: TmsShapeClassName): String;
begin
 Result := aSelf.rValue;
end;

function TmsShapeClassName.EQ(const aValue: String): Boolean;
begin
 Result := (Self.rValue = aValue);
end;

function TmsShapeClassName.EQ(const aValue: TmsShapeClassName): Boolean;
begin
 Result := (Self.rValue = aValue.rValue);
end;

(+) https://bitbucket.org/ingword/mindstream/commits/7f34f5efa542db681a08d702d38cc32e6441ad6c

И ещё:

type
 TmsShapeClassName = record
  rValue : String;
  class operator Implicit(const aValue: String): TmsShapeClassName;
  class operator Explicit(const aSelf: TmsShapeClassName): String; overload;
  class operator Implicit(const aSelf: TmsShapeClassName): String; overload;
  class operator Equal(const A: TmsShapeClassName; const B: String): Boolean;
//  function EQ(const aValue: String): Boolean; overload;
  function EQ(const aValue: TmsShapeClassName): Boolean; overload;
 end;//TmsShapeClassName

...

// TmsShapeClassName

class operator TmsShapeClassName.Implicit(const aValue: String): TmsShapeClassName;
const
 cPref = 'Tms';
begin
 Result.rValue := aValue;
 if ANSIStartsText(cPref, Result.rValue) then
  Result.rValue := Copy(Result.rValue, Length(cPref) + 1, Length(Result.rValue) - Length(cPref));
end;

class operator TmsShapeClassName.Explicit(const aSelf: TmsShapeClassName): String;
begin
 Result := aSelf.rValue;
end;

class operator TmsShapeClassName.Implicit(const aSelf: TmsShapeClassName): String;
begin
 Result := aSelf.rValue;
end;

class operator TmsShapeClassName.Equal(const A: TmsShapeClassName; const B: String): Boolean;
begin
 Result := (A.rValue = B);
end;

(*function TmsShapeClassName.EQ(const aValue: String): Boolean;
begin
 Result := (Self.rValue = aValue);
end;*)

function TmsShapeClassName.EQ(const aValue: TmsShapeClassName): Boolean;
begin
 Result := (Self.rValue = aValue.rValue);
end;

И вот ещё куда стоит посмотреть:

  TPointF = record
    class function Create(const AX, AY: Single): TPointF; overload; static; inline;
    class function Create(const APoint: TPoint): TPointF; overload; static; inline;

    class operator Add(const APoint1, APoint2: TPointF): TPointF;
    class operator Subtract(const APoint1, APoint2: TPointF): TPointF;
    class operator Equal(const APoint1, APoint2: TPointF): Boolean;
    class operator NotEqual(const APoint1, APoint2: TPointF): Boolean;
    class operator Implicit(const APoint: TPoint): TPointF;
    class operator Negative(const APoint: TPointF): TPointF;
    class operator Multiply(const APoint1, APoint2: TPointF): TPointF;
    class operator Multiply(const APoint: TPointF; const AFactor: Single): TPointF;
    class operator Multiply(const AFactor: Single; const APoint: TPointF): TPointF;
    class operator Divide(const APoint: TPointF; const AFactor: Single): TPointF;

    class function PointInCircle(const Point, Center: TPointF; const Radius: Integer): Boolean; static; inline;

    function Distance(const APoint: TPointF): Single;
    // 3D cross-product with Z = 0
    function CrossProduct(const APoint: TPointF): Single;
    function DotProduct(const APoint: TPointF): Single; inline;

    procedure Offset(const APoint: TPointF); overload; inline;
    procedure Offset(const ADeltaX, ADeltaY: Single); overload; inline;
    procedure Offset(const APoint: TPoint); overload; inline;

    procedure SetLocation(const X, Y: Single); overload; deprecated 'Use ":=" assignment instead';
    procedure SetLocation(const P: TPointF); overload; deprecated 'Use ":=" assignment instead';
    procedure SetLocation(const P: TPoint); overload; deprecated 'Use ":=" assignment instead';
    function Subtract(const Point: TPointF): TPointF; overload; deprecated 'Use TPointF.Offset instead';
    function Subtract(const Point: TPoint): TPointF; overload; deprecated 'Use TPointF.Offset instead';
    function Add(const Point: TPointF): TPointF; overload; deprecated 'Use TPointF.Offset instead';
    function Add(const Point: TPoint): TPointF; overload; deprecated 'Use TPointF.Offset instead';
    function Scale(const AFactor: Single): TPointF; deprecated;
    function EqualsTo(const Point: TPointF; const Epsilon: Single = 0): Boolean;

    function IsZero: Boolean;
    function Ceiling: TPoint;
    function Truncate: TPoint;
    function Round: TPoint;

    function Normalize: TPointF;
    function Length: Single;
    function Rotate(const AAngle: Single): TPointF; 
    function Reflect(const APoint: TPointF): TPointF; inline;
    function MidPoint(const APoint: TPointF): TPointF; inline;
    function AngleCosine(const APoint: TPointF): Single;
    function Angle(const APoint: TPointF): Single;

    case Integer of
      0: (V: TPointFType;);
      1: (X: Single;
          Y: Single;);
  end;

Особенно вот сюда:

class operator TPointF.Equal(const APoint1, APoint2: TPointF): Boolean;
begin
  Result := SameValue(APoint1.X, APoint2.X) and SameValue(APoint1.Y, APoint2.Y);
end;

function TPointF.EqualsTo(const Point: TPointF; const Epsilon: Single): Boolean;
begin
  Result := SameValue(X, Point.X, Epsilon) and SameValue(Y, Point.Y, Epsilon);
end;

class operator TPointF.NotEqual(const APoint1, APoint2: TPointF): Boolean;
begin
  Result := not (APoint1 = APoint2);
end;

class operator TPointF.Implicit(const APoint: TPoint): TPointF;
begin
  Result.X := APoint.X;
  Result.Y := APoint.Y;
end;

Оператор сравнения с учётом Epsilon хорош. Не правда ли?

(+) https://bitbucket.org/ingword/mindstream/commits/2291e3309b5ee49de09d0e219298859dbb721a8b

Чужой пост. Тестировщик vs программист

Ссылки на исходный текст к сожалению у меня нет.

Тестировщик vs программист

Если перефразировать поговорку «плох тот солдат, который не хочет стать генералом», то выйдет «плох тот тестировщик, который не хочет стать программистом» или «плох тот программист, который не хочет стать стартапером». Сейчас это почти аксиома. Например, в среде неокрепших умов считается, что тестирование — это своего рода трамплин в IT, первая ступенька на пути к программированию. Мол, через N-лет в тестировании будет легче совершить переход в разработку. Тем более что автоматизация, к которой так стремятся мануальщики — это и есть зачаточная стадия программирования. Но годы идут, а в программирование переходят лишь немногие.
Похожая ситуация происходит и с программистами, которые по молодости бьют себя в грудь и обещают родить множество стартапов, стать CEO или на худой конец хотя бы проджект-менеджером. Но и здесь особого прогресса не видно — даже в тимлиды зовут неохотно. А в это же время рядовому QA-мануальщику выдают новые лампасы и стригут в product owner’ы. Но при этом запрещают ему ходить в бар для программистов. Что происходит?

Инертные люди

С одной стороны, дело может быть в традиционной инертности человека. Затратив пару лет на то, чтобы освоить свою профессию (тестирование/программирование), он уже не рвется в смежную специальность. Ему и здесь тепло. Хотя, с другой стороны, может, не так уж и хотел?
Тезис «котелок не потянул» рассматривать не приходится, потому как обе эти профессии являются инженерными, да и в работе тестировщика и программиста есть много точек соприкосновения. То же написание тестов, уточнение требований, знание Linux, SQL, умение писать bash-скрипты и так далее. Да и часто в требованиях к вакансии тестировщика указывают способность понимать ООП, читать код и даже уметь кодить. То есть, тестировщик, который соответствует всем этим параметрам, уже является без пяти минут джуном-программистом.
Причем когда какой-нибудь тестировщик с перечисленным набором умений объявляется на форуме с жалобой «не могу найти работу», тут же подтягиваются программисты, которые советуют кое-что подучить и смело идти в программирование:
— Из навыков у меня: базовые знания C#, Javascript, SQL, знаю HTML, CSS, в свое время написал 2 сайта (это в подтверждение знаний html и css).
— Хорошо, почему не подтянуть JS, не посмотреть AngularJS и не пойти во фронтэндщики? Туда, может быть, попасть даже проще, чем в QA, а работа не такая дурацкая, а всё-таки осмысленная, инженерская, в отличие от тестирования.
Но они не идут. Мало того, что по факту лишь немногие QA таки переходят в разработку (по разным причинам), так и дорога в product owner’ы для них оказывается короче, чем для программистов. Логика проста: тестировщик знает, как приложение не должно себя вести, тогда как PM знает, как должно. Немного магии, и — вуаля! — держите свежего начальника.
Но есть в работе программиста и тестировщика кардинальное различие. Один строит, другой ломает. Один оптимист, другой пессимист. Один любит, другой ненавидит.
Программист проектирует и изготавливает автомобиль, а тестировщик пытается его убить об стену на скорости 200 км в час. Разраб радуется, что машина продолжает, хоть и с повреждениями, но катиться по шоссе, а тестер в это время ликует, что у неё вот-вот отвалится глушитель. Программист говорит: «ерунда, заживет», тестировщик отвечает: «срочно в больницу». Дуалистика!

Оптимизм и пессимизм

Программист по природе своей — оптимист. Если он не будет оптимистично смотреть в будущее, его съест ежедневная горечь ошибок. Никогда ничего не бывает гладко, даже чертовы туториалы — и те компилятся не с первого раза. Программиста спасает вера в то, что все будет хорошо: «это не баг, это фича», когда QA уверен в обратном. Так они устроены — каждый в свое болото тянет. Но это взаимовыгодный союз. Они — как два друга, или как семейная пара, где один витает в облаках, а другой его всё время тянет на землю. Чтоб не улетели оба.
Но тестировщики тоже умеют радоваться. Правда, причины для радости у них своеобразны — как для программиста. У меня до сих пор стынет кровь в жилах, когда вспоминаю радостный вопль знакомого тестировщика: «Аааа! Нашел!». «Что ж ты радуешься, скотина?» — думаю я. Нашел проблему, дефект, чертов баг. А хочется лететь, двигаться дальше. Поэтому если в рабочей обстановке у одного на лице радость и улыбка, то у другого непременно будет pokerface. «Здесь не работает!», — улыбается тестировщик, — «И в логах, глянь — одни epic fatal total kernel panic error’ы. Всё красным», — не унимается его радость . «Сейчас посмотрим», отвечает ему с лопатным выражением лица разраб. Проходит полчаса — и они меняются ролями: программист с улыбкой объясняет, что это на самом деле не баг, а неправильная конфигурация environment’а, или что таки баг, но не критический, и погоды он не делает. Тестер чахнет прямо на глазах.
К чему я всё это говорю — у тестировщиков с программистами разные системы ценностей. И чем дольше каждый из них работает в своей профессии, тем сложнее ему потом сделать разворот на 180. Один живет годы с философией «баги — это плохо», тогда как другой всю жизнь считает: «баги — это хорошо».
Как в анекдоте: «Программист видит стакан наполовину полным, проджект-менеджер видит стакан наполовину пустым, тогда как тестировщик видит его наполовину треснувшим.»

Ценности

Но и это не всё. Программист смотрит в будущее — он моделирует, планирует, пытается предсказать на несколько шагов вперед. Планирует ли тестировщик? Конечно. Но в режиме «Карфаген должен быть разрушен». Как хладнокровный охотник он продумывает покушение на софтину — отсыпает пороху, чистит ружье, смотрит прогноз погоды, точит нож. Он постарается убить её во что бы то ни стало, любым доступным способом, хоть голыми руками. Вот почему программистам неспокойно, когда в «сезон охоты» родная софтина надолго уходит в саванну. «Достаточно ли я её подготовил? Сумеет ли она избежать смерти? Если она будет ранена, то не смертельно ли? Успею ли я оказать ей первую помощь?» — мелькают мысли в голове программиста, пока он прихлебывает кофе, искоса поглядывая на тестировщика, который, кажется, начинает входить в раж.
Критиковать всегда легче. Как бы не было сложно грамотно протестировать софтину, создать её или пофиксить скрытую багу все равно сложнее. Это как в искусстве: кинокритику, чтобы указать на недочеты сюжета и общее впечатление от картины, нужно потратить часы, максимум дни. Режиссеру и его команде, чтобы снять этот фильм — месяцы, а иногда и годы. В этом плюс и одновременно минус рыботы тестировщика: с одной стороны, он меньше стрессует, ему не звонят в воскресенье утром с вопросами «почему не работает». С другой стороны, именно поэтому он находится ниже на иерархической ступеньке, ведь главную работу делает программист. Отсюда возникает вопрос: какое занятие человек выберет — менее сытое, зато более спокойное, или же более выгодное, но при этом требующее больше нервов?

Перфекционизм

Стерильный мир нулей и единиц является отличной средой для деления бактерий перфекционизма, которые захватывают мозги IT-специалистов. У программиста острая фаза длится до поры до времени, пока не прижмут сроки и пока не придется изобретать костыли для своего детища — чего не сделаешь ради заказчика? Тогда как у тестировщика она приобретает хронический характер. Если программист — это перфекционист-второклассник, то тестировщик — перфекционист-третьекурсник. Пока разраб закрывает глаза на мелкие огрехи в надежде, что зритель не заметит неровностей и царапин, тестер только на них и смотрит. С линзой в руке. Поначалу все тихо-мирно. Но когда девелопер отвлекается на «смотри, самолет!», у тестировщика в руках оказываются здоровенные раскаленные клешни, бензопила, отбойный молоток и ванна с жидким бетоном. Сейчас он будет испытывать софтину на идеальность.
Поэтому вопрос в том, захочет ли тестировщик пересмотреть свои перфекционистские привычки, научится ли он смотреть сквозь пальцы на некоторые мелочи.

Любовь

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

Ненависть

Посмотрим правде в глаза: программисты не всегда ладят с тестировщиками. Оно и понятно — хотят вроде бы одного, но методы у них разные. Одни строят, другие ломают. Одни джинсы сшивают, другие пытаются их порвать конями. К этому добавляется еще и иерархическая и зарплатная составляющая, а также дискриминация по признаку тестировщика. Поэтому вопрос в том, захочет ли человек, взяв вместо лупы отвертку и поменяв звезду на свастику, переходить в стан врага.
То есть если повыносить за скобки типичные причины, по которым тестировщики и программисты неохотно меняются местами (нет знаний, опыта, вакансий и т.д.), то в игре останутся не менее интересные факторы: оптимизм/пессимизм, перфекционизм, система ценностей, и, конечно же, любовь и ненависть. Поэтому, если технарь на старте своего пути уверен, что пойдет «дальше» — например, в тестировщики, разрабы, руководители, в PM’ы и product owner’ы, но с течением лет этого не происходит, то далеко не факт, что дело в чьей-то ленивой заднице или неспособности обучаться. Нет (хотя, очень может быть, паскуда — прим. авт.). Просто сваи уже вбиты и бетон залит. Проще строить новый дом, чем достраивать этажи или взрывать фундамент и начинать с нуля. Поэтому на старте неплохо бы еще разок обмозговать, куда поедет бетономешалка, но при этом не спешить заливать первый попавшийся фундамент. Кто знает, может, там дальше за горизонтом есть более интересные и стоящие заливки формы.
Два мнения от реальных тестировщиков:

1. "Спасибо за шикарную статью! Мне очень понравилось! Жизненно, доходчиво и немножко с юмором"

2. "Прочитал. Нельзя вот так всех взять и поделить под одну гребенку.... И насчет ненависти - заблуждение.... Хотя исключения есть. Видимо они и описаны в статье..."

Ссылка. О разработке ПО и книге Крега Лармана “Applying UML and Patterns”

http://sergeyteplyakov.blogspot.ru/2015/03/applying-uml-and-patterns.html

"У стандартного процесса обучения есть интересная особенность. Как только мы решили узнать что-то новое, мы садимся за учебники, идем на курсы и получаем новые знания всеми доступными способами. Через время мы говорим себе «Фффатит!», забиваем на обучение и переходим к практике (на ранних этапах теория переплетается простыми практическими задачами, но они не оказывают существенного значения). После чего, мы начинаем применять наши новые знания на практике, и через время они практически полностью выветриваются из нашей славной головешки и их место занимает опыт.

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

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

"Самая большая опасность, которая может поджидать опытного специалиста – это уверенность в своих знаниях, которые вполне могут оказаться однобокими или протухшими. За 5-10-15 лет практики мы легко можем забыть причины, почему мы делаем так или иначе. Наш опыт очень часто достаточно однобок, что приводит к серьезным последствиям при разработке, например, новых систем. Мы привыкли работать с легаси кодом, ругать всех и вся, а как только появляется возможность сделать все с нуля, мы садимся в лужу, и начинаем повторять тот самый го#%о-код, который мы же сами ругали на предыдущих проектах. Почему? Да потому что тот самый го#%о-код является наиболее актуальным опыт, а как надо иначе мы просто не знаем (может и знали, да забыли).

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

четверг, 19 марта 2015 г.

Цитата. Мне очень понравилась

"я написание
тестов
вернее первого теста
сегодня воспринимаю
как "потерю девственности""

Как я дружил Delphi XE7 с устройствами Samsung

"Ругательная роль" была тут - http://programmingmindstream.blogspot.ru/2015/03/delphi-android.html

Теперь по делу.

Мы делали проект - MindStream. Оглавление.

Под FMX.

И продолжаем делать.

НО тестировали и запускали под Windows только.

Ибо "поверили на слово" Embarcadero, что "единая база кода" и "код написанный единожды - работает на всех устройствах".

Свято верили мы в эту "мечту".

И тут наконец Samsung прислал нам планшеты для тестирования - Offtopic. Samsung прислал планшеты для тестирования.

И я вчера решил "запустить наше хозяйство" на присланных устройствах.

Потратил я на это дело часов восемь. А может и побольше.

Итак.

По шагам.

ПЕРВОЕ.

Ставим драйвера устройства.

Проверяем, что устройство НЕ ПОДКЛЮЧЕНО к компьютеру.

Драйвера берём тут:
http://androidxda.com/download-samsung-usb-drivers

Ну или прямо тут:
https://bitbucket.org/ingword/mindstream/src/125e663326c754319dbfe8532b2f362c5d365691/TestApp/Drivers/?at=B-Samsung-Try

Почему привожу эти ссылки? Потому, что поиск в Google и на сайте Samsung - у меня лично результатов приемлимых не дал.

Может быть руки кривые.

ВТОРОЕ.

Возможно придётся поставить Kies, Посмотрите на сайте Samsung - что это такое.

Прямая ссылка:
https://bitbucket.org/ingword/mindstream/src/125e663326c754319dbfe8532b2f362c5d365691/TestApp/Drivers/Kies3Setup.exe?at=B-Samsung-Try

Почему возможно?

Ну потому, что я СНАЧАЛА поставил Kies, но устройств НЕ УВИДЕЛ. А потом только поставил драйвера.

Возможно хватит одного из этих пунктов.

ТРЕТЬЕ.

Возможно потребуется ПЕРЕЗАГРУЗКА компьютера.

ЧЕТВЕРТОЕ.

Запускаем Delphi и СОЗДАЁМ или открываем проект FireUI.

ПЯТОЕ.

Смотрим на Project Manager.


Нажимаем правую кнопку мыши и выбираем Refresh.

Должна появится такая картина:

Если устройства не появятся, то а "залипнет" иконка со стрелками, то надо пару раз перезапустить Delphi. Каждый раз нажимая Resresh.

В конечном итоге устройство появится и Delphi это "где-то запомнит". И после этого всё будет хорошо.

ШЕСТОЕ.

Выбираем Target Android,

Нажимаем Build.

Если появляются Internal Error как в моём ругательном посте (http://programmingmindstream.blogspot.ru/2015/03/delphi-android.html) то делим проект пополам и пытаемся собрать.

Пока ошибка не исчезнет.

Когда проект соберётся, то в окне Messages будет написано Success.

Примечание. Сборка может идти минут 20-ть и оболочка может сожрать до 1.5 ГБ памяти.

СЕДЬМОЕ.

Нажимаем Run.

Тут пишется Delploying.

И тут меня подстерегала ошибка:
[PAClient Error] Error: E2820 Could not find program, 'C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\adt-bundle-windows-x86-20131030\sdk\tools\ZipAlign.exe'

Не хватало какой-то утилиты из SDK - ZipAlign.exe

Не знаю почему.

Я её нашёл в предыдущей инсталляции Delphi XE6 и скопировал в указанное место.

Для вас я положил эту утилиту в репозитарий: https://bitbucket.org/ingword/mindstream/commits/fafb709a95b1352b82709e464659e4da9d5a9ac5?at=B-Samsung-Try
https://bitbucket.org/ingword/mindstream/src/fafb709a95b1352b82709e464659e4da9d5a9ac5/TestApp/Tools/zipalign.exe?at=B-Samsung-Try

ВОСЬМОЕ.

Опять жмём Run и дожидаемся окончания конца Deploying.

И тут опять может не запуститься. На устройстве возникает диалог про finger print или "отпечаток пальца".

Который НАДО принять.

Я это не сразу сделал. Но потом - увидел и сделал.

ДА!

И ещё - на устройстве надо включить режим Debug via UBS или USB Debug,

Для этого открывает Options и About Device.

Ищем поле Build (Number) и СЕМЬ раз кликаем в него.

После этого появится группа "параметры разработчика" - Developer Options.

ТАМ ставим галку- USB Debug.

Вот собственно и всё.

Приятной ОТЛАДКИ.

Мне лично - ровно такого текста - не хватало. Надеюсь он будет вам полезен.

Прямо скажем... Delphi для Android содержит "некоторые проблемы"...

Прямо скажем... Delphi для Android содержит "некоторые проблемы"... Да-с...

На нашем проекте сжирает при компиляции 1.5 Гб памяти и падает с Internal Error.

[DCC Fatal Error] msShape.pas(387): F2084 Internal Error: GPFE06D7363-761F2F71-0

GPF - это ВИДИМО - General Protection Fault.

12 тыс строк кода - 1.5 Гб ПАМЯТИ. Ну куда это годится?

Похоже что разработчики не всё качественно тестировали.

Не говоря уж о том, что компиляция идёт раз в 10-20 медленнее, чем под Windows.

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

Но я всё равно это сделаю. Как только выделю минимальный проект.

У меня ведь цель не в том, чтобы "обругать и тем самовыразиться", а в том, чтобы у меня это заработало.

Ну а под Win-64 проект - собирается. И даже запускается из командной строки. А из под отладчика - Unable to create process.

Да-с...

"Hello world" - да - собирается... И работает. Респект разработчикам.

В общем про "единую кодовую базу" - пока есть сомнения.

Несмотря на то, что проект С НУЛЯ писался под СТАНДАРТНЫЕ КОНСТРУКЦИИ.

Исходники тут - https://bitbucket.org/ingword/mindstream/src/0745fccded2b070c03850e74c9d4644a680f1da1/?at=B-Samsung-Try

Не могу отделаться от стойкого ощущения, что я "поддался обаянию последователей моей любимой компании".

Отрезал нафиг JSON - всё собралось. Никогда я не любил слово JSON. Сколько с ним ни сталкивался - одни сплошные недоразумения.

Но "с толкача" я в итоге приложение - "завёл".

Вот фотка:

Ну и с линиями понятное дело - проблемы. Ну и с моторикой кликов.

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

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

Ну и я надеюсь, что Delphi XE8 принесёт нам радость, а не разочарование.

пятница, 13 марта 2015 г.

Ссылка. Описание продукта над которым мы трудимся

https://bitbucket.org/ingword/mindstream/overview

Цели:

1. Написать рисовалку UML (на самом деле там присутствует ревизионизм). Для десктопа и планшетов.
2. Сделать обобщённое описание мета-моделей.
3. Сделать кодогенерацию из диаграмм. На основе мета-моделей.
4. Написать методичку для школьников. Как программировать "не программируя".
5. Внедрить технологию "микросхем":
 a. Про "микросхемы" и UML.
 б. Ещё немного про UML.
 в. Ссылка. Pascal Script.
6. Написать "книгу" о том "как мы писали редактор UML с помощью UML и шаблонов проектирования". На уровне GoF или хотя бы Джоэла.
7. Внедрить технологию связей: требования <-> прецеденты <-> код <-> тесты.
8. Обобщить эту технологию на применения кажущиеся "далёкими от программирования".
9. Привлечь внимание к технологии кого-нибудь из "китов" IT-отрасли. Хотя бы Embarcadero.
10. Перестать "писать по ночам".

Если вдруг кто-то захочет присоединиться к проекту - всегда рады.

Готовы рассмотреть разные варианты сотрудничества:

1. На "общественных началах", потому что "интересно".
2. На "общественных началах", потому что "хочется сделать что-то нужное и полезное".
3. На "общественных началах", потому что "надо сделать хороший курсовой проект или диплом". Поверьте - у нас есть масса полезного материала для "студенческих работ". Но не для "халявщиков".
4. На "общественных началах" с последующим обещанием "доли в успехе" (если таковой случится).
5. Сдельная работа за оговоренную оплату по различным "смежным задачам". По схеме "сначала работа - потом вознаграждение". Под честное слово. У нас есть некий "запас средств". Если вы сделаете что-то реально стоящее - мы вас "не кинем".
6. Работа на "окладе". Небольшом по "меркам рынка". Но тут будем отдельно "договариваться". И "вы" и "мы" - должны будем показать "состоятельность в профессии" и "лояльность друг к другу".
7. Работа на "окладе". Достойном по "меркам рынка". Такой возможностью мы пока не располагаем. Но кто знает.

Мы понимаем, что время OpenSource и/или CrowdSource - "прошло", но вдруг...

Нам надо как писать код, так и выполнять всякую сопутствующую работу как то - "переводы" и оформление текстов и документации.

Более полная информация о продукте - MindStream. Оглавление.

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

Только "писание кода" и "сопутствующих документов".

Никаких "разговоров ради разговоров". Никаких "высоких технологий ради высоких технологий".

"Огонь и движение".

И ещё стоит почитать - Коротко. Ни о чём. Инверсия зависимостей.

Коротко. Ни о чём. Хороший по-моему коммит

Хороший по-моему коммит:

https://bitbucket.org/ingword/mindstream/commits/332b51866e6964684322a12688ad708e936bca24

Показывающий как от "классов" и "мета-классов" можно перейти к "мета-мета-классам".

Ещё на ту же тему - Пример использования шаблонов генерации.

Цитата оттуда:

"> А если бы диаграмма мета-мета-модели была бы построена для описания чего-то конкретного,

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

Offtopic. Не могу не поделиться. О долге и совести

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

"Рига, 1991 год.
Рижский ОМОН — в любом милицейском спецназе знают его многострадальную историю. Историю про то, как небольшая кучка милиционеров из отряда особого назначения не подчинилась требованиям «новой латвийской независимости», и с оружием в руках решила бороться до конца «за СССР». В январе 1991 года вся милиция Латвии приняла присягу новой власти и превратилась в национальную полицию. Все, кроме Рижского ОМОНа. Омоновцы Риги решили бороться за Советскую власть.
По указанию министра МВД СССР Пуго бойцы Рижского ОМОНа захватили рижский Дом печати, телеграф, здание латвийского МВД, разоружили арсенал филиала школы милиции. На многочисленные сигналы в МВД СССР с просьбой о помощи, ответа не поступало. СССР уже разваливался, расползался по швам, политики делили власть, а в Риге кучка людей в черных беретах пытались вернуть страну, которую уже поделили и растащили правительственные пройдохи. Они держались до последнего. Их объявили вне закона. Они держались до последнего.
В августе 1991, когда ГКЧП взяло власть в Москве, Рижский ОМОН получил надежду, что не все потеряно. После провала путча руководство отряда сожгло все секретные документы и отряд решил пробиваться на территорию России.
Начались переговоры, омоновцы окопались на своей базе. Им предлагали сдать оружие и бронетехнику под гарантии пропуска в Россию по одному. Они отказались. Только полным составом, вместе с семьями, с бронетехникой, оружием и амуницией. Латвийское правительство предложило отряду добираться колонной до Пскова, по пути стягивая войска и полицию для удара по мятежникам. Они отказались. Только на военно–транспортных самолетах, полным составом, с бронетехникой, оружием и семьями. Бойцам предлагали сдать руководство отряда, а остальным расходиться по домам. Они отказались.
И Латвия пошла на уступки. Вскоре 14 военно–транспортных самолетов, груженых техникой и людьми взмыли в небо. У Латвии не было своих сил ПВО. Россия также не горела особым желанием принять у себя вооруженный милицейский отряд. После долгих раздумий МВД РФ решило отправить Рижский ОМОН на дислокацию в Тюмень, подальше от больших городов.
«Мы вернемся!» – было написано на броне БТРов Рижского ОМОНа. Они не смогли вернуться обратно в свою страну. В зеркало прошлого не шагнешь. Страна развалилась."

Ссылка. Офигенная штука

Офигенная штука. Если верить заявленной функциональности.

"I've created a multi-platform leak checking library with DUnit integration and per test memory leak details (basically FastMM full debug report but per test) and instance cycle detection (analyzes managed fields of your object graph and tells you where your instances create cycles)."

https://bitbucket.org/shadow_cs/delphi-leakcheck/

https://plus.google.com/_/notifications/emlink?emr=13264506605716084617&emid=CJjU7JPVn8QCFQ3EHgodYVsAsg&path=%2F108858205253578173448%2Fposts%2F1wocM3D2HXJ&dt=1426055080015&ub=SQUARE_SUBSCRIPTION

Offtopic. И ещё цитата

"Вокруг преподавания русского языка очень много спекуляций.
О том как истинный философ я сужу, немного преподававший русский в школе и всю жизнь как газетчик проработавший со словом.
Во-первых, сами учителя пишут зачастую плохо (как же учат других?!) - приходилось немало иметь дела с их текстами, когда работал в "Учительской газете" и в провинции.
Во-вторых, начальники, а теперь нувориши - часто и неграмотны, и в письме косноязычны.
Секретарь парткома крупного завода писал "доч" - без ь "дочь". Потом он стал долларовым миллионером.
В-третьих, и писатели часто неграмотны и пишут плохо. Был студентом на практике, когда заметку в газету принёс знаменитый детский писатель Сергей Голицын - я пришёл в ужас: "Это нельзя печатать!"
- Перепиши, - спокойно заметила завотдела.
- Переписать известного писателя?!
- Ну и что. Всегда так делаем.
Переписал.
Оказывается, литературные редакторы часто являются безвестными сотворцами известных произведений.
"Детство" Л. Толстого полностью переписано Некрасовым, из-за чего у них был большой скандал.
Вроде бы, "Студенты" Ю. Трифонова тоже едва ли не полностью переписаны литредактором. Но Сталинскую премию получил Трифонов.
В 5-м классе, где я преподавал, учился сын чемпиона мира по шахматам Б. Спасского - Вася Спасский. Он никогда не учил никаких правил, но диктанты писал только на "5". Сейчас он известный писатель по теме рок-музыки. Смайлик «wink»
В общем, значение русского языка в нашей жизни сильно преувеличено.
Деланье денег, например, гораздо более важное искусство-умение."

На мой взгляд к программированию это тоже относится. Хотя - русский язык - важнее.

Как и любой ДРУГОЙ естественный язык. Если есть понимание законов и принципов естественного языка. А также уважение к его нормам и правилам, то и программирование становится не проблемой. Мне так кажется.

Ссылка. КОНКУРС ПРИЛОЖЕНИЙ НА DELPHI

http://www.delphimobile.ru/

http://www.delphimobile.ru/terms.pdf

"Создай свое мобильное или настольное приложение на RAD Studio XE7 (Delphi XE7, C++ Builder XE7) и выиграй приз!"

Offtopic. Грубо, но по делу

[17:26]  СЕ> У Шнурова из Ленинграда из тивтера:
"Сергей Шнуров @YaTebyaEbal · 13 мин 13 минут назад
По ТВ нам говорят, что теперь всё будет иначе. Будут, мол, другие картинки показывать. А в парадном как было нассано, так и есть нассано."
Прям твои слова
[17:26]  ЛА>
[17:26]  СЕ> https://twitter.com/yatebyaebal

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

вторник, 10 марта 2015 г.

Ссылка. Память программиста: как запомнить паттерны и Камасутру

http://dou.ua/lenta/articles/mnemonics/

Цитата автора:

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