Ля-ля vs Бэ-мэ: итоги года

0 коммент. | добавить комментарий

Ярчайшим событием уходящего года стал уход из Ля-ля одесского сайт-менеджера и директоров ИСГ и основание ими собственной компании Бэ-мэ. Было все:

  • и обещания о переводе меня и моих ребят в Бэ-мэ
  • и уговоры Ля-ля остаться
  • и вызов меня в московский офис Ля-ля
  • и бесконечные приезды большого начальства со сборами всех сотрудников на кухне и заверениями что «все будет хорошо»
  • и неконтролируемые попытки Ля-ля поднять всем зарплаты с целью закрепить людей на рабочих местах
  • и уверения руководства Бэ-мэ в «светлом будущем»
  • и «командировка» в Ля-ля сотрудников половині команды, уже оформленных в Бэ-мэ
  • и заказчик, который сначала подтвердил наш переход в Бэ-мэ, а потом закрепил в Ля-ля
  • и длинная переписка с нашим ПМ-ом с немецкой стороны
  • и разъединение команды

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

Сначала я очень хотел перейти в Бэ-мэ. Сейчас мне все равно. Я устал. Устал от непрекращающейся агитации и постоянных выпадов с обеих сторон. Устал от организационных проблем, создающих ощутимые неудобства в работе, от самоустраняющихся немцев, от полных надежды лиц новых сотрудников, от звонящих HR-ов других компаний, пронюхавших, что не все ладно в Датском королевстве... Мне неудобно ходить в Ля-ля: я чувствую, что знаю больше остальных. Мне неудобно ходить в Бэ-мэ по той же причине. Я не знаю точно, где правда, но знаю, что период полураспада продолжается и многое еще впереди.

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

Мы все молодцы.

Lonewolf's Weblog Goes Blogger.com

0 коммент. | добавить комментарий

Вот он, конец 2007-го! Еще немножко – и начнется новый, 2008-й. В связи с этим, а также с тем, что мне до одури надоела эта мышиная возня с моим Web Wiz Journal, мой блог переходит на Blogger.com.

Причины:

  1. Авто-комменты от роботов. Web Wiz никак не умеет бороться с ними, в результате чего многие записи имеют уже по 150 спам-комментов.
  2. Проблемный хостинг. Моя запись на Brinkster.com имеет ограничение по трафику, из-за чего сайт в последнее время ложится где-то около девяти вечера, и лежит до утра следующего дня.
  3. Неудобно добавлять сообщения с картинками – сначала зайди на хостинг, залей картинку, потом зайди в админку блога, добавь запись… Неудобно, короче!
  4. Все-таки гугловый сервис – круто, светлое будущее и все такое.
  5. Сюда можно писать прямо из Word 2007 J

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

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

Придется, правда, обновить фиды:


  • http://sergey-borodavkin.blogspot.com/rss.xml (для RSS 2.0)
  • http://sergey-borodavkin.blogspot.com/atom.xml (для Atom 1)


Форца Гугл J

Java Multi-Level Undo Technique (Reflection API)

0 коммент. | добавить комментарий
1. Overview

The best examples of the end-user software leave absolutely no doubt that undo capability is not an option ever more. Currently every application that can alter existing data has to support undo and redo operations, which allow to cancel the changes made by user and to repeat them again as needed. As user knows that he can eliminate carelessly changes at any time, his work becomes more comfortable and the software is considered reliable and predictable.

For some reasons, still many applications support only limited undo/redo capabilities, allowing canceling and repeating only single operation. There is no need to prove that multi-level undo is much better. In this article I'm going to show that implementing multi-level undo in Java is easy, requires minimal amount of changes in your existing code and can be separated to reuse the approach in future. The top of the iceberg is already well-known to the developers who have had an experience with programming for Mac OS X using Cocoa framework which has the NSUndoManager class utilizing a similar technique.

The article is divided into sections describing the approach. In the next section, “Introduction to Java Reflection API”, a very brief description of things is given. If you are already familiar with reflection, you can skip this and move on to the next section, “Implementing basic undo/redo handling”. The last one, “Tuning the undo engine”, is devoted to improving the solution. After it, the conclusions and some tips on how to continue are given.

2. Introduction to Java Reflection API

The reflection library gives you a rich instrumentation to work with your Java code dynamically. For example, if a new class is added to the application during development, it is possible to organize a set of requests to get know the features of that class. Saying more generally, reflection is a way that a program can use to know about itself. Among the possibilities opened with it, are:

  • analyzing the features of the classes during the runtime
  • checking the object state during the runtime by getting the information about its fields and the values contained there
  • using the Method instances that work similar to the pointers to functions in languages like C++, etc.
Consider, for example, a class with rather strange name: Class (java.lang.Class, to be more precise). The instance of the class Class is an object describing the particular properties of a particular class. Here is an example:

public abstract class Shape { . . . }

public class Circle extends Shape { . . . }

public class Square extends Shape { . . . }

. . .

Shape s;

. . .

Class c = s.getClass();

System.out.println(c.getName() + " " + s.toString());

The last operator can print the line “Circle radius=10”, if s is a Circle instance, or “Square side=5”, if s is a Square instance.

Now you can do whatever you want. Imagine that you don’t know the exact class of s, but it is necessary to create another instance of the same class. The following call is the solution:

Shape s1 = s.getClass().newInstance();

Here the default constructor is used to initialize s1. If there is no default constructor for the class, an exception is thrown.

You can extend your knowledge about reflection by checking out the classes Field, Method and Constructor in the java.lang.reflect package. Summing up, the key feature of reflection is the ability to instantiate and work with some entities that are the parts of the application, be it a class, its constructor, a field or its modifier, etc. Actually, the possibility to refer to a class method as to an instance of the Method class is the core of the proposed undo technique. Now we are ready to begin implementing undo mechanism.

3. Implementing basic undo/redo handling

Primarily, undo support is heavily based on using the LIFO queue (stack), as the last performed operation has to be undone first. So, it is obvious that the class being developed, let’s call it UndoManager, will have undoStack as its member. Let’s start from the following code:

public class Pair {
public Object first;
public Object second;

public Pair(Object f, Object s) {
first = f;
second = s;
}
}

public class UndoManager {
private Stack undoStack = null;
private Object target = null;

public UndoManager(Object forWhom) {
undoStack = new Stack();
target = forWhom;
}

public void addInvocation(Method method, Object[] args) {
Pair p = new Pair(method, args);
undoStack.push(p);
}

public boolean canUndo() {
return (undoStack.size() > 0);
}

public void undo() {
if (!canUndo()) {
return;
}
Object obj = undoStack.pop();
if (obj instanceof Pair) {
Pair p = (Pair)obj;
invokeCommand(p);
}
}

protected void invokeCommand(Pair p) {
Method method = (Method)p.first;
Object[] args = (Object[])p.second;
try {
method.invoke(target, args);
return;
} catch (Exception ex) {
System.err.println("Cannot undo " + method.getName());
ex.printStackTrace();
return;
}
}
}

Here class Pair is a helper which simply allows storing two objects together. The undo is actually performed by an UndoManager instance. As it is shown, it is necessary to pass the target object to its constructor. Target object is the instance responsible for making the actions and organizing the undo workflow.

To add a method invocation to UndoManager, it is necessary to call method addInvocation(Method method, Object[] args), where method is target object’s method that will be called during undo; args is an array of arguments that will be passed to method. addInvocation simply stores the given method and its arguments into a Pair instance in the undo stack.

When the method undo() is called, the following happens. The last Pair is popped from the undo stack, and the target object’s appropriate method with its arguments is executed. Of course, an exception is thrown when something goes wrong.

Actually, this is all for undo. However, additional efforts are needed to support redo. As you can see, after the method is undone, it simply disappears and thus cannot be redone:

public void undo() {
. . .
Object obj = undoStack.pop();
. . .
}

To redo this method later, it is needed to store it somewhere. The right place to do so is another stack called redoStack. For example, after the sequence of methods A B C has been executed, the undoStack contains the C B A sequence (C will be executed first during undo). If we put each method being undone to the redoStack, then it will contain the sequence A B C again. Undo stack has reverse order, redo stack has direct order – this is what we need.

The changes to UndoManager class are the following:

. . .
private Stack redoStack = null;
. . .
public UndoManager(Object forWhom) {
. . .
redoStack = new Stack();
. . .
}
. . .
public boolean canRedo() {
return (redoStack.size() > 0);
}
. . .
public void redo() {
if (!canRedo()) {
return;
}
Object obj = redoStack.pop();
if (obj instanceof Pair) {
Pair p = (Pair)obj;
invokeCommand(p);
}
}

Attentive reader will notice that there is no way to fill redoStack. Seems it remains empty all the time. So, it is time to talk about the organization of the target object. Does it have to meet some special requirements? Let’s start with example:

public class MyClass {

private String value;

public MyClass() {
value = "";
}

public String getValue() {
return value;
}

public void setValue(String s) {
value = s;
}
}

Let’s imagine that we need to support undo/redo for the method setValue(String s). Of course, first we need to provide MyClass with its own UndoManager instance. Second, the setValue() method has to be changed to the following:

public void setValue(String s) {
try {
// Get the method as an instance
Method m = this.getClass().getDeclaredMethod(
"setValue",
new Class[]{String.class}
);
// Get the current value
Object[] args = new Object[]{getValue()};
// Add it to the undo manager
undoManager.addInvocation(m, args);
} catch (Exception e) {
// . . .
}

// Modify value
value = s;
}

In the added try-catch block we first get the reference to the method, then save the current value and add this data to the undo manager. Afterwards it is safe to modify the value: when we call undoManager.undo(), the method setValue() will be invoked with the previous value as an argument, so that it will be restored.

That’s nice, isn’t it? Let’s look at the sample sequence of events:

  1. We call setValue("A"). The invocation setValue("") is added to the undo manager.
  2. The new value is set.
  3. We call undo(), during which the undo manager makes the setValue("") invocation that restores the old (empty) value and… adds invocation setValue("A") to the undo manager!

So, there are actually two sources for the undoManager.addInvocation() execution: the method setValue() (or, saying more generally, the undo invocation method, call A) and, the undoManager.undo() method, call B. If call A is the place where a method invocation should be added to the undo stack, then call B is the place to add invocation to the redo stack. This approach can be implemented by providing the boolean variable isUndoing to the UndoManager class. It should be set in the undo() method like:

public void undo() {
isUndoing = true;
. . .
isUndoing = false;
}

As we have found out, there will be an addInvocation() call, caused by the organization of the method being undone, inside the undo() method. Now it becomes clear how the UndoManager’s addInvocation() method should look:

public void addInvocation(Method method, Object[] args) {
Pair p = new Pair(method, args);
if (isUndoing) {
redoStack.push(p);
} else {
undoStack.push(p);
}
}

Now we have both undo and redo. Also we know how to organize the undo invocation methods in the target class. The last section of the article is devoted to improving the approach.

4. Tuning the undo engine

There are still two things to be done. First: sometimes it is needed to clear the redo stack. For example, we have executed operations A, B, C and D. Afterwards we have undone D and C. Now the undo stack contains B and A, and the redo stack contains C and D. If now we execute some different operation E, then the true history of operations will be A, B, E. However, C and D are still stored in the redo stack – in this case it should be cleared. The rule is the following: redo stack should be cleared each time when a method invocation is added to the undo manager, if it is not in undoing or redoing state. Such a check must be done in the addInvocation() method.

The second thing: it is often needed to group undo/redo operations to execute multiple of them in a single undo or redo step. For example, if you type the word “peace” in your favorite text editor, then you probably expect that the whole word will disappear when you press the undo button on its toolbar, not only the last letter of it. To do so, we may add yet another stack to the UndoManager class (let’s call it groupStack) that will collect undo operations to group. Also it is needed to add the boolean variable, isUndoGroupOpened, and to create the following methods:

public void beginUndoGroup() {
if (isUndoGroupOpened == true) {
throw new IllegalStateException("beginUndoGroup() call while undo group is already opened");
}
isUndoGroupOpened = true;
}

public void endUndoGroup() {

if (isUndoGroupOpened == false) {

throw new IllegalStateException("endUndoGroup() call without matching beginUndoGroup()");
}
ArrayList actions = new ArrayList(groupStack);
if (isUndoing) {
redoStack.push(actions);
} else {
undoStack.push(actions);
}
isUndoGroupOpened = false;
groupStack.clear();
}

The undo group, when closed, will be stored in the corresponding stack as an ArrayList. Now, inside the undo()/redo() methods, it is possible to track this situation and perform all operations in the ArrayList at a time.

The complete source code of the resulting UndoManager class is the following:

import java.lang.reflect.Method;
import java.util.*;

public class UndoManager {
private Stack undoStack = null;
private Stack redoStack = null;
private Object target = null;
private boolean isUndoGroupOpened;
private Stack groupStack = null;
private boolean isUndoing;
private boolean isRedoing;

public UndoManager(Object forWhom) {
undoStack = new Stack();
redoStack = new Stack();
groupStack = new Stack();
target = forWhom;
isUndoGroupOpened = false;
isUndoing = false;
isRedoing = false;
}

public void addInvocation(Method method, Object[] args) {
if (!isUndoing && !isRedoing) {
redoStack.clear();
}

Pair p = new Pair(method, args);
if (isUndoGroupOpened) {
groupStack.push(p);
} else {
if (isUndoing) {
redoStack.push(p);
} else {
undoStack.push(p);
}
}
}

public void beginUndoGroup() {
if (isUndoGroupOpened == true) {
throw new IllegalStateException("beginUndoGroup() while " +
"undo group is already opened");
}
isUndoGroupOpened = true;
}

public void endUndoGroup() {
if (isUndoGroupOpened == false) {
throw new IllegalStateException("endUndoGroup() without " +
"matching beginUndoGroup()");
}

ArrayList actions = new ArrayList(groupStack);
if (isUndoing) {
redoStack.push(actions);
} else {
undoStack.push(actions);
}
isUndoGroupOpened = false;
groupStack.clear();
}

public boolean canUndo() {
return (undoStack.size() > 0);
}

public boolean canRedo() {
return (redoStack.size() > 0);
}

public void undo() {
if (!canUndo()) {
return;
}

if (isUndoing || isRedoing) {
throw new IllegalStateException();
}
isUndoing = true;
Object obj = undoStack.pop();
if (obj instanceof Pair) {
// Plain undo
Pair p = (Pair)obj;
invokeCommand(p);
} else if (obj instanceof ArrayList) {
// Undo group
beginUndoGroup();
ArrayList actions = (ArrayList)obj;
for (int i = actions.size() - 1; i >= 0; i--) {
Pair p = (Pair)actions.get(i);
invokeCommand(p);
}
endUndoGroup();
}
isUndoing = false;
}

protected void invokeCommand(Pair p) {
Method method = (Method)p.first;
Object[] args = (Object[])p.second;
try {
method.invoke(target, args);
return;
} catch (Exception ex) {
System.err.println("Cannot undo method " + method.getName());
ex.printStackTrace();
return;
}
}

public void redo() {
if (!canRedo()) {
return;
}
if (isUndoing || isRedoing) {
throw new IllegalStateException();
}
isRedoing = true;
Object obj = redoStack.pop();
if (obj instanceof Pair) {
// Plain redo
Pair p = (Pair)obj;
invokeCommand(p);
} else if (obj instanceof ArrayList) {
// Redo group
beginUndoGroup();
ArrayList actions = (ArrayList)obj;
for (int i = actions.size() - 1; i >= 0; i--) {
Pair p = (Pair)actions.get(i);
invokeCommand(p);
}
endUndoGroup();
}
isRedoing = false;
}
}


4. Conclusions

The described approach helps to implement undo/redo functionality in your Java application fast and easy. This solution is different from the traditional way, where the design pattern Command is often used. Using reflection for undo is better as it doesn’t require the objects to implement some special interfaces. The only requirement for the undo method is to store its invocation with the previous arguments in the undo manager.

The further improvement of the proposed technique may be an effort to make it run safely in a multithreaded environment. Also, it is still possible to simplify the changes needed for undo methods and to improve the error handling. However, such a technique remains simple, can be provided without big changes to the existing code, and thus helps to get the desired results faster.

Виза

0 коммент. | добавить комментарий
На прошлой неделе ездил получать визу в немецкое посольство. Теперь мне не отдают обратно загранпаспорт без разрешения на то Германского ведомства по делам иностранцев.

То, что они стребовали с меня резюме, диплом (как доказательства того, что я имею отношение к разработке ПО), мед. страховки - это понятно. Веселое случилось в пятницу. Они захотели, на минуточку, скан моего загранпаспорта! Люди, у которых находится мой загранпаспорт, потребовали его скан! Ну руки опускаются, а! Где я его им найду?!

Вот сижу и думаю: мой дед получил Героя Советского Союза за разведку боем при форсировании Днепра. Много он их тогда перекосил. После войны всю Европу объездил на мотоцикле. А я теперь должен получать разрешение на то, чтобы въехать в их замечательную страну...

Разработка как она есть

0 коммент. | добавить комментарий
Картина называется "Программный комплекс. Позади - 15 лет разработки и сотни разработчиков. Фрагмент."

http://www.artlebedev.ru/kovodstvo/idioteka/2007/06/05/

...только из его шкуры тулуп вышел...

0 коммент. | добавить комментарий
Пересматриваю "Ух ты, говорящая рыба" (ака "Добрый Э-эх") - впервые за много лет.

Не перестаю восхищаться этим диалогом:

- Кто там?
- Это я, добрый Ээх. Я здесь.
- И я здесь.
- А ты кто такой? Откуда взялся?
- С того берега моря.
- На чем приехал?
- Оседлал хромую блоху, сел и приехал.
- Море что - лужа?
- Может и лужа, да только ту лужу орел не перелетел.
- Значит орел - птенец?
- Наверное, птенец, да только тень от его крыльев город закрывает - в городе ночь настает.
- Город небось крохотный?
- Через тот город заяц бежал - не перебежал.
- Выходит заяц - маленький?
- Заяц - как заяц, из его шкуры тулуп вышел.
- Куда вышел?
- Вышел из того города, где заяц бежал, на который тень от орла упала, и пошел куда глаза глядят.
- Чьи глаза?!
- Глаза того тулупа, который из шкуры зайца вышел в городе, где ночь настает, когда над ним птенец пролетает верхом на хромой блохе.
- Чего?!
- Чего-чего... На хромой блохе с того берега моря, которое зайцу не перелететь, орлу не перебежать... Хоть море - не море, а так - лужа посреди города, где тень от блохи на зайца упала и насмерть убила. А из шкуры зайца тулуп вышел и пошел куда глаза глядят, тут заяц ка-ак прыгнет...
- Какой заяц?!
- Насмерь убитый. Как прыгнет куда глаза глядят, аж на тот берег моря, которое не перелететь-не перебежать, из которого тулуп вышел и в которое тень от блохи упала и зайца насмерть убила, хоть заяц - не заяц, а орел!
- Какой заяц?!! Какой орел?!! Какая блоха?!!
- Повторить? Ну значит та самая блоха, с того берега лужи...
- А-а-а-а-а!!!... Да хватит уже!!!...

Ховайся!

0 коммент. | добавить комментарий
Только что нашел такую классную (для меня) ветку одного форума, что просто ваще!

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

Популярность, йопт!

Сказка о Программе

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

А теперь – сказка.

* * *

Сказка о Программе

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

«Вот как-нибудь дойдут руки – любил говаривать Начальник – и мы обязательно выделим время на переработку и оптимизацию алгоритмов».

«Вот как-нибудь выкрою время – любил помечтать Программист – и я обязательно что-нибудь с этим придумаю!»

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

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

И эта жирная сука пробует, блядь, захуярить в нее на своем блядском ноутбуке ебаный файл, бля, в семьсот пятьдесят тысяч строк! И Аутлук его сраный чтоб не тормозил, бля, при этом! А говна тебе на лопате?! Руки оторвать к ебеням! Блядь, не тянет она, нахуй, такие объемы! Запустил Начальник Начальника программу и открыл в ней файл, состоящий из семиста пятидесяти тысяч строк. Глядь - ан работа его ноутбука нежданно-негаданно замедлилась ощутимо. Аутлук стал принимать письма через одно, а напоминания о Заседаниях - так те вообще стали появляться лишь на следующий день, и то нерегулярно.

Вызвал Начальник Начальника к себе Начальника, посмотрел на него грозно и молвил: «Будет сие исправлено к завтрему, али как?» «Будет, будет, не сумлевайтесь, ужо напрягемся» - залепетал в ответ Начальник. И пулей бросился бежать к Программисту, на ходу переставляя приоритеты задач в плане работ и придумывая, каким способом можно было бы уменьшить потребляемый Программой объем памяти…

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

***


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

Сглад фотаг!

0 коммент. | добавить комментарий
Благодаря Маришке (читайте ее ЖЖ, она хорошая), я узнал про программу Google Picasa и одноименный гугловый сервис. Теперь я имею склад фотографий, находится он здесь:

http://picasaweb.google.ru/sborodavkin


Там еще не много фоток, но это все же лучше, чем маленькие тюмбнейлы по уголкам. Уже сейчас там есть про Копенгаген и Берлин.

Берлин

0 коммент. | добавить комментарий
Ох и здорово же, скажу я вам, есть томатный суп на Унтер-ден-Линден, глядя, как «летят запряженные кони поверх Бранденбургских ворот…»! Ну да обо всем по порядку.

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

В Берлине нас встретил ее друг Филипп, они помогли мне купить билет на целый день на метро, после чего мы распрощались до вечера. Что немаловажно, Киа взяла для меня карту Берлина, так что я быстро сориентировался и решил начать с Тиргартена. Ехать туда – две остановки от Хауптбанхофа (это вокзал на местном наречии).

Ну что сказать вам про Тиргартен: лес-лесом, хоть и очень старинный. Он расположен по обе стороны от улицы 17 июня и содержит много аллей, деревьев и водоемов. Иногда там встречаются памятники, хотя «старого Тиргартенского слона» из небезызвестного стихотворения я там не нашел. И немудрено – площадь у Тиргартена просто огромная, больше двух сотен гектаров! Поразила там, пожалуй, только колокольная башня – посреди парка находится высокая башня со множеством колоколов наверху, которые все время мелодично звонят. Как эта вся кухня управляется – непонятно…

Все на той же улице 17 июня находится колонна свободы (Siegesseule), на вершине которой стоит золотая женщина с крыльями и с венком. Внутри этой колонны можно подняться наверх, но я не решился – уж лучше все самому ногами обтопать. Так что, вдоволь обфотографировав золотую женщину, я продолжил свое шествие по Тиргартену вдоль Strasse 17 Juni, пока слева не увидел памятник советским воинам, павшим в боях за взятие Берлина. Это очень, я бы сказал, величественное сооружение, с танками и пушками по бокам, и с могучим русским воином на высоком постаменте. Также на плитах позолоченными буквами написаны имена всех погибших солдат, а на двух больших клумбах рядом растут живые цветы. В общем, мне понравилось – память, хоть и горькую для себя, немцы чтят.

Совсем недалеко от памятника находится Рейхстаг со своим девизом «Dem Deutscher Volke» над главным входом. Вход сейчас туда бесплатный, в связи с чем очередь стоит вроде как в Мавзолей в лучшие времена. Конечно же, внутрь я не собирался, а только осмотрел его снаружи. Над ним теперь есть большой прозрачный купол – что-то вроде смотровой площадки, откуда видно весь комплект Бунестаг. Прямо перед Рейсхтагом – площадь Platz der Republik с очень необычным для площади оформлением (вся засеяна травой, как газончик), на которой до войны стояла колонна свободы, и где немцы праздновали объединение Берлина.

И что-то настроение у меня такое сделалось… Ну, вы меня поймете – что должен чувствовать русский человек после осмотра памятника советским воинам и Рейхстага – «он с солдатом прошел до победного по дорогам нелегких годин» и «враги сожгли родную хату» в одном флаконе. Знаете, петь военные песни, есть гречневую кашу, идти поступью победителя и плевать фрицам в морду – как-то так…

Чтобы отвлечься, я свернул от Рейхстага и вышел к Бранденбургским воротам. Они действительно выглядят очень эффектно! Пять секций, центральная – пошире, по которой было позволено проезжать только королю и его семье, и в которую нагло въехал Наполеон после взятия им города (я этого не знал – прочел на стендах). Наверху, конечно, колесница с Богиней мира и четырьмя запряженными конями – все как положено. За воротами начинается Pariser Platz и Унтер-ден-Линден, но туда я пока что не пошел.

Вместо этого я свернул в сторону площади Потсдаммер, на которой находится кинотеатр IMAX. Я очень много о нем слышал и хотел его обязательно посетить. Суть в том, что он показывает НАСТОЯЩЕЕ трехмерное кино со специальными очками и всеми делами. Купив билет, я имел еще час времени в запасе, посему сел на метро и поехал на Alexander Platz – центр Восточного Берлина.

И тут – разительная перемена. В западной части города – все красиво, культурно, чинно. Только поднялся из метро на Александр-платц – сразу оказался посреди огромной стройки, где песок, пыль, тут же рядом продают матрешек и шапки-ушанки – короче, весь ГДР-овский колорит. Однако, углубившись чуть дальше в восточную часть, я понял, что не все так печально. Улицы, конечно, заметно шире, ходит трамвай – но в остальном это, конечно, тоже настоящая Европа. Сфотографировав Ратхаус (мерию) и красивый фонтан с Посейдоном, в котором люди бултыхались и мыли ноги, я вынужден был вернуться, поскольку начинался мой фильм в IMAX.

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

После кино я вернулся к Бранденбургским воротам, и поскольку был голоден, то решил принимать пищу на Унтер-ден-Линден, в непосредственной близости от них. Конечно, родных немецких лиц в кафе под открытым небом было не видно – сплошная английская речь. Туристы – что с них возьмешь. Что удивило – так это цена: центр Берлина, а стоит как везде: с супом и со вторым с «мсьяом говьюжьим» я поел за всего за десять евро. Это напротив Бранденбургских ворот, да!

Сильно потряс меня монумент убитым евреям Европы. Представьте себе – посреди города на большом поле находится лес серых бетонных блоков, высотой от метра до трех, расположенных ровными рядами – всего больше двух тысяч блоков. Между ними можно ходить. Вид у этого всего дела просто неимоверный, первое чувство – ужас! Киа мне потом рассказала, что вокруг этого памятника велись долгие споры, городские власти долго не соглашались и пр. В частности, был такой конфуз: все блоки уже установили, и надо было покрывать их специальным составом против граффити. Однако оказалось, что концерн-подрядчик в годы войны производил газ «Циклон-Б», которым в газовых камерах концлагерей убивали евреев. Все оказалось под угрозой срыва, но «хорошее поведение» этого концерна, который участвовал в фонде для выплаты компенсаций угнанным на принудительные работы в Германию, все-таки позволило довести монумент до конца.

Ну да ладно. После обеда я пошагал по Унтер-ден-Линден опять, получается, в сторону Александр Плац – но уже пешим порядком. Теперь я уже смог не спеша оценить красоты Музейного острова, Кафедрального собора, а также университета Гумбольдта – тоже весьма красивое здание. Также я побывал в храме с органом. Как играет у них орган, правда, послушать не довелось, но ничего – все равно интересно.

Напоследок (так как дело шло к вечеру) я прокатился в район Spandau, т.к. предварительно прочел в Интернете, что это очень старый район и там очень интересно. Ничего особо интересного я там не нашел, да и, признаться, я натер себе мозоль, поэтому, поблуждав там немного, я вернулся к метро и поехал на вокзал. Там я поужинал в Макдональдсе и, встретив вскоре Кию, сел в поезд и в 21-18 отбыл в Гамбург.

Фотографии из Берлина можно посмотреть на http://picasaweb.google.ru/sborodavkin.

Кобенхавн

0 коммент. | добавить комментарий
Итак, собрался я, и в субботу рванул в Копенгаген. Дорога туда у меня была в поезде без пересадок с предварительным бронированием места – за один евро я (все через тот же автомат на вокзале, который я смог-таки заставить общаться со мной по-английски) заказал себе место «в кресле у столика в вагоне для некурящих». Вагон оказался очень удобным, с откидными столиками и с четырьмя креслами вокруг каждого. Вскоре после того, как поезд тронулся, пришел проводник и проделал дырочку в моем билете, после чего я стал читать книжку про го. Почитаю пару страничек – полюбуюсь в окошко на многочисленные ветряные электростанции и пролетающие мимо деревушки-городишки. А поезд шпарит, скорость – за сотню. Красота!

Первым моим сильным впечатлением оказалась паромная переправа. Вдруг поезд остановился и нам объявили, что сейчас нас будут погружать в паром, где мы сможем посетить кафе и магазины. Я, конечно, слышал, что такое бывает, но сам никогда не видел. А уж тем более – чтобы весь поезд взял да и заехал в паром! Переправа на нем заняла около часа; за это время я выпил кофе с ватрушкой, походил по палубам и осмотрел магазины. Магазины на пароме какие-то странные – только косметика, парфюмерия и алкоголь – ничего другого не продают. Там же (на пароме) я обменял часть евро на датские кроны, т.к. в Дании евро не в ходу.

После переправы мы поехали по Дании, и в 12-05, точно по расписанию, прибыли в Копенгаген. Я начал с того, что купил карту, а уж потом вышел на улицу. Прямо через дорогу был вход в Тиволи, так что с него я и начал.


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

Из Тиволи я вышел на площадь Ратуши – центральную площадь Копенгагена. На ней, кроме самой ратуши, есть фонтан с быком и постамент с трубадурами. Возле него я пристал к экскурсии на английском и выслушал легенду с моралью. Легенда такая: эти трубадуры должны трубить, когда рядом проходит совсем невинная девушка. А мораль, соответственно, такая: до сих пор звуков труб никто не слышал.

Также на площади есть камень «нулевой километр» - от него начинается отсчет Дании во все стороны, если я правильно понял. В одну из сторон отходит самая старая пешеходная зона в Европе – она называется Строгет и состоит из нескольких улиц. Вся она усеяна ресторанами и кафе, магазинами и сувенирными лавками. И, надо сказать, толпы там просто огромные! С одной стороны, конечно, туристы… А с другой – на мою голову, именно в субботу в Копенгагене проходил матч Дания – Швеция. Ох, и заколебали меня эти пьяные футбольные фанаты! Разодетые в форму своих любимых команд, жрущие пиво и орущие футбольные гимны – это, определенно, не для слабых духом! Поэтому я периодически сворачивал со Строгет в боковые улицы, где тоже было много интересного для меня.

Действительно, все правда – улочки в старом центре очень-очень узкие. Кое-где одна машина проедет, а две – уже не разъедутся. Но все-таки, среди многочисленных старых церквей и маленьких площадей, самое главное – это домики! Они, как мы читали в сказках, действительно раскрашены в разные цвета – тот желтенький, этот красненький, еще дальше – голубенький… На одной улице сложно отыскать повторяющиеся цвета. А крыши, крыши… Дома стоят так близко, что по ним свободно можно гулять. Не знаю насчет Андерсена, но глядя на эти мансарды, я вспоминал Карлсона-который-живет-на-крыше. Да и в принципе, конечно, Дания, Швеция – наверняка почти одно и то же в плане архитектуры. Есть поэзия в этих домиках, определенно есть!

Прошагав все улицы Строгет, я свернул по направлению к Амалиенборгу – королевской резиденции с какого-то-там древнего года. Представляет он из себя площадь с четырьмя окружающими ее одинаковыми дворцами. В субботу королевы там не было – а иначе, как я прочел в Интернете, я увидел бы там несущих караул гвардейцев в высоких шапках на медвежьем меху. По дороге я также осмотрел Мраморную церковь. Купол у нее, наверное, несколько десятков метров в диаметре – такой огромный! Внутри тоже очень красиво, хотя и не так помпезно.

Дальше, пройдя сквозь парк с фонтанами, я вышел к набережной и к Русалочке. Я слышал, что вроде бы многие ругают ее – не знаю, мне она очень понравилась. Я даже попросил, чтобы меня с ней рядом сфотографировали. Сидит такая маленькая на камушках, смотрит в море, грустит… Туристов к ней, конечно, целыми автобусами возят. Там рядом площадка и надпись: «Стоянка только для автобусов, не более 15 минут». Как автобус подъезжает – все оттуда сразу выпрыгивают и бегут к Русалочке фотографироваться.

Потом я еще погулял по набережной Langeliniekai, после чего вернулся в город, но немного с другой стороны – не через Амалиенборг, а через гавань Нихавн (Nyhavn). Она представляет собой канал длиной с километр, в котором стоят красивые парусные корабли, а по берегам – снова кафе-рестораны, и снова домики-домики. На подходе к гавани я опять пересекся с футбольными фанатами – на этот раз шведскими. Имел счастье наблюдать их старинный красивый обычай, который сейчас и опишу.

Старинный красивый шведский обычай

Итак, пьяные шведы перекрывают большой толпой узкую Копенгагенскую улочку в районе гавани Нихавн. Один из них кладет перед собой футбольный мяч и берет разбег. Толпа в это время кричит букву «У-у-у». Взяв разбег, пьяный швед лупит изо всех сил по мячу так, чтобы он подлетел как можно выше. Толпа в это время кричит букву «А-а-а», а мяч тем временем должен попасть в как можно большее количество окон.

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

Поскольку футбольный матч еще не начался, в центре было по-прежнему много футбольных болельщиков, посему я решил прокатиться на метро до станции Norreport и осмотреть два парка – Ботанический сад и замок Розенборг с прилегающим парком Rosenborg Have. Метро там, кстати, такое: длинная колбаса одним вагоном с тремя резинками посредине, вроде как в наших троллейбусах, которая едет сама – то есть без машиниста.

В Ботаническом саду было так здорово, что в Розенборг я уже опоздал – он закрылся. Пришлось фотографировать замок через забор (прутья в кадр не попали). Вот что я вам скажу, дорогие мои – парки у них просто замечательные! В том же районе я нашел еще один, небольшой, но тоже очень красивый – со склонами, старыми деревьями, травкой, цветами и скульптурами. Я бы там гулял и гулял.

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

Во время катания я сделал много фотографий и был под впечатлением, в результате чего после окончания экскурсии сел в одном ресторане прямо на воздухе, лицом к каналу, и стал ужинать. Вернусь – буду всем рассказывать: «Вот сижу я, бывало, вечером в Копенгагене, в гавани Нихавн…». Или «А в Копенгагене, в гавани Нихавн, едал я и повкуснее антрекоты».

Когда я закончил с едой, стало уже совсем темно. Прогулявшись еще по центру, в т.ч. по бульвару Ганса-Христиана Андерсена и найдя там его памятник (кстати, прямо напротив Тиволи), я прибыл на вокзал, откуда вскоре убыл… но нет, не в Гамбург.

Поездка обратно – это вообще была песня. Но зато дешево :) Из Копенгагена я поехал на станцию Fredericia. Приехал я туда в четыре-двадцать. Следующий поезд – нет, все еще не в Гамбург, а на станцию Padborg – был в шесть-двадцать. И как вы думаете, что я-таки делал два часа в этом Мухосранске? Разумеется, спал. На вокзале. На скамейке. Меня удивило, что скамейки стоят посреди зала, рядами, и на них спят вполне приличные люди, совсем не бомжеватого вида. Некоторые иногда встают, уходят в сторону платформ – видно, поезд подоспел. Так что я, откинув ложный стыд, завел на телефоне будильник, положил под голову рюкзак и два часа дрых на скамейке без задних ног. Приеду – скажу Вовчику: «Кто не спал в Дании на вокзале на скамейке – тот многого в этой жизни еще не знает».

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

А вообще-то про Париж, конечно, легче писать. Там сказал: «Елисейские поля» - и все сразу: «ах-ах-ах, Елисейские поля!». Сказал: «Монмартр» - и все сразу: «ох-ох, Монмартр!» - больше можно ничего и не говорить. А тут скажешь: «Тиволи» - и уже начинается: «а расскажи нам, что такое это твое Тиволи»… Или «Амалиен… как-как? Амалиен-брог? Ах, Амалиенборг? Нет, не слыхали».

Но мне очень понравилась поездка! Писать о ней еще и писать. Церковь святого Николая, дворец Кристианборг, цитадель… (черт, про цитадель ничего не написал!!!). Копенгаген (по крайней мере, центр и окрестности) очень впечатляет. Я бы сказал – старинен и средневеков. С чем сравнивать – не знаю. Нужно еще поездить по миру, места разные посмотреть, чтобы сравнивать-то.

Была бы возможность.

Мальчик бежит по дороге, сшибая столбы...

0 коммент. | добавить комментарий
А я позавчера был на концерте Земфиры. Вы спросите – нужно ли было приезжать для этого в Дойчланд? Да просто все так сложилось. Узнал я о концерте накануне в пятницу вечером, когда, ища в Интернете всякие развлечения в Гамбурге, наткнулся на какую-то гамбургскую афишу, а в ней увидел объявление о предстоящем концерте 28 мая. Позвонил я в кассу в 17:15, а закрывается она в 17:30. Это с одной стороны. А с другой – по удачному совпадению находится эта касса в пяти минутах ходьбы от моей работы. Так что отказать себе в удовольствии я не мог, купил билет за 25 евреев и был позавчера на концерте. Проходил он в концертном зале Markthalle в центре города.

Сергей меня, правда, пытался отговаривать. Мол, наши артисты едут в заграничные туры только для того, чтобы рубить бабло малой кровью, исполняя старые номера в течение часа с плохим звуком под фонограмму. Не знаю, кто там как, а Земфира – как Земфира, все такая же молодец, трудяга и все такое. Два с половиной часа отпахала без перерыва, мне очень понравилось! Она осенью обещает выпустить новый альбом – так что были и новые песни оттуда. Хотя, бесспорно, хитом концерта стала песенка «Зибен-зибен ай-лю-лю» в ее исполнении.



После концерта в раздевалке мне заявили, что мой зонтик пропал. Куртка есть, зонта нет. А на улице дождь, знаете ли… Я подождал рядышком, пока люди разойдутся, наблюдая, не проплывет ли рядом мой зонт. Но зонта не было. Когда толпа немного рассосалась, я снова подошел и вежливо, но твердо, снова спросил про зонт. Тетка сказала мне идти в администрацию и там разбираться. Я отправился к нужной двери, на ходу готовя длинную речь о том, какой я высокооплачиваемый работник, что час моей работы стоит 50 евро, что если я пойду без зонтика и, не дай Бог, простужусь, то неделя моего простоя обойдется вам, горе-организаторы, в две тысячи евро, что компания из-за моей болезни не сможет вовремя выпустить продукт и потеряет десятки тысяч евро, что инвесторы также понесут убытки и потеряют еще десятки тысяч…

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

С поездками все еще не очень. Был я сегодня на автобусной станции, разузнал насчет Амстердама. Туда, к сожалению, везут в неудобное время: либо в четверг, либо в субботу вечером – мне ни то ни другое не подходит. Пошел я тогда на вокзал посмотреть, как обстоят дела с поездами. Конечно, у немцев там полная автоматизация и билеты продают специальные автоматы с сенсорными экранами. Туда можно нажимать и выбирать, что только душа пожелает. А какой должна быть душа? Совершенно верно – немецкой. Никакой другой язык ни в одном автомате выбираться не пожелал.

В общем, набрал я на автобусной станции разных буклетиков – может, выберу что другое, окромя Амстердаму. Может, Питера удастся вытащить на вокзал после работы, чтоб он мне помог. Ну а нет – так уж нет. Зато мы с ним и с его (ну как правильно склоняется это имя?!) Кией едем в Берлин 9-го июня в 8-00 утра, а возвращаемся в 23-30. Поезд идет всего полтора часа, дорога туда и назад стоит всего 40 евро.

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

Зацените: «Битте цвай хамбургег, кляйне поммс мит кетчуп, кляйне кола мит кайн айс унд милкшейк кирш».

Кроме того, когда у меня в ресторане спрашивают «Алес гешмект?», я умею ответить: «Я-я, натюрлих, филен данке, зер гут гешмект!» А уж о том, что мне почти всегда понятно, сколько нужно заплатить в магазине, когда кассирша невнятно говорит, например, «фюнф цванцих» - об этом я даже и говорить не буду, ввиду своей бесконечной природной скромности.

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

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

Одесса-Гамбург

2 коммент. | добавить комментарий
Ну что ж, период «чтоб враги не сглазили» прошел, посему посвящаю непосвященную часть своей молчаливой аудитории, что снова мне по делам служебным пришлось прилететь в Гамбург, где я буду находиться следующие 6 недель. К счастью, в этот раз в номере есть Интернет – а это значит, что качество жизни неуклонно растет, честь и хвала немцам (хотя все равно мало мы их, засранцев эдаких, дрючили в сорок пятом!)


Долетел я опять не без происшествий. Самолет из Одессы вылетел где-то на двадцать минут позже запланированного, что привело к тому, что в Пражский аэропорт RUZYNE (или как-то так) я вышел за 10 минут до отлета самолета на Гамбург. На табло напротив рейса Прага – Гамбург уже моргала надпись “LAST CALL” – и я побежал изо всех сил. Бежать пришлось минут десять – ну ничего, зато на чек-ине оценили, сказали “you were very quick”.

Но я-то успел, а вот багаж-то мой – нет. Меня утешили, что так часто бывает. Сказали, что наверняка завтра утром его пришлют, и тогда его привезут мне на такси. А пока что я иду завтра на работу небритый и в отстойной футболке.

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

Вот.

Обезьяны и пол-ребенка

0 коммент. | добавить комментарий
Обращаю внимание своей молчаливой аудитории, что у меня в блог-ленте появился новый ЖЖ. Петр Бормор пишет туда сказки. Читайте их, они хорошие.

У одного индуса жили три обезьяны: слепая, глухая и немая.
Однажды в дом забрался вор, увидел обезьян и собрался их убить, чтобы не оставлять свидетелей.
-Ничего не вижу!- поспешно сказала слепая обезьяна.
-Ничего не слышу!-добавила глухая.
А немая только руками развела: она, мол, и рада бы что-то сказать, да вот не может.
Вор успокоился, собрал всякое добро в мешок и убежал.
Утром хозяин обнаружил пропажу и вызвал полицию.
-Я всё видела!- сказала глухая обезьяна.
-Я всё слышала!- добавила слепая.
"А я записала номер машины",- показала знаками немая и протянула листок.
--------
Скольких преступников уже погубило слепое следование стереотипам!..

(c) bormor

UPD сразу: ну и безоглядова, как всегда, великолепна:

Поперек Ленинского проспекта висит рекламная перетяжка:

"Мы поможем определить пол Вашего будущего ребенка"
WWW.POLREBENKA.RU

О рынках ПО

0 коммент. | добавить комментарий
А что, все уже знают, как нынче модно пробиваться на рынок программного обеспечения? Сейчас я напишу о двух стратегиях завоевания. Первую все знают. Называется она:

"Написать программу, которую еще никто не написал"

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

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

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

"Написать программу, которую написали все"

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

Это значит, что ваша целевая аудитория, во-первых – большая, а во-вторых – многообещающая. Ну, например, напишите мейлер лучше чем TheBAT!, и вы гарантированно найдете своего покупателя. Опять-таки, обилие конкурентов позволяет выделить набор функциональности у конкурирующих продуктов (стырить фичи), добавить что-то свое и выпускать новый продукт.

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

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

А какой рынок выбираете вы?

Правило

0 коммент. | добавить комментарий
В результате работы над моим Java-проектом я придумал Правило. Применяйте его почаще.

Правило
Всегда, когда вы можете использовать архитектуру Model-View-Controller, используйте ее.

Это окупится. Зуб даю.

Еще раз о собеседовании

2 коммент. | добавить комментарий
Мне довелось на этой неделе неделе на пару с коллегой - тимлидом дружественной команды собеседовать кандидата на должность Java-разработчика. Для меня это был дебют. В Академосе я, правда, проверял тесты - но это совсем другое. Сидеть на собеседовании с Другой Стороны Стола и задавать вопросы - это куда как более сильно.

Собеседование мы проводили техническое - соответственно, нас избавили от необходимости рассказывать кандидату про то, что "в компании Люксофт пишут ахуенный софт", или "Люксофт: пишем разные программы классные".

Мы спросили про опыт работы и готовые проекты. Узнав, что человек занимался системой учета персонала, я зацепился за слово "персонал" и стал выяснять, как бы он сохранил список персонала на диске или передавал бы его по сети. Соответственно, обсудили Serializable (знал) и Externalizable (плавал). Поговорили о паттернах - попутно выяснив, что кандидат не знает UML, хоть в резюме и обещал. Потрепались об MVC на примере компонента JTable, который рисует табличку. Говорили также о многопоточности в Java и особенностях ее в Swing (человек хвастал знаниями Swing'а, но о его вопиющей не-потоко-безопасности - опять ни сном ни духом).

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

Потом еще про алгоритмы спрашивали (сам виноват - зачем писал в резюме про "знание алгоритмов сортировки, поиска, и т.д."). Про сложность алгоритмов он никогда не слышал, ни один алгоритм сортировки даже не назвал, про binary search не рассказал...

Еще о многом говорили - зацепили Exception'ы, особенности Java 1.5, Eclipse, SWT... Короче, промурыжили мы его около часа, и не взяли. Хочу теперь проводить много собеседований. Как мне кажется, решение "не взять" - гораздо менее ответственное, чем "взять". Поэтому хочу теперь кого-то "взять". Джависты, ау! У нас правильный настрой!!!

UPD 13.02.07: вчера еще одного собеседовал! Этому давал уже две задачки - одну на простой алгоритм, и другую - на простое проектирование, но уже не про стол, а про автобус. Дела идут...

Vista и распознавание голоса в ей

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

Теперь злой пользователь Вася может написать песенку со словами, например, такими:

Ай-ай-ай, вот бы здорово
Стереть каталог C:\WINDOWS,
И при свете полной луны
Очистить корзину, да-да!


Если у жертвы злого пользователя Васи в момент прослушивания этой песенки будет включен микрофон, то ей типа будет плохо. Ну, так себе уязвимость на самом деле, хотя может причинить и зло. А вот кому будет классно - так это вирусописателям. Я помню те времена, когда вирусы писались на ассемблере, и было это типа сложно. С новой версией Windows все меняется! Рекламный ход Microsoft заключается в следующем:

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

  • РАЗ: напишите словами, что бы вы хотели от вашего вируса
  • ДВА: передайте полученную строку в Windows Speech API
  • ТРИ: робот Сэм произнесет, а новая Windows Vista автоматически выполнит все ваши команды! Наша система позволит Вам стать более успешными! Откиньтесь на спинку кресла и наслаждайтесь!

Вот такие-то пироги. Теперь им придется учить систему реагировать только на голос ее хозяина. Багов-то будет :) Ну, Forza Vista!

Lonewolf on CMMI

1 коммент. | добавить комментарий
CMMI (Capability Maturity Model Integration) - это модель улучшения процесса разработки продуктов и служб. Сегодня я буду говорить о CMMI-DEV - CMMI для разработки ПО. Эта модель имеет 5 уровней (чем выше уровень - тем круче). Любая компания может за несколько десятков тыщ вызвать к себе бравую команду оценщиков и пройти сертификацию на определенный уровень.

Зачем это нужно? Ну, например, вы возглавляете аутсорсинговую компанию "Швайнске" и как раз окучиваете нового клиента. Заклинание "Наш процесс разработки сертифицирован на CMMI Level N" - это хороший способ как минимум привлечь к себе внимание, а как максимум - вполне может повлечь за собой подписание контракта на Q сладких лет.

Вот Люксофт на своем сайте заявляет о том, что имеет CMMI 5 уровня. Врут. На самом деле, пятый уровень имеет только филиал в Москве, и то не весь. У нас, как я считаю, сейчас уровень 2 (но сертификации нет никакой, так что можно мне не верить). А вообще уровни зрелости бывают такими:

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

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

Уровень 3. Определенный. Процессы понимаются всеми и описываются в терминах стандартов, процедур, инструментов и методов - гораздо более строго, чем на уровне 2. Документы теперь стандартизованы на уровне всей организации, и никак иначе. А главное - на уровне 3 происходит следующее: конкретные личности перестают определять процесс разработки.

Теперь стоп. Дальше пока не рассказываю.

Ведь посмотрите: что происходит в мире разработки ПО последние лет дцать? Мы изо всех сил стараемся снизить влияние человеческого фактора на процесс разработки и на конечный продукт. Началось с программной инженерии, сейчас вот CMMI-DEV и аналогичные модели, имя коим - легион... Уровни 3, 4 и 5 предполагают, что если, например, команду в ответственный момент покинет ключевой разработчик, то ничего страшного не произойдет. Мы попросту заменим его другим человеком близкой по уровню квалификации, и он волшебным образом втыкнет во все сразу - потому что у нас классный процесс, документирование, процедуры и метрики.

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

Ставлю интересный вопрос: хорошо это или плохо? Нужно ли стремиться к получению 5 уровня? Или можно остановиться на третьем?

По мнению многих, процессы уровней 4 и 5 являются самодостаточными. Легко можно представить себе крупную компанию, сертифицированную на CMMI ML4 или ML5, в которой дни напролет работа просто кипит: пишутся отчеты, проводятся собрания, выпускаются руководящие инструкции, выполняется расчет разнообразных метрик... Только вот разработка программ как-то не очень укладывается в эту картину. Нет времени на разработку, потому как поддерживать хороший процесс - это вам не хухры-мухры, на это время нужно!

Но многие также думают, что стремиться нужно к CMMI ML3, что это хорошо, а я говорю - не очень хорошо. Почему?
  1. Потому что вполне можно смириться с тем, что соседняя команда не понимает процессов в моей команде - им это и так ни к чему, у них есть свои.
  2. Пусть каждая команда имеет свой набор документов - лишь бы им удобно работалось.
  3. Потому что мне хочется работать с квалифицированными коллегами, а не с безликим персоналом.
  4. Потому что я предпочту уменьшить текучку, тем самым снизив риск ухода ключевых специалистов.
  5. И еще потому, что люди - это самое важное, что может быть в разработке софта, что бы там не втирали нам эксперты из Carnegie Mellon Software Engineering Institute. Им надо свой CMMI продавать, а нам надо работать и делать мир лучше.
Таким образом, если мы не ставим своей целью пробиться к наивысшему уровню 5, то остановиться вполне можно на втором. Третий - это не очень круто, и преимущества от него не столь значимы.

Итого: как по мне, так на сертификации можно и сэкономить (если вы не директор аутсорсинга "Швайнске"). Гораздо важнее то, что в действительности происходит внутри вашей организации. И если вы часто опаздываете со сроками, оказываетесь перед необходимостью внесения изменений в последние минуты, ваши расходы растут и вы не можете точно сказать, чем занимается сотрудник вон за тем столом - попробуйте пересмотреть ваши взгляды на процесс разработки. Я смею утверждать:
  1. Процесс не ограничивает свободу вашего творчества
  2. Процесс - не то же самое, что бюрократия
  3. Внедрение процесса оправдано в равной степени как для больших, так и для маленьких команд.
  4. Процессы хороши даже для очень маленьких команд.
  5. Даже если вы одиночка - вам все равно нужен процесс.
  6. CMMI-DEV уровня 3 не так хорош, как его малюют. Часто имеет смысл остановиться на уровне 2.

Диплом

0 коммент. | добавить комментарий
Завтра защищаю диплом. Тема - "Методика и программные средства для автоматизированного составления учебного расписания".

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

Да, если кто вдруг ищет работу программистом в Одессе - обращайтесь, могу порекомендовать. Нужны C++, Java, QA engineer / QA team lead. Luxoft и Techinsight.