1. Checking Microsoft Orleans with PVS-Studio for fun and profit

    Intro

    Every developer knows that good code quality is not granted. It comes by way of an iterative process of continuous improvement. We know how innocent changes can subtly introduce bugs in another area - a developer changes something in one module and breaks something in another.

    It’s essential to have some static ananlysis tool in the developer’s toolbelt. Such a tool can easily save you hours and days of debugging and prevent production failures. And you can use any tools you like, as long as you are paying attention to its warnings and hints.

    In this post, I’m going to use PVS-Studio to analyze “Microsoft Orleans”. If you are not aware what PVS-Studio is - let me grab a snippet from official website >

    PVS-Studio 6.0 performs static code analysis and generates a report that helps a programmer find and fix bugs. PVS-Studio does a wide range of code checks, but it is especially useful to search for misprints and Copy-Paste errors.

    Recently, the company released version 6.0 with initial C# support. I was waiting for this release for a while, so I’ve contacted the team behind the tool and asked for a trial license to test and write an article.

    As you may know - PVS-Studio team checks open-source projects from time to time, to show the strengths of their product. They were doing their own check of Microsoft Orleans project, when I contacted them. Team let me to do the check and kindly shared their traditional “unicorn-branded” image for the article.

    PVS-Unicorn-In-Clouds

    ### Microsoft Orleans, virtual actors and … profit :).

    Microsoft Orleans logo

    Microsoft Orleans is a framework based on the concept of virtual actors. Orleans terminology is different from other actor frameworks (Akka, Service Fabric) - Actor objects are Grains and Server\Host instances, who forms a single Cluster, are Silos.

    A huge benefit of using virtual actors is that at any moment your code can obtain, from Orleans runtime, a proxy class for a specific grain with known Id and interface and invoke any method on it. The invocation will send a message to your cluster, which will be delivered to a grain with a given Id. Runtime guarantees that any grain with a given Id will be created only once and all messages will be delivered to that instance. Runtime does automatic activation and deactivation of grains based on grain-related activity. If the silo which hosts your grain goes offline - cluster automatically balances your grain to other Silo and redirect grain messages there. Your code won’t be affected except a minor call delay.

    Also, runtime gives you guarantees that code on the grain will be executed in single-threaded mode, so no other calls can come in between method operators, and you don’t need to complicate method with any multi-threading fences and locks.

    The “profit” of such frameworks is that they are very easy to scale - product takes many heavy duties off of developers’ shoulders and allows them to focus on writing business-valuable code. You don’t need to know any special syntax - simply write traditional OOP-style code and let runtime care for the rest.

    Microsoft Orleans has plenty of other great features, like pluggable storage providers, explicit messaging via streams, pub-sub and others valuable additions for developing cloud- or on-prem-based highly scalable solutions. You can read more about the project here - Microsoft Orleans@GitHub.

    And it is worth to note, that Orleans is used in Halo 4 and Halo 5 backends, so it’s literally production battle-tested ;)

    PVS-Studio goes Orleans, Analysis results


    Microsoft Orleans is being developed very rapidly, and it’s obvious that a one-off analysis won’t make any significant quality shift in a long run, it just allows us to highlight some of the current issues.

    I’ve checked latest source-code after PR#1288 was merged. PVS-studio shows

    • 18 High-severity warnings
    • 7 Medium-severity warnings
    • 58 Low-severity warnings.

    Also it worth to mention the split of warnings between main runtime code and unit\integration tests projects:

    PriorityTotalRuntimeTests
    High18 12 * 6
    Medium7 4 3
    Low58 13 45


    * - 4 warnings were in a single method and other 3 were in old and least used code.

    Okay, let’s drill down and see if PVS-Studio found something dangerous.

    High-severity warnings

    The most significant finding of this check is this pretty serious bug in a key sanitization method. As was discovered later team were scratching their heads about another problem which roots from this bug. And were fully convinced that “sanitization works fine”.

    PVS-Studio gave this message

    **V3010 The return value of function ‘Replace’ is required to be utilized. AzureStorageUtils.cs 278,279,280,281 **

    and it was about this method:

    public static string SanitizeTableProperty(string key)
    {
        // Remove any characters that can't be used in Azure PartitionKey or RowKey values
        key.Replace('/', '_');  // Forward slash
        key.Replace('\\', '_'); // Backslash
        key.Replace('#', '_');  // Pound sign
        key.Replace('?', '_');  // Question mark
        if (key.Length >= 1024)
            throw new ArgumentException(string.Format("Key length {0} is too long to be an Azure table key. Key={1}", key.Length, key));
        return key;
    }
    

    Oops, classical snake oil - sanitization is there, but the key passed into the method is returned unchanged. Strings are immutable in .NET and calling Replace like this doesn’t change the original string.

    Another finding -

    V3006 The object was created but it is not being used. The 'throw’ keyword could be missing: throw new InconsistentStateException(FOO). MemoryStorageGrain.cs 129

    if (currentETag != null)
    {
        string error = string.Format("Etag mismatch during {0} for grain {1}: Expected = {2} Received = null", operation, grainStoreKey, currentETag.ToString());
        logger.Warn(0, error);
        new InconsistentStateException(error);
    }
    

    Creating new InconsistentStateException without throw keyword. The code below this section has a properly thrown exception, so this can be considered as a missed bug.

    Next warning that worth to pay attention to (false alarm in our case):

    V3022 Expression 'USE_DEBUG_CONTEXT_PARAMS && arguments != null && arguments.Length > 0’ is always false. GrainReference.cs 480*

    [NonSerialized] private const bool USE_DEBUG_CONTEXT_PARAMS = false;
    ...
    if (USE_DEBUG_CONTEXT_PARAMS && arguments != null && arguments.Length > 0)
    {
        ...
    }
    

    The statement is always false and can be optimized and removed by .NET compiler. It’s fine in our case as we have some debugging statements there but such behaviour may be damaging if some important code will be “optimised”

    The following warning was found in rarely executed code, so it didn’t cause noticeable problems, but could:

    V3025 Incorrect format. A different number of format items is expected while calling 'Format’ function. Expected: 3. Present: 2. Program.cs 169,183

    WriteStatus(string.Format("**Calling DeleteGrain({0}, {1}, {2})", silo, grainId));
    
    WriteStatus(string.Format("**Calling LookupGrain({0}, {1}, {2})", silo, grainId));
    

    It may look like everything is fine here and failing to write logs is OK. But actually this code will throw an exception:

    FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.

    Formatting wars. They were for a good cause. Re-phrasing what warning says - “this code is hard to read and prone to potential errors”

    V3033 It is possible that this 'else’ branch must apply to the previous 'if’ statement. Interner.cs 251

    private void InternCacheCleanupTimerCallback(object state)
    {
    ...
       long numRemoved = numEntries - internCache.Count;
       if (numRemoved>0)
           if (logger.IsVerbose) logger.Verbose(ErrorCode.Runtime_Error_100296, "Removed {0} / {1} unused {2} entries in {3}", numRemoved, numEntries, internCacheName, clock.Elapsed);
       else
           if (logger.IsVerbose2) logger.Verbose2(ErrorCode.Runtime_Error_100296, "Removed {0} / {1} unused {2} entries in {3}", numRemoved, numEntries, internCacheName, clock.Elapsed);
    }
    

    Such implicit and loosely formatted blocks are doors wide-open to bugs, like Apple had in their certificate verification:

    Apple certificate check bug:

    if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
        goto fail;
    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
        goto fail;
        goto fail; **V3054 Potentially unsafe double-checked locking. Use volatile variable(s) or synchronization primitives to avoid this. StreamImpl.cs 142, 144**
    

    I’ve cut some code parts for brevity

    private readonly object initLock; // need the lock since the same code runs in the provider on the
    ...
    internal IInternalAsyncObservable<t> GetConsumerInterface()
    {
        // Canonical double-checked locking
        if (consumerInterface == null)
        {
            lock (initLock)
            {
                if (consumerInterface == null)
                {
                    if (provider == null)
                        provider = GetStreamProvider();
    
                    consumerInterface = provider.GetConsumerInterface<t>(this);
                }
            }
        }
        return consumerInterface;
    }
    

    Initially, when I saw this code, I had some doubts (yes, multi-threading is hard ;) ) about if this double-locking pattern can be applied to a non-static object. But this is not a singleton pattern as I thought after the first look… This pattern implementation is correct and it may be a false positive alert in PVS-Studio.

    NB: I actually tried to understand this case deeper to clarify it for myself. But digging deeper I found
    “Sayonara volatile” by Joe Duffy and couple other articles and posts on this matter, which opened my personal “can of multi-threaded worms”.

    Worth to note that PVS-Studio is capable of detecting certain complex patterns, like Double-checked locking.

    Next good spot - a problem that hard to catch by a million eyes, but easy by a static code analysis:

    V3022 Expression 'n1 == 0 && n1 != 0’ is always false. Unsigned type value is always >= 0. Probably the ’||’ operator should be used here. UniqueKey.cs 113

    private static UniqueKey NewKey(ulong n0, ulong n1, Category category, long typeData, string keyExt)
    {
        // in the string representation of a key, we grab the least significant half of n1.
        // therefore, if n0 is non-zero and n1 is 0, then the string representation will always be
        // 0x0 and not useful for identification of the grain.
        if (n1 == 0 && n1 != 0)
            throw new ArgumentException("n0 cannot be zero unless n1 is non-zero.", "n0");
    

    Comment is describing one set of checks and conditions and if statement has another. And again - every time you’re following a certain code style - God saves a kitten. Compare how obvious this problem with clearly named variables.

    if (n1 == 0 && n1 != 0)
        vs
    if (secondHalf == 0 && secondHalf != 0)
    

    And this warning appears pretty often in logs - methods were copy-pasted, renamed but old logic stays.

    V3013 It is odd that the body of 'IncrementMetric’ function is fully equivalent to the body of 'DecrementMetric’ function (1079, line 1095). TraceLogger.cs 1079

    Spaced Copy-Paste, actually there is one properly implemented copy pasted method

    public override void IncrementMetric(string name, double value)
    {
        foreach (var tc in TelemetryConsumers.OfType<imetrictelemetryconsumer>())
        {
            tc.IncrementMetric(name, value);
        }
    }
    ...
    public override void DecrementMetric(string name, double value)
    {
        foreach (var  tc in TelemetryConsumers.OfType<imetrictelemetryconsumer>())
        {
            tc.IncrementMetric(name, value); // This Decrement method increments...
        }
    }
    

    The unreliable code in unit tests may be annoying. If test randomly halts once per 10 or 100 runs - it feels like a Heisenbug - unexpected and very hard to debug. This doesn’t mean that we have one here, but if you can - write your tests as your main code - no dangerous expressions allowed.

    V3032 Waiting on this expression is unreliable, as compiler may optimize some of the variables. Use volatile variable(s) or synchronization primitives to avoid this. LoggerTest.cs 468

    // Wait until the BulkMessageInterval time interval expires before wring the final log message - should cause bulk message flush
    while (stopwatch.Elapsed **V3051 An excessive type check. The object is already of the 'Exception' type. PersistenceGrainTests.cs 178**
    
    catch (AggregateException ae)
    {
        exceptionThrown = true;
        Exception e = ae.GetBaseException();
    ->> if (e is Exception)
        {
            // Expected error
        }
        else
        {
            throw e; // this will never happens
        }
    }
    

    throw e; will never be executed, as if will be always true - any DerivedException is Exception Is this critical? Yes and no, it depends on the context - in some components, it may be minor but critical in others.

    Low-severity warnings

    Relatively many minor warnings PVS-Studio produced for the unit testing code. Checking all of them I can say - there is no critical issues there, mostly - some complex testing logic to trigger edge case scenarios, like this one

    V3008 The 'promise’ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 91, 84. TestInternalGrains ErrorGrain.cs 91

    // the grain method returns but leaves some unobserved promise
    
    Task<long> promise = Task<long>.Factory.StartNew(() =>
    {
        if (!doThrow)
            return 0;
        logger.Info("About to throw 1.");
        throw new ArgumentException("ErrorGrain left Immideate Unobserved Error 1.");
    });
    -->>promise = null;
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    return Task.FromResult(11);
    

    This code is trying to verify the behaviour of garbage-collected Task. Which may be a sign of a problem, but this is intentionally done this way in tests.

    Or another: Initialize and Cleanup methods have same code

    V3013 It is odd that the body of 'TestInitialize’ function is fully equivalent to the body of 'TestCleanup’ function (44, line 52). ConfigTests.cs 44

    [TestInitialize]
    public void TestInitialize()
    {
        TraceLogger.UnInitialize();
        GrainClient.Uninitialize();
        GrainClient.TestOnlyNoConnect = false;
    }
    
    [TestCleanup]
    public void TestCleanup()
    {
        TraceLogger.UnInitialize();
        GrainClient.Uninitialize();
        GrainClient.TestOnlyNoConnect = false;
    }
    

    And another error-prone code formatting

    V3043 The code’s operational logic does not correspond with its formatting. The statement is indented to the right, but it is always executed. It is possible that curly brackets are missing. RequestContextTest.cs 87,97,111,155,181

    if(msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)
    {
        headers.Add(kvp.Key, kvp.Value);
    };
    

    Practical outcome

    Out of all findings reported to Orleans bug tracker, 5 were marked as bugs. One with Replace is epic ;) Pretty good catch for barely 20 mins of automatic code analysis.

    Why Code analysis is not a favour of the month.


    Microsoft Orleans has very high velocity, you can see the pulse and commits frequency on GitHub - Orleans-contributors. Over the course of writing this article I’ve checked the project few times, saving analysis logs. The table below shows that even in a very professional team of developers “bugs happen…”

    Priority 28 Jan2 Feb4 Feb v6.01Comments
    High 19 21 18 2 days and -3 critical warnings, which is a good sign, but 2 of these criticals were V3025 (String.Format args) so they must be cleaned before sending PR.
    Medium 4 4 7 +3 medium severity - may be fresh bugs.
    Low 52 46 58 +12 inaccurate code areas


    As you can see, even within the short timespan, new bugs rise and fall. Having a tool for quickly bringing some of them into the spotlight is always a good thing. And every static analysis can help. Whatever you like - Resharper, PVS-Studio, FxCop or any other code analysis - use it, and use it regularly. It’ll save your precious time you otherwise may be spending in the debugger or chewing through megabytes of trace logs. If you aren’t using one - you’re doing dev wrong.

    On the convenience of modern tools - they all pretty much on the same page - “It just works”. PVS-Studio has nice and noticeable context menu entry when right-clicking in Solution Explorer. Also, you can run it from Visual Studio “quick launch” menu - Ctrl+Q and start typing 'PVS’. It’d be good to see some kind of nuget that enables dev to type something like PVS-Solution or PVS-Project and, later on, add this command to your CI build script. But current integration works well for most typical usage scenarios.

    Conclusions


    Modern realities set pretty high expectations for the code quality and velocity. Everyone is running fast just to stay on the same level in the industry. No surprise that even strong teams and senior developers can miss some tricky or, sometimes, obvious bugs. Comprehensive test suit helps with staying on track. But someone needs to build one first, not talking about the effort to maintain such suite in up-to-date state. Thus any “helping hand” you can get, is valuable, doesn’t matter if it’s a paid tool or some free alternative.

    Static analysers is just one of them, whether it’s Visual Studio built-in one, PVS-Studio or Resharper. They don’t really compete with each other but complement one another to make the best out of developer time and energy. Even such simple thing like enabling “Treat Warnings as Errors” may save you from couple of shots in the foot.

    Try many, choose few, use regularly as toothbrush ;)

    Thanks for reading that far. Happy and bug-free programming!

    PS: Author wants to thank everyone who’s helped to proof-read this article and PVS-Studio team for a trial license offered for this testing.

     
  2. Проверка проекта Microsoft Orleans с помощью PVS-Studio

    Введение


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

    Начну я эту “новую страницу” с опробования хорошего, но до некоторого времени неприменимого в .NET, инструмента как PVS-Studio (для сомневающихся в чистоте моих намерений - да, за этот пост я, возможно, получу лицензию на 1 год для проверки Orleans. А может и не получу, как фишка ляжет-с).

    PVS-Studio 6.0, как заявляет официальный сайт компании, это статический анализатор кода, ориентированный на простоту использования и поиск ошибок на этапе написания кода. И относительно недавно, компания зарелизила версию, поддерживающую проверку C# проектов. Чем мы собственно и будем проверять проект Microsoft Orleans.

    Кстати, команда PVS-Studio тоже проверяла проект Orleans на предмет выявленных ошибок, но я их немного опередил и они любезно предоставили мне свою КДПВ (“картинку для привлечения внимания”) с неизменно радующим единорогом.

    PVS-Unicorn-In-Clouds

    Что такое проект Orleans, Виртуальные актеры и в чем их профит.


    Microsoft Orleans logo

    Microsoft Orleans это framework, который построен на концепции виртуальных актеров. Терминология Orleans немного отличается от других подобных фреймворков (Akka.Net, Service Fabric, Erlang Actors):
    Актеры называются Grains (ака зерна), а сервера, участвующие в кластере - Silo.

    Преимущество виртуальных актеров в том, что в любой момент ваш код может получить у Orleans Runtime прокси для обращения к конкретному Grain по его интерфейсу и Id. При вызове методов прокси посылается сообщение кластеру из нескольких серверов, где оно будет доставленому Grain-у с заданным Id. Runtime гарантирует, что такой Grain будет создан в единственном экземпляре на одном из серверов и последующие вызовы будут доставлены ему. Runtime также автоматически удаляет из памяти (деактивирует) Grain-ы, которые не получали вызовов заданное время, таким образом постоянно собирая “мусор”. Если сервер на котором находилось ранее ваше “зерно”, ушел в оффлайн - Runtime быстро поднимет инстанс на другом и вы ничего не заметите, кроме небольшой задержки. Если вызов должен прийти на тот же самый сервер - Runtime это оптимизирует и вызов будет локальным.

    Собственно, профит виртуальных актеров в том, что это все очень легко масштабируется в облаках: Silo пингуют друг друга и определяют когда кто-то недоступен, перераспределяют зерна “павшего камрада” между собой и все такое. Кластер радостно живет и доступен, пока есть хотя бы одно активное Silo, и при подключении новых участников - они получат свой диапазон “зерен” и начнут активно обрабатывать запросы. А свой код вы пишите, используя привычный ООП-подход. Получается такой, как бы “Distributed C#/.NET”.

    Еще сам рантайм дает гарантии что при выполнении метода на зерне, никакой другой вызов не на то же самое зерно не прийдет, т.е. рантайм гарантирует single-threaded выполнение вашего кода, что позволяет меньше думать о всяких не-thread-safe ситуациях и больше сосредоточиться на написании полезной бизнес-логики.

    Вообще, там еще много других интересных вещей, таких как заменяемые провайдеры хранилища, messaging, pub-sub и другие полезные вещи для разработки приложений под облачные (или распределенные on-prem) платформы. Подробней с проектом можно ознакомиться здесь - Microsoft Orleans@GitHub. Microsoft Orleans неплохо протестирован и в масштабных проектах - этот фреймворк используется на бакенде игр Halo 4 и Halo 5 - собирает информацию о всех играх, аггрегирует статистику и т.д.

    Почему захотелось проверить Orleans


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

    Во-вторых, концепции и гарантии, заложенные в Orleans, довольно нетривиальны и от их реализации зависит качество работы кластера.

    В-третьих - было просто интересно попробовать PVS-Studio с С# - команда продукта пишет отличные статьи про проверку С++ проектов, а вот C# был как-то обделен вниманием до последнего времени.

    Результаты проверки


    Проект Microsoft Orleans развивается очень динамично и, очевидно, разовая проверка хоть и поможет найти сомнительные места - в длинной перспективе на общее качество повлияет не сильно.

    Итак, по состоянию на момент мержа PR #1288 4/02/2016 2:43:26 PM, Commit hash: 7c1e35466fde08fcf1c2caf64fa304d25e60e045 PVS-Studio (версия 6.01.15638.1) нашла: * 18 High-priority
    * 7 Medium-priority * 58 Low-priority

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

    И еще - вот таблица, которая показывает разделение ошибок между основным кодом (Runtime и вспомогательные проекты) и кодом в тестах:

    PriorityTotalRuntimeTests
    High18 12 * 6
    Medium7 4 3
    Low58 13 45


    * - 4 предупреждения на неправильное использование Replace в одном методе, 3 предупреждения в малоиспользуемом коде. Итого ~5 на которые стоит обратить внимание.

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

    Критичные ошибки, обнаруженные в проекте

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

    …an embarrassing bug in SanitizeTableProperty that IIRC puzzled us recently. …were sure the sanitization worked.

    PVS-Studio выдала вот такое предупреждение:

    **V3010 The return value of function ‘Replace’ is required to be utilized. AzureStorageUtils.cs 278,279,280,281 **

    И по указанном адресу находился (баг уже исправлен) метод:

    public static string SanitizeTableProperty(string key)
    {
        // Remove any characters that can't be used in Azure PartitionKey or RowKey values
        key.Replace('/', '_');  // Forward slash
        key.Replace('\\', '_'); // Backslash
        key.Replace('#', '_');  // Pound sign
        key.Replace('?', '_');  // Question mark
        if (key.Length >= 1024)
            throw new ArgumentException(string.Format("Key length {0} is too long to be an Azure table key. Key={1}", key.Length, key));
        return key;
    }
    

    Довольно классный баг, прямо snake oil (…и тут медленно пришло прозрение что этот баг скорей всего вылезал и в нашем коде пару раз….). Параметр key типа string, к тому же передается в метод. Строки в .NET immutable, так что сколько бы раз мы не вызывали key.Replace - значение не изменится.

    Следующая неплохая находка -

    V3006 The object was created but it is not being used. The 'throw’ keyword could be missing: throw new InconsistentStateException(FOO). MemoryStorageGrain.cs 129

    if (currentETag != null)
    {
        string error = string.Format("Etag mismatch during {0} for grain {1}: Expected = {2} Received = null", operation, grainStoreKey, currentETag.ToString());
        logger.Warn(0, error);
        new InconsistentStateException(error);
    }
    

    Новое исключение создается, но не выбрасывается. Т.е. если при записи присылается Etag=null и это первая запись, ошибки не происходит. Чуть ниже в том же методе исключение все же выбрасывается - т.е. у нас тут пропущенная проблема.

    Еще одно предупреждение:

    V3005 The 'jsonSettings’ variable is assigned to itself. AzureTableStorage.cs 104

    При чтении конфигурации настройки сериализации в переменной jsonSettings инициализируются 2 раза:

    if (useJsonFormat)
    {
        jsonSettings = jsonSettings = OrleansJsonSerializer.SerializerSettings;
    }
    

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

    Следующее (false alarm в нашем случае):

    V3022 Expression 'USE_DEBUG_CONTEXT_PARAMS && arguments != null && arguments.Length > 0’ is always false. GrainReference.cs 480*

    [NonSerialized] private const bool USE_DEBUG_CONTEXT_PARAMS = false;
    ...
    if (USE_DEBUG_CONTEXT_PARAMS && arguments != null && arguments.Length > 0)
    {
        ...
    }
    

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

    А это предупреждение найдено в малоиспользуемом коде, поэтому этот участок не вызывал особых проблем, но мог бы:

    V3025 Incorrect format. A different number of format items is expected while calling 'Format’ function. Expected: 3. Present: 2. Program.cs 169,183

    WriteStatus(string.Format("**Calling DeleteGrain({0}, {1}, {2})", silo, grainId));
    
    WriteStatus(string.Format("**Calling LookupGrain({0}, {1}, {2})", silo, grainId));
    

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

    FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.

    А следующее предупреждение может сигнализировать о реальных проблемах в логике кода, в Orleans это, к счастью, только логгирование -

    V3033 It is possible that this 'else’ branch must apply to the previous 'if’ statement. Interner.cs 251

    private void InternCacheCleanupTimerCallback(object state)
    {
    ...
       long numRemoved = numEntries - internCache.Count;
       if (numRemoved>0)
           if (logger.IsVerbose) logger.Verbose(ErrorCode.Runtime_Error_100296, "Removed {0} / {1} unused {2} entries in {3}", numRemoved, numEntries, internCacheName, clock.Elapsed);
       else
           if (logger.IsVerbose2) logger.Verbose2(ErrorCode.Runtime_Error_100296, "Removed {0} / {1} unused {2} entries in {3}", numRemoved, numEntries, internCacheName, clock.Elapsed);
    }
    

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

    Apple certificate check bug:

    if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
        goto fail;
    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
        goto fail;
        goto fail;
    

    Для того чтобы такие вещи не появлялись - есть StyleCop и много других методов “принуждения к правильному стилю”. И их тоже полезно использовать.

    Еще одно предупреждение, тоже незначительное в данном случае, просто избыточная проверка. Но если проверка вычислительно “дорогая” - стоит от нее избавиться.

    V3053 An excessive expression. Examine the substrings ’/bootstrap’ and ’/boot’. ClientGenerator.cs 310

    else if (arg.StartsWith("/bootstrap") || arg.StartsWith("/boot")){...}
    

    На этом критические ошибки, которые достойны внимания, заканчиваются и впереди еще немного Medium и побольше Low.

    Найденные Medium ошибки

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

    V3054 Potentially unsafe double-checked locking. Use volatile variable(s) or synchronization primitives to avoid this. StreamImpl.cs 142, 144

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

    private readonly object initLock; // need the lock since the same code runs in the provider on the
    ...
    internal IAsyncBatchObserver<T> GetProducerInterface()
    {
    ->>  // not so сanonical double-checked locking, effectively doing the same,
        if (producerInterface != null) return producerInterface;
        lock (initLock)
        {
            if (producerInterface != null) 
                return producerInterface;
    
            if (provider == null)
                provider = GetStreamProvider();
    
            producerInterface = provider.GetProducerInterface<T>(this);
        }
        return producerInterface;
    }
    
    internal IInternalAsyncObservable<T> GetConsumerInterface()
    {
    ->> // Canonical double-checked locking
        if (consumerInterface == null)
        {
            lock (initLock)
            {
                if (consumerInterface == null)
                {
                    if (provider == null)
                        provider = GetStreamProvider();
    
                    consumerInterface = provider.GetConsumerInterface<T>(this);
                }
            }
        }
        return consumerInterface;
    }
    

    Два примера применения Double-checked locking паттерна. Чак Норрис мира .NET (aka Jon Skeet) в статье Implementing the Singleton Pattern in C# приводит более изящную и надежную реализацию, если нужен синглтон.

    Я еще хотел написать что:

    Но вот лично у меня этот код вызывает еще одно сомнение: во всех статьях и примерах этот паттерн всегда использует lock на static объект, и вот я не очень уверен, что его можно применять на non-static локах с гарантированно надежным результатом…

    Но, после общения с разработчиками и чтения вот этой статьи Sayonara volatile by Joe Duffy, соглашусь, что т.к. в нашем случае это не синглтон, допустимо использование не-статического поля. И без volatile.

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

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

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

    V3022 Expression 'n1 == 0 && n1 != 0’ is always false. Unsigned type value is always >= 0. Probably the ’||’ operator should be used here. UniqueKey.cs 113

    private static UniqueKey NewKey(ulong n0, ulong n1, Category category, long typeData, string keyExt)
    {
        // in the string representation of a key, we grab the least significant half of n1.
        // therefore, if n0 is non-zero and n1 is 0, then the string representation will always be
        // 0x0 and not useful for identification of the grain.
        if (n1 == 0 && n1 != 0)
            throw new ArgumentException("n0 cannot be zero unless n1 is non-zero.", "n0");
    

    Тут надо было проверить n0!=0 , как и написано в комментарии к этому коду, а в текущей реализации проверка всегда false. Опять же, хороший Coding-style мог бы помочь в данном случае - если бы переменные не назывались n0 и n1, а например firstHalf и secondhHalf - ошибка бы бросалась в глаза более явно. Сравните:

    if (firstHalf == 0 && secondHalf != 0)
        vs
    if (secondHalf == 0 && secondHalf != 0)
    

    Предупреждение об одинаковом коде в двух разных методах -

    V3013 It is odd that the body of 'IncrementMetric’ function is fully equivalent to the body of 'DecrementMetric’ function (1079, line 1095). TraceLogger.cs 1079

    Spaced Copy-Paste, между этими 2-мя методами есть еще и правильная реализация декремента, который уменьшает метрику.

    public override void IncrementMetric(string name, double value)
    {
        foreach (var tc in TelemetryConsumers.OfType<IMetricTelemetryConsumer>())
        {
    ->>     tc.IncrementMetric(name, value);
        }
    }
    ...
    public override void DecrementMetric(string name, double value)
    {
        foreach (var  tc in TelemetryConsumers.OfType<IMetricTelemetryConsumer>())
        {
    ->>     tc.IncrementMetric(name, value);
        }
    }
    

    То же самое, но в тестах:

    V3013 It is odd that the body of 'StartTimer’ function is fully equivalent to the body of 'StopTimer’ function (183, line 188). TimerOrleansTest.cs 183

    public Task StartTimer(string timerName)
    {
        if (persistant) return persistantGrain.StartTimer(timerName);
        else return grain.StartTimer(timerName);
    }
    public Task StopTimer(string timerName)
    {
        if (persistant) return persistantGrain.StartTimer(timerName);
        else return grain.StartTimer(timerName);
    }
    

    Этот привет от Ctrl+C, Ctrl+V в тестах может иметь и худшие последствия - тесты будут false-positive.

    Сложный код в тестах:

    V3032 Waiting on this expression is unreliable, as compiler may optimize some of the variables. Use volatile variable(s) or synchronization primitives to avoid this. LoggerTest.cs 468

    // Wait until the BulkMessageInterval time interval expires before wring the final log message - should cause bulk message flush
    while (stopwatch.Elapsed <= TraceLogger.BulkMessageInterval)
    {
        Thread.Sleep(10);
    }
    

    Я сам не очень хорошо понимаю, как и почему цикл здесь может превратиться в бесконечный, но пример в описании этого предупреждения на сайте PVS-Studio более понятный [V3032]. Не очень большая проблема, т.к. код в тестах, но даже в теории - произвольно падающие тесты или зависающие бесконечно долго - не самая приятная штука.

    И опять странный код в тестах -

    V3051 An excessive type check. The object is already of the 'Exception’ type. PersistenceGrainTests.cs 178

    catch (AggregateException ae)
    {
        exceptionThrown = true;
        Exception e = ae.GetBaseException();
    ->> if (e is Exception)
        {
            // Expected error
        }
        else
        {
            throw e;
        }
    }
    

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

    Low priority ошибки, обнаруженные в проекте

    Довольно много замечаний PVS-Studio обнаружила в тестах, но просмотрев большинство из них, можно сделать вывод, что критических или high-impact проблем среди них нет, просто комплексно протестировать такой продукт довольно сложно и часто приходится идти на разные ухищрения, чтобы вызвать определенное поведение системы.

    Например вот:

    V3008 The 'promise’ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 91, 84. TestInternalGrains ErrorGrain.cs 91

    // the grain method returns OK, but leaves some unobserved promise
    
    -->>Task<long> promise = Task<long>.Factory.StartNew(() =>
    {
        if (!doThrow)
            return 0;
        logger.Info("About to throw 1.");
        throw new ArgumentException("ErrorGrain left Immideate Unobserved Error 1.");
    });
    -->>promise = null;
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    return Task.FromResult(11);
    

    Проверяется поведение кода с таском, который собран GC.

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

    ** V3013 It is odd that the body of 'ProduceSequentialSeries’ function is fully equivalent to the body of 'ProduceParallelSeries’ function (618, line 625). StreamingGrain.cs 618**

    public override async Task ProduceSequentialSeries(int count)
    {
        await base.ProduceParallelSeries(count);
        State.Producers = _producers;
        await WriteStateAsync();
    }
    
    public override async Task ProduceParallelSeries(int count)
    {
        await base.ProduceParallelSeries(count);
        State.Producers = _producers;
        await WriteStateAsync();
    }
    

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

    V3013 It is odd that the body of 'TestInitialize’ function is fully equivalent to the body of 'TestCleanup’ function (44, line 52). ConfigTests.cs 44

    [TestInitialize]
    public void TestInitialize()
    {
        TraceLogger.UnInitialize();
        GrainClient.Uninitialize();
        GrainClient.TestOnlyNoConnect = false;
    }
    
    [TestCleanup]
    public void TestCleanup()
    {
        TraceLogger.UnInitialize();
        GrainClient.Uninitialize();
        GrainClient.TestOnlyNoConnect = false;
    }
    

    В тестах конфигурации при инициализации и при завершении зачем-то дважды проводится ДЕ-инициация примитивов. Интересно зачем.

    V3043 The code’s operational logic does not correspond with its formatting. The statement is indented to the right, but it is always executed. It is possible that curly brackets are missing. RequestContextTest.cs 87,97,111,155,181

    if(msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)
    {
        headers.Add(kvp.Key, kvp.Value);
    };
    

    И все-таки, я большой сторонник строгих Coding-style правил. Ну или хотя бы автоматического принуждения к стилю, путем StyleCop, Resharper или CodeFormatter. Это ничего не стоит, но позволяет не ломать глаза.

    V3052 The original exception object 'ae’ was swallowed. Stack of original exception could be lost. GrainReferenceCastTests.cs 212

    catch (AggregateException ae)
    {
        Exception ex = ae.InnerException;
        while (ex is AggregateException) ex = ex.InnerException;
        throw ex;
    }
    

    Теряем стек AggregatedException. Я понимаю, что для случаев с другими исключениями это плохо, но мы в нашем проекте точно так же “раскручиваем” AggregatedException. Я бы записал это в false-positive если в catch секции именно AggregatedException.

    Оценка критичности найденых багов разработчиками проекта.

    Из всех отправленных отчетов об ошибках, спустя 3 часа 5 отмечены как bug, 1 критический с Replace исправлен Довольно неплохой улов для 20 минут статического анализа в автоматическом режиме.

    Почему Code analysis это не очередной favour of the month.


    Проект Orleans развивается очень интенсивно, частота коммитов очень высокая, Gihub это подтверждает - Orleans-contributors. За время написания статьи, я проверил проект несколько раз, сохраняя логи анализа. В том числе разными версиями PVS Studio (6.0 и 6.01).

    Вот сравнение разных логов:

    Priority 28 Янв2 Фев4 Фев v6.01Comments
    High 19 21 18 За два дня -3 критичные ошибки - что хорошо. Но 2 из них были аналогами V3025 (string.Format args), что очевидно баг.
    Medium 4 4 7 За эти же 2 дня +3 предупреждения средней тяжести.
    Low 52 46 58 И +12 новых участков неаккуратного кода.


    Как видно из таблицы, критические ошибки появляются и исчезают за очень короткое время. Куда как удобней отлавливать их в результате анализа сразу после билда, а не после часов дебага или падения продакшена - экономит время и нервы программиста. Это, конечно, банальность из серии “Лучше быть богатым и здоровым, чем бедным и больным”, но если еще есть программисты, которые не используют хоть какой-нибудь доступный статический анализатор кода - “You’re doing it wrong” …

    В плане удобства использования - интеграция у PVS-Studio с Visual Studio 2015 довольно простая - в контекстном меню Solution Explorer на С# файле, проекте, или корневом solution есть пункт Analyze with PVS-Studio с хорошо заметной зеленой иконкой. Довольно легко найти. Если только в этом контекстном меню нету еще 100500 пунктов от других расширений. Было бы интересно увидеть какой-нибудь вспомогательный nuget пакет, который бы умел легко запускать анализ из командной строки, чтобы можно было открыть Package Manger Console или build.cmd и сказать PVS-Solution или PVS-Project Orleans, ну и чтобы потом это все как-то встроилось в xproj механизмы нового CoreCLR.

    Хотя, для быстрого запуска хватает и Ctrl+Q, PVS ... Down, Down, Down, Down, Enter :).

    Заключение


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

    Любой статистический анализатор, будь то предупреждения Visual Studio, анализатор Resharper'а или PVS-Studio, это еще один инструмент в коллекции разработчика и помощник при обнаружении потенциальных проблем с кодом. Используйте хотя бы то, что доступно бесплатно. Например, на всех наших проектах по умолчанию включен режим Treat Warnings as Errors, что помогает писать код чуть более дисциплинированно. Это ничего не стоит программисту, но может сберечь его от выстрелов себе в ногу. Современные анализаторы использовать очень легко, в большинстве случаев всё отлично работает “из коробки” и единственное, что может хоть как-то оправдать не-использование анализаторов, это вопрос цены.

    NB: Автор благодарит команду PVS-Studio за предоставленную временную лицензию для тестирования.

    Всем прочитавшим - Happy and bug-free programming!

     
  3. “Право на ошибку” и его стоимость.

    В процессе работы над разными проектами в Австралии, я заметил интересное различие в трудовой культуре Австралии и России. Конечно же этих различий тут много, но вот это конкретное - имхо очень сильно влияет на восприятие ежедневной работы. А именно - “стоимость” ошибки в России и в Австралии очень разная. Сейчас поясню…

    Что больше всего отложилось из рабочего процесса в России - допускать ошибки нельзя или ультра-крайне нежелательно, ошибка программиста - это катастрофа, полный провал, непрофессионализм и бездарность. Даже если ты ее исправил сразу или попозже - уже запятнался. И эта линия шло красной нитью через все места работы, будь то околооборонный НИИ или известная продуктовая компания. Т.е. совершив ошибку на работе в России ты в своих глазах (да и в глазах окружающих) становишься изгоем. “Ты налажал!”, как приговор. Ну ладно, не совсем как приговор, но ехидный колючек в свою сторону огребешь сполна, можно быть уверенным. Даже после единственного такого факапа - в голове откладываются неприятные ассоциации. А уж напыщенно-дребезжащие комментарии “Нуууу, Леееша”, “ээх, нахеровертили вы там” и “ну кто так строит, кто так строит” - вспоминаются до сих пор с мурашками. В общем уровень драмы неприличной зашкаливает на пустом месте.

    Всё, теперь после единственного фэйла подходим к требованиям - как к иконе, перестраховываемся 100500 раз, придумываем нереальные сценарии и комбинации параметров, и сами же от них защищаемся в коде. В общем довольно много энергии тратится просто на то, чтобы случайно не налажать еще раз. Даже не так - чтобы ни в коем случае ни на гран не допустить сомнений в своем профессионализме. Т.е. если нужен запас прочности 1, мы положем 10, нет, лучше 12, если из 100 000 пользователей из-за редизайна интерфейся вдруг уйдет один - это крест на бизнесе, прибыли не будет и надо вывернуться, но удержать всех и каждого.

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

    В Австралии (ну по крайней мере то, что я видел) - ситуация обратная. Сделать ошибку - нестрашно, если сам ее и исправил - так вообще молодец. Даже если что-то не получается, коллеги попытаются подбодрить, подсказать, иногда просто влезут в разговор с дельным (или не очень ;) ) советом. Ошибки конечно появляются, их исправляют, но самое важное - никто не нагнетает драму, не ходят и не шпыняют, что “вот налажал, ну что ж, лох это судьба”. Не все, не везде и не всегда, но в общем здесь люди предпочитают поддержать тебя и помочь, улыбнуться, что-то подсказать или даже просто попытаться разобраться вместе - вдруг это подтолкнет тебя на путь решения проблемы.

    В общем - ошибки тут делать легко и приятно. Ну вернее не совсем приятно, потому как есть еще внутренние стандарты, которые все еще твердят что “Ошибка - это лажа, страшная драма!”, но нету того давящего ехидства и боязни показаться хоть в чем-то непрофессионалом. Ты знаешь, что тебе ошибки простят… От этого жить и работать в Down Under в этом плане - значительно приятней. Не давит постоянный страх ошибки, не тратится энергия на какие-то нелепые и неподтвержденные опасения и ситуации, которые могут возникнуть в будущем. “Когда проблема возникнет - тогда и будем думать как ее решать, если не получится отложить” - это наверное основной скрытый девиз работы в Австралии.

    К сожалению даже у такого положительного и расслабленного режима работы есть и “обратная сторона медали” - можно легко прекратить учиться новому, т.к. если сделал ошибку и за это ничего не было, то можно пойти в другое место и там покосячить, здесь покосячил, там покосячил, вроде как и дело двигается, но качество такое, что постоянно надо переделывать. Но это уже индивидуальный вопрос каждого человека о внутренней “планке качества”, снаружи ее поднять очень трудно…

    Идеальный сценарий - высокая внутренняя планка качества, которая задирается вверх избытком “драмы” и “страхом ошибки” в России и расслабленное отношение к совершаемым и исправляемым ошибкам, которое есть в Австралии. Тогда будет оставаться больше энергии на полезные дела, а не на “борьбу с ветрянными мельницами навязанных страхов”.

    А вы, друзья-коллеги, как думаете - существует ли завышенный “уровень драмы” в России и расслабленное отношение к ошибкам в Австралии ?

     
  4. One Year at the end of the Rainbow

    Как-то внезапно, день за днем, прошел уже целый год. Ага, именно 19 ноября 2012 года я второй раз ступил на территорию Австралии, но уже без обратного билета в кармане. За это время произошло много разного, интересного и полезного. Вообще, забегая вперед, на сегодня это самый интересный год жизни, который я прожил =) . Потому что много всего поменял. И снаружи, в виде своего окружения и внутри, под влиянием другой ментальности и другого мировоззрения.

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

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

    Работа. С ней у меня все как-то легко получилось, может потому что опыт был совпадающий с тем, что компания искала, может потому что еще и по цене немного демпинговал, а может просто повезло, а “умный и хороший” тут совсем непричем - не знаю. Зато за этот год работы сформировались взгляды, которые раньше особо не могли возникнуть.

    Во-первых работа это все же сотрудничество двух сторон, и обе стороны могут и должны высказывать свое мнение на тему успешности сотрудничества. Почему-то в России у меня не было ощущения, что работаешь “больше, чем просто на дядю”, а тут - есть. Может быть это от новизны, а может быть это действительно так, и к мнению сотрудников прислушиваются чаще (мб компания пока еще маленькая). Тут все как-то более открыты и твою инициативу могут не только выслушать, но и воплотить. Это здорово, потому что это создает ощущение что ты что-то можешь поменять, можешь сдвинуть компанию в “правильном” направлении. А если что-то сильно не нравится - поменять, спрос на опытных программистов есть везде. Воодушевляет однако.

    Во-вторых - нет апатии. Возможно потому что проблем меньше, возможно потому что другая рабочая этика, но люди выглядят более заинтересованными в результатах, они понимают что хотят и умеют считать свои затраты на проект. А как только все научились считать - сразу оказывается что использовать услугу А лучше и удобней чем “переизобретать велосипед” своими силами. Это кстати ощутимо меняет стиль работы - уже не думаешь о том, что “надо предусмотреть еще 100-500 фич”, а просто рекомендуешь какой-то хороший продукт, пусть даже платный. Или берешь доступную хорошую библиотеку, вместо написания и сопровождения своих оберток. Также клиент с удовольствием пользуется премиум поддержкой от Microsoft, и вполне успешно. Наши проблемы с некоторыми сервисами решались инженерами из Microsoft довольно быстро. Это позволяет консультантам сосредоточиться на основной цели проекта и сделать в срок все что хотел заказчик. Приятно стоять на плечах других гигантов.

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

    А еще - похвалы и комплименты. Не в обиду никому будет сказано, но за год работы тут я услышал во много раз больше положительных отзывов, чем за все время работы в России. Как-то не принято в нашей культуре говорить - “молодец, отличная работа” или “здорово что ты заметил эту проблему”. Да даже если кто-то такое скажет - на него просто посмотрят дико - не издеваешься\не стебешься ли. Это неправильно, и такое отсутствие внешних оценок сильно демотивирует (Вопрос о качестве и ценности таких оценок - это отдельная тема). Ну неужели так трудно признать за другим человеком успех и сообщить ему об этом ? У нас многие почему-то считают успех соседа как свою личную неудачу, вот и доходят коллективы до состояния “пауков в банке”. Признавать чужой успех как и свои ошибки в России стыдно. А здесь - нормально, ожидаемо.

    Вот такая вот разница в бизнес-этике.

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

    Как мне кажется, люди тут особо не ждут великих лидеров которые “вот вот выведут народ в светлое будущее” - просто берут и делают сами на местах. То что считают полезным и правильным. Маленькие усилия, маленькие действия на местах - и все меняется. Ну например (правда старый уже пример) - выставили мне штраф за якобы просроченную оплату интернета, 15$, не много но неприятно (на фоне месячного платежа - немного :) ). Начал разбираться с поддержкой - оказывается они сами не смогли списать с моей карты деньги потому что что-то у них не сработало. Компания в лице сотрудника спокойно признала свою вину, снял штраф и еще сделал подарок в ~$20-25 скидки со следующего счета. Вот скажите мне - много ли саппорта первой линии в российских компаниях имеет возможность за 5 минут принять решение об индивидуальных финансовых изменениях для клиента. Я боюсь что даже софта, который такое умеет делать, особо не много.

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

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

    PS: Я честно постараюсь еще раз возобновить практику написания статей в блог на более регулярной основе. Но хотелось бы видеть фидбэк и комментарии от читателей, если таковые имеются. Чтобы убедиться что это интересно не только мне.

     
  5. Remember Remember the 1st of Movember или “усатый ноябрь”.

    Есть в Австралии (и не только в Австралии) замечательное движение - Movember. Название образовано от двух слов - moustache + November. Суть движения довольно проста - сбор благотворительных взносов на разработку лекарств и способов лечения “мужских болезней” - рака яичек, простаты и еще на поддержание психического здоровья. Казалось бы таких благотворительных организаций вокруг - множество, и все они так похожи друг на друга. Но эти ребята нашли просто отличнейший подход к продвижению - сами мужчины и продвигают ежегодную кампанию по сбору средств, при этом получая и доставляя море позитива и удовольствия.

    Rebels with moustaches

    Рецепт продвижения примерно следующий. Берется мужчина, одна особь. Путем командного brain-шторма определяется, чем же эта особь может отличаться от особи женского пола. Оказывается - усами. Далее придумываются несложные правила:

    1. Первого Movember, Mo Bro (moustache brother - “братан по усам”) должен начать с “чистого листа”, т.е. чисто выбритым, без бороды и и усов.
    2. В течении месяца Mo Bro должен растить и ухаживать за усами
    3. Нельзя соединять усы с бородой - это считается goatee
    4. Нельзя соединять усы с бакенбардами - это считается как борода
    5. Каждый Mo Bro должен быть джентельменом :)

    И предлагается участвовать всем мужчинам. В этот микс добавляется неплохой сайт, промоматериалы, различная mo-branded аттрибутика (футболки, кепки и прочее) и приложение под iPhone. Для закрепления результата - приложение под iOs и возможность соревноваться с другими Mo Bros, как по отдельности так и в команде. Да, да, взращивание усов - это командный вид спорта :).

    В результате 1 “моября” в офисах появляются чисто выбритые мужчинки, которых ранее без бороды и представить было невозможно, многие коллеги их даже не узнают, ну или весь день давят улыбку, потому как - “непривычно” очень. А у участников появляется очень удобная причина для объяснения “Почему Володька сбрил усы” - “Ну так ведь Movember на дворе… Нравится - делай взносы ;-)”. Это почти “официальная” возможность раз в год попробовать вырастить что-то новое или что-то необычное - и повод есть, полезное дело, и количество вопросов “А зачем ты это сделал?” в этот месяц резко снижается.

    Вот и я решил поучаствовать, попробовать что-то новое, посмотреть на “этого странного чудика” в зеркале, да и просто словить лулзов, как говорится.

    Вот примерно так выглядит мой прогресс “выращивания свежих усов” за неделю. По-моему неплохо :)

    1st to 8th Movember

    Если вам это нравится, вы считаете что мы делаем правильное дело или просто хотите улыбнуться глядя на усатых Mo Bros то можно:

    Делать добрые дела весело и легко, надо только начать ;-)

     
  6. Про рекламу и почему я ее не люблю …

    Тут в Facebook возник довольно интересный вопрос от Дмитрия Дерягина:

    Боюсь уже спрашивать… А почему так дико напрягает открытая реклама? …То есть ну правда. Я считаю совершенно нормальным желание разных компаний себя порекламировать. Иногда некоторые объявления мне надоедают, я их отключаю (у фейсбука можно попросить не показывать то или иное неинтересное объявление). Но так как тут всё честно и прозрачно, мне это нравится. В отличие от перепостов от знакомых непроверенных объявлений о больных детях из Африки.

    Попробую ответить, почему меня напрягает реклама. Для начала я в общем согласен с мнением что честная и “в меру” реклама лучше чем тот спам что встречается в интернете. Но даже это особо проблему не решает.

    Имхо ответ довольно очевидный - обильная реклама - это визуальный мусор. Многие признают, что повышенный уровень шума вреден для здоровья, влияет на концентрацию и продуктивность. Но человек получает до 80-90% (по разным источникам) информации через зрение - почему же никто не говорит, что интенсивные визуальные нагрузки - тоже вредны. Вообще-то наш мозг прекрасно фильтрует ненужную визуальную информацию. Проблема только в том, что рекламодатели идут на многое чтобы пробить эти фильтры - мигающая реклама, яркая и анимированная, трехмерная (билборды со всякими выступающими конструкциями), выскакивающие окна, подчеркнуто кричащие заголовки, имитация вспышки на баннерах.

    Lots of ads

    Помимо того, что излишняя реклама вызывает напряжение и ненужное переутомление, у нее есть еще несколько проблем:

    Первая проблема, как мне кажется - реклама категорически нерелевантна. Даже в фэйсбуке (в мобильном приложении нельзя избавиться от рекламы вообще), который уже вроде как очень много знает о моих предпочтениях по лайкам и различным постам, реклама безумно нерелевантна. Мне зачем-то рассказывают в какие игры играют дети френдов на iPad (игры в свою очередь замусоривают ленту своими лайками и достижениями), показывают в какие флеш-игры я могу сыграть на телефоне, который флеш вообще не поддерживает. Не говоря уже о том, что предлагает Гугль на основании поиска - там тоже все довольно печально. Про всякие мелкие и крупные баннерные сети - даже говорить не о чем. Т.е. по сути пользы от меня рекламодателю - 0, ну не перейду я по ссылке “купить холодильник” если я уже 3 недели перестал интересоваться этой темой, потому что уже купил его, но мне его упорно будут предлагать. И автомобиль я не буду покупать перейдя по баннеру (это вообще крайняя степень “доверчивости”).

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

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

    Кстати, в Мельбурне рекламы довольно мало. Ну вернее, бумажный спам попадает в почтовый ящик регулярно и его даже больше чем в было в Москве (надо вот купить наклейку No Junk Mail, говорят помогает). А вот внешней уличной рекламы мало - она в основном локализована на остановках в виде небольших стендов, или большие билборды в метро. И на торговых улочках, т.е. там где много магазинов - они могут себя рекламировать - вывеску там или стойку поставить. Рядом с новостройкой есть объявления, что вот тут за углом продаются квартиры (“стальные”…). Но такого безобразия как в Москве, когда все просто залеплено рекламой и находясь на одном конце города можно узнать, что на другом конце продаются квартиры в новостройке или фаянсовые унитазы - нету.

    На дорогах (особенно за городом) в большинстве своем социальная реклама о том, что не надо быстро ездить и “если устали - остановитесь и немного поспите (powernap now :) )”. Да и сама реклама не вычурная и кричащая. Она не давит на глаза, рассеивая внимание и отвлекая. Т.к. ее тут мало, то иногда ее даже интересно почитать, если никуда не торопишься. По сравнению с Москвой, где все фильтровалось на уровне подсознания, тут я стал больше обращать внимания на рекламу.

    Light of city ads

    Массовая реклама уродует облик городов. Это третья проблема. Вот у меня почти все картинки-воспоминания о Москве (да и не только о Москве, обо всех местах в России, где я побывал, кроме Валаама и Выборга наверное) содержат рядом стоящий билборд, или перетяжку с рекламой какой-нибудь бани над дорогой или на фоне церкви. Причем понимание насколько облик города изуродован приходит только после того, как поживешь некоторое время в городе без уродующей рекламы. Когда осознаешь, что настоящий “профиль” любого города, т.н. Skyline - это вообще-то не 20-метровые телевизоры на крышах и 100-метровые зеленые банеры какого-нибудь Мегафона, а прекрасные профили старых зданий (которых в Москве, я не сомневаюсь, не меньше чем в любом другом городе), ну или на крайний случай - небоскребы из стали и стекла, хотя последние нравятся не всем.

    Я думаю других причин почему люди не любят рекламу - можно найти очень много. Для меня перечисленные проблемы, кмк - основные. И я не разделяю рекламу на real life ads * vs *internet ads, для меня это один и тот же вид дискомфорта. Как говорится - “в сортах г..на не разбираюсь”.

    Собственно возникает простой вопрос - почему я должен на это смотреть? Если в случае аудио-мусора я могу переключить радио, купить интересующее музыкальное произведение и слушать его без рекламы или просто одеть звукоизолирующие наушники, то в случае с визуальными раздражителями я не могу их избежать, пока нету очков фильтрующих рекламу в реальной жизни. Зато в интернете - могу. Достаточно поставить себе AdBlock и наслаждаться более “чистым” интернетом. А выбирать из кучи отвратительной рекламы ту, которая может быть не такая уж и плохая - нет времени и желания, проще все спрятать чем тратить время разбирая ее на “непричастных и виноватых”.

    И да, времена когда реклама показов или переходов работала - уже, имхо, проходят. Гораздо адекватнее вступать в персональные коммуникации, через фэйсбук, твиттер, любые доступные социальные сети. Если вы продаете услугу - расскажите о ней, вместо того чтобы спамить мой почтовый ящик или вывешивать мигающие баннеры на слабо-релевантном сайте. А еще стоит задуматься о том, что чем дольше пытаться поддерживать статус-кво и цепляться за старые методы что работали 10 лет назад - тем дальше будут убегать адекватные и не боящиеся пробовать новое конкуренты. И пользователи тоже помогают поддерживать в полуживом состоянии таких вот “дохлых лошадей”. Не согласны ? Комментируйте.

     
  7. Записки далекого марсохода From Down Under. Часть 3.5 Open space офис, как убийца производительности программистов.

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

    Да, еще маленькое отступление - мне тут рассказали какие “страшные кары” могут быть за то, что не так что-то сказал про клиента работодателя и все такое. Поэтому я постараюсь без лиц и указаний, просто общее мнение на тему “другого” офиса (по сравнению, конечно, с Аби)

    Когда я был “молодым и глупым” :) - я не верил, что в мире бывают такие опен-офисы, которые показывают в разных сериалах:

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

    Типа вот такого…

    Random open office

    Ну т.е. для любого человека, который изучал вопрос влияние рабочего места на производительность программистов, да и не только программистов (пусть даже “диванный эксперт” по статьям в интернете) - сразу возникает недоумевающий вопрос - “Ээээ, а зачем так ?”.

    Минусы такого открытого пространства очевидны. Шум снижает производительность. Особенно если еще нет привычки работать в шумном окружении - это вообще катастрофа, я до сих пор считаю что у меня снижена производительность. Хотя наша команда уже переехала с прохода в более тихую комнату.

    Запахи еды. В Австралии, как мне рассказали (т.к. изначально я думал, что это особенность нашего “клиента”), довольно распространен подход обедать на рабочем месте, т.е. своя еда в “пасочках”, греют и прямо перед ноутбуком или компьютером едят. В целом мне этот подход не нравится, ибо - если не грязными руками испачкаешь клавиатуру, то запахи - это же витающие в воздухе частички пищи, они оседают на поверхностях ноутбука. И это еще не худшая ситуация, сам запах может довольно сильно отвлекать. Думаю некоторые Аби-татели прекрасно помнят вареную рыбу из микроволновок. А теперь представьте какой-нибудь ядренный карри, да не на закрытой кухне, а по всему офису. И не от одного-двух сотрудников, а от десятков. В общем, то еще “бедствие”.

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

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

    Кстати, наша команда испытала довольно заметный подъем производительности, когда мы переехали из “проходного стола” в закрытое помещение.Внешнего шума стало меньше и теперь он уже чаще создается самими сотрудниками (диалоги и обсуждения, ну и разговоры “через диагональ стола”). Этот уровень уже можно нивелировать наушниками и музыкой (“контролируемый шум”).

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

    К чему я все это пишу… Наверное к тому, что хочется сказать всем, кто в Аби жалуется на кубиклы и шум - вы, кмк, плохо представляете себе что такое открытый офис, шум на рабочем месте и какое падение производительности это может вызывать. Да, бывает и лучше, типа у каждого свой кабинет и все такое, но это скорее в сказках про светлую жизнь. А вот в жизни - всегда начинаешь ценить что-то, когда это потеряешь. Потеряете тихий офис - поймете что такое “шумно”. В Аби в большинстве своем тихо, как в библиотеке.

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

    А вы как думаете - какие могут быть преимущества у open-space офиса, по сравнению с кубиклами или кабинетами ?

     
  8. Записки далекого марсохода From Down Under. Часть 3.1 О ежедневной работе и Kloud Solutions

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

    Я, в общем, тоже каждый день таскаю рабочий ноут. Лично мне это даже нравится, удобнее чем стационарный комп и “практичнее”. Правда есть пара проблем - привыкнуть к клавиатуре ноута - довольно проблематично, ну по крайней мере, я за месяц еще не привык. Есть вменяемая радиоклавиатура, как решение проблемы, но ее на работу надо донести, да и места там не много - не разложишься сильно. Вторая проблема - низкое расположение дисплея ноутбука. За день довольно сильно устает шея т.к. смотреть приходится ниже обычного подъема монитора. Эту проблему в офисе решают высокими подставками (где-то док-станция, где-то просто телескопическая лапа), но в силу ограниченности и временного рабочего места (ибо наемная сила) - у нас пока нету.

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

    Немного о компании: у Kloud Solutions довольно интересная внутренняя сервисная инфраструктура . “Как следует из названия, подкустовный выползень…” Эмм, в силу основного “облачного” направления бизнеса - вся инфраструктура в “облаках” (про локальные сервера я еще ничего не слышал :) ). Т.е. это и Sharepoint Online, Office2013 + Office365, всякие облачные Exchange and Lync, Team Foundation Service (угу, облачная тележка), синхронизации и все такое. Ну и понятное дело - лабораторные площадки для экспериментов - Azure\AWS.

    С одной стороны - это довольно удобно, тебе выдали пару-тройку логинов, добавили твоему родному аккаунту права в sharepoint и все работает. С другой стороны - без интернета уже вообще никуда ( особенно это раздражает в TFS), а он в Австралии не только не быстрый и не дешевый (по сравнению с МО, тут какие-то заоблачные цены), но еще и регулярно отваливающийся, даже Wi-fi в офисе =(. Что приводит к очевидным проблемам - работа периодически прерывается на восстановление интернета - потому как без него - ни коммит не сделать, ни билд запустить, даже Work Item или Product Backlog в TFS не посмотреть. Так что everything-in-cloud для повседневной работы - довольно спорная тема. Хостинг приложений - да, отлично работает, а повседневная рутина - появляется узкое место в виде постоянного internet соединения.

    В таком ракурсе мне кажется, что следующим логическим развитием Distributed VCS должна стать интеграция в Git\Mercurial различных backlog\bugtracking приложений, которые бы хранили свою информацию в DVCS, и могли бы ее синхронизировать. Т.е. точно также как происходит работа с изменениями в коде проекта - должно происходить и с задачами\багами в проекте. Работаешь локально - ведешь историю своих багов, делаешь pull\push - отправляешь не только код но и связанные work items\bugs. Конечно это не так хорошо как полностью централизованная система, и всякие burndown charts не построишь пока не соберешь данные со всех участников, но в некотором виде - это может работать, ИМХО.

    Вернемся к Kloud Solutions. Я успел поучаствовать пока только в одном team meeting, но было довольно интересно. На самой встрече, вначале Nicki Bowers (это Managing Director Kloud Solutions) рассказала о том, какие клиенты с какими проектами есть у компании, об их отзывах на работу Kloud, перспективы и ближайшие горизонты. Все это довольно интересно (особенно в первый раз), потому что позволяет понять куда и как движется компания, создает определенное чувство сопричастности, а не просто отношения “работодатель-работник”. Не знаю, есть ли подобное мероприятие у всех IT-компаний тут (но сомневаюсь), но сам подход, имхо, очень правильный.

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

    А потом мы перешли к “Сheck-in” :). Забавная процедура, когда каждый кратко рассказывает о том, чем он сейчас занимается, на каком проекте и кратко немного о себе. С одной стороны это позволяет понять, “кто все эти люди” вокруг :), узнать чем они занимаются, в чем они эксперты. С другой стороны - с первого раза оказалось сложно даже просто запомнить всех людей по именам, не говоря уже про область их профессиональной экспертизы или проекты на которых они работают. Но думаю после 2-3 таких team meeting, будет уже попроще.

    В моем понимании эта встреча была таким упрощенный team building, не сфокусированным вокруг какой-то activity типа картинга\paintball\lasertag, а просто сбор команды в одной комнате и обсуждение текущего положения дел (а под пиво после официальной части это было еще более расковано). Вообще такие мероприятия, как мне кажется, позволяют сотрудникам обрести некий common ground, общее понимание и видение ближайших перспектив.

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

    В следующем посте будет про open office, еду на рабочем месте, шум и производительность. Ваш марсоход остается на связи.

     
  9. Записки далекого марсохода From Down Under. Часть 3, “рабочие будни на красной планете”

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

    Вообще изучать тему работы уже с имеющимися “своими тараканами” - довольно интересно. Попробую изложить что уже увидел и приглашаю к дискуссии в комментариях. Сразу скажу - у меня пока только первый опыт работы в местной компании, поэтому генерализировать его на всю Австралию не стоит, все высказываемые точки зрения - очень субъективные :)

    Kloud Solutions

    Как я уже писал - я теперь работаю в Kloud Solutions, в роли Development Consultant ( консультант по разработке или консультант-разработчик, не знаю как перевести точнее). В отличии от свободной формы одежды в ABBYY, тут приходится одевать рубашку и формальные брюки (не джинсы). Вообще, как мне сказали, форма зависит от клиента - если у клиента в офисе свободный стиль - можешь ходить как нравится (даже могут попросить одеваться более неформально чтобы не сильно выделяться ;) ), если же у клиента формальный дресс-код - надо соответствовать.

    Кто такие Development Consultant (да и вообще Consultant в мире программирования Австралии). До приезда сюда у меня было устойчивое мнение что консультанты в мире программирования - “морские свинки”. Т.е. обычно это некий salesman, продающий IT-решения или IT услуги. В принципе то, что я видел и слышал в России - так и было. Руками консультанты ничего, относящегося к программированию, делать не умеют, надевают пинжаки-галстуки и вперед, впаривать “высокие нанотехнологии” с использованием заученных фраз и зная куда щелкать мышкой в их продукте. В Австралии ситуация полностью обратная - IT-консультанты это нанимаемые на проект программисты\администраторы (последние тут Infrastructure Consultant). Судя по тому, что я уже видел и слышал - это очень высококвалифицированные программисты. Связано это с тем, что компании предоставляющие такие услугу - стараются нарабатывать и поддерживать репутацию и поэтому у них предусмотрены всякие программы повышения квалификации и поощрения развития, ну и всякие сертификации от Microsoft. С одной стороны партнеры Microsoft таким образом поддерживают свой уровень партнерства, с другой - так куда легче получать проекты, ибо репутация тут имеет вполне ощутимую ценность - очень много построено на репутации. В общем мы, консультанты, тут не лапшу вешаем, а продолжаем усиленно работать руками. Что в общем - интересно и полезно.

    Итак все же вернемся к теме о работе:

    Во-первых - довольно устойчивое ощущение свободы и независимости. Начиная с отношения работодателя (даже писать “работодатель” как-то уже не комфортно, я бы сказал - заинтересованная организация…) - к тебе относятся как к специалисту, притом довольно высокооплачиваемому. Т.е. нет такого, что “я-начальник, ты -дурак, иди работай что скажу”, а как к равному, к эксперту продающему свое время (и задорого). И все в общем прекрасно понимают две простых вещи - вхолостую эксперт простаивать не должен, ибо это потерянные деньги, и вторая - раз уж ты купил эту экспертизу - пользуйся и доверяй, а не ставь под вопросы все его решения. Ну и очевидная третья - консультант знает свою цену и востребованность на рынке, поэтому не боится остаться без работы. Это создает очень приятные (и тешащие самолюбие) условия работы, по крайней мере в связке консультант-компания.

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

    Проекты в большинстве своем довольно короткие (т.к. наемная сила недешевая) и вовсю практикуется Scrum, Agile и прочие страшные слова. Итерации разработки - тоже очевидно короткие, все интенсивно и без рассусоливания на 2-3 недели. Это приятно. Но вот недостаток такого подхода тоже налицо - т.к. проект в итоге строится из маленьких историй-кирпичиков, получается что для того чтобы сделать историю в срок - в ход идет копипаста, без детального продумывания переиспользования кода. В результате - какая-то стройная архитектура не наблюдается и много мест не самых оптимальных и дублирующегося кода. Поэтому все знакомы с clean-up week, когда за неделю-другую, все пытаются судорожно исправить…

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

    Помимо интересных greeen field проектов есть тут еще т.н. Brown field. Это все тот же Legacy проект, который когда-то начинался как Green а усилиями разнообразных трудяг превратился в черте-что-и-сбоку-бантик. Их тоже кому-то приходится поддерживать. А т.к. репутация у определенных компаний тут довольно устойчивая + деньги платят за работу, консультантов нанимают в том числе и разбирать такие “завалы”. Задорого, но и очень срочно. Т.е. вот уже сроки сдачи проекта прошли, всё в авральном режиме и тут в светлую голову ударяет светлая жидкость с убеждением, что “если мы наймем очень крутых ребят, то они за 2 месяца тут все поправят и еще по ходу дела одной левой нашу команду научат нормально работать”. Всякие “Мифические человекомесяцы” тут, как и везде, читают в основном программисты, а не руководители. Вот и выходит, что помимо крутых проектов кому-то приходится и “почерпать коричневую жидкость”.

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

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

    стыренный слон

     
  10. Записки далекого марсохода From Down Under. Часть 2.

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

    Я периодически стараюсь выбираться пешком погулять по разным районам (хотя по площади тут просто огромные пространства…), посмотреть на спальные районы, на чистоту, инфраструктуру. В целом из того что видел - впечатления довольно положительные. Огромное количество зелени. И не просто молодых, высаженных на 2-3 года деревьев, а именно взрослые, крупные деревья, с густой кроной. Этим мне Мельбурн очень напоминает зеленый Луганск, где я в детстве проводил много времени - большое, просто огромное количество зелени, в том числе и в самом центре (тут это называется City\CBD), довольно широкие улицы, много пространства и свежего воздуха “по сравнению с”.

    Green City

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

    улица спального района

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

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

    С курением все не так радужно как мне показалось в первый приезд. Конечно все не так трагично как в Москве, но курящие люди встречаются регулярно. Зато все пачки сигарет у них одинаково черные и со всякими “веселыми картинками” - рак языка, легких, импотенция и прочие любимые друзья заядлого курильщика :) .Так что сами-себе-злобные-буратины есть повсюду, это в общем не удивительно, хотя я так надеялся…

    Kloud Solutions, my new employer

    Ну и к веселой новости, про работу. Работу я нашел (несмотря на все затруднения в виде требования местного опыты и сильного снижения найма с середины декабря), уже получил официальный job offer и подписал его. В общем буду работать в довольно веселой “облачной” компании Kloud Solutions, на должности Development Consultant. Изначально просили выйти на работу 29 января, что было очень удобно - в планы на январь сразу нарисовались в неспешном режиме подыскать жилье, выбрать пенсионный фонд, разобраться с ноутбуком (консультанты тут ходят со своими ноутами, ибо работа подразумевается мобильная), дождаться TFN (чтобы налоги не списывались в размере 50% от зп, а было как у всех нормальных людей). Ну и слетать в Gold Coast, повидаться с товарищем.

    Но “внезапно”, за час до подписания контракта, меня “обрадовали” новостью, что было бы очень здорово если бы я смог выйти пораньше. Ну пораньше, так пораньше, не вопрос. Раньше начнешь - быстрее к… эмм, это не сюда, читают и дети :). В итоге 7 января на работу, 14 уже на территорию клиента. И все планы естественно уплотнились - срочно искать жилье, придумывать как его обставить, ибо въезжаешь тут по сути в пустую квартиру-дом - только шкафы встроенные и кухня. А учитывая что районов тут огромное множество и надо внимательно почитать отзывы про них и понять - какой подойдет, а в какой не стоит и соваться - задачка становится веселее некуда. Еще эти праздники - все же разъедутся, до 11 января точно не успею снять ничего :(. Ладно, прорвемся, где только наша не пропадала…

     
  11. Маленькие скриптхаки: Запуск Powershell в Unrestricted режиме из командной строки

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

    Все оказалось довольно просто но как обычно не задокументировано в явном месте. Нужно в cmd вызвать powershell вот с такими параметрами (все в одну строчку, ключевой -ExecutionPolicy Unrestricted, остальные просто полезные ):

    %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe 
    -NonInteractive -ImportSystemModules -NoProfile 
    -ExecutionPolicy Unrestricted 
     -File "C:\SomePowershellScript.ps1"  >> C:\PowershellScript.Log.txt 2>&1
    
     
  12. 21:34

    Notes: 1

    Tags: australialifetravel

    Записки далекого марсохода From Down Under. Часть 1

    Всем привет.

    Меня тут по-доброму почти назвали “марсоходом который делает фотографии только для самого себя и не делится”. Меня это очень повеселило поэтому вторая попытка рассказать про Мельбурн будет происходить под заглавием “Записки далекого марсохода”.

    Для начала - shameless plug - летайте самолетами Emirates. Emirates

    В этот раз мне не хотелось лететь через Лондон с двумя пересадками и я полетел через Дубаи. Великолепные самолеты, и Боинг до Дубаи и уже ставший привычным A-380 до Мельбурна. Расстояние между креслами - явно увеличенное (не то что British Airways), есть электронная регистрация на рейс (правда меня в итоге пересадили с моего места на одном из рейсов, потому что одна семья попросилась сидеть вместе, но в общем дали место не хуже), usb зарядка и куча всяких других плюшек. Прекрасно обученный персонал - очень дружественные стюардессы в отличающейся униформе, вкусная еда, но то что меня просто подкупило - металлические приборы для еды. Да-да, вилка, ложка и нож (TSA наверное от одной мысли об этом седеют до волос на спине - полный самолет пассажиров с металлическими ножами :) ), качественые и стальные, а не обычный пласстмассовый трэш, которым вареные овощи невозможно разрезать. И что-то никто не боится что вот террористы возьмут и с этими вилками наперевес захватят самолет. Кстати что еще удивило - было объявление что стюардессы говорят на нескольких языках, включая русский. И это в общем-то на рейсе из Дубаи - довольно неожиданно В общем респект и уважуха Emirates за такой уровень сервиса и перелет. Правда я чуть не проспал стыковку в Дубаи, будильник звенел раза три, ну и топать пришлось через весь аэропорт - внутренняя интуиция нашла самое удаленное от гейта место отдыха =). В общем дальше все стандартно, посадка, такси, незнакомое место обитания с миниатюрной хозяйкой дома. Марсоход добрался успешно и легко. Начал осваиваться.

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

    Погода в Мельбурне действительно, как говорят - “4 сезона в один день”. В майский приезд мы ее не застали такую потому что было всегда довольно прохладно. А вот лето - все расставило по своим местам… Например, сегодня я два раза попал под легкий дождь и раза три пожалел что не взял головной убор, потому что ощутимо припекало. И стандартно - сильный ветер который может мгновенно затихнуть и солнце начнет жарить. В общем не соскучишься :) 4 seasons in one day

    Документы и всякие необходимые вещи оформляются довольно просто - или через интернет или при лично явке - без особых очередей (ну или электронные очереди идущие очень быстро. Все очень подробно разъясняют, если надо напишут, расскажут 2-3 раза, главное чтобы до тебя дошло. Да и вообще - все стараются помочь, и это довольно заразительно - сам стараешься тоже помогать, участвовать в местной жизни - будь то пятничная тусовка в кафе или воскресное барбекю.

    Что исключительно здорово - здесь на всех уровнях ведется пропаганда здорового образа жизни и укрепления локальный community. Т.е. как у нас на всех продуктах наклеено - “без ГМО”, так и тут - очень популяризуются продукты organic, gluten free и т.д. Возможно часть из этого - рекламные трюки ( потому как продаются такие товары с некоторой наценкой) но в общем - organic это местный популяризуемый тренд. Ну и продукты совершенно другие по качеству. Я вот начал активно употреблять местное обезжиренное молоко, вместе с хлопьями на завтрак. Кто меня знает - тот осведомлен, что на протяжении всей свой жизни я переношу молоко исключительно как добавку в кофе. Ну и кефир. А тут оно вкусное. А вот кефира я пока не нашел. Говорят что самое близкое к нашему кефиру - это butter milk. Правда тоже пока еще не нашел. Молочных продуктов тут много и возможно просто не замечал то, что искал. И главное - я нашел тут хумус. Довольно похожий на то, чем нас кормили друзья в Израиле. Так что жизнь определенно удалась :D. Ну и вода - она тут чистая и мягкая - можно пить из-под крана и в чайнике нету накипи. Вообще нету. Мне это даже непривычно после Мск :)

    Eat organic

    Ну и естественно, экология - уникальная экосистема, карантин, раздельный сбор мусора, быть eco-friendly это тоже хорошо и довольно часто встречающаяся жизненная позиция. Пропаганда велосипедов вместо личных автомобилей идет полным ходом: начиная с цены за бензин в 1.5 доллара за литр ( это где-то около 45-50 рублей), заканчивая shared машинами (flexicar.com.au - типа можно по клубной подписке взять машину на час. И не очень дорого и выглядит довольно логично - не надо иметь свою машину, можешь взять shared и съездить куда надо. Помимо этого - огромное количество выделенных велодорожек в том числе и на шоссе, куча стоянок, в центре есть rent a bike - типа взять на прокат и от одного rent-a-bike доехать до другого ( и там оставить). Единственное чем это не удобно - шлем. Без шлема ездить запрещено поэтому к rent-a-bike надо ходить со “своим самоваром”. Что выглядит немного нелогично т.к. Например туристам этим сервисом не попользоваться (ну вряд ли кто таскает с собой шлем от велосипеда на прогулке), а у местных в большинстве - свои велосипеды.

    Помимо вкусной еды и экологии, здесь везде пропагандируется укрепление локальной community - типа дружите с соседями, покупайте местное, ну или хотя бы австралийское. Тут вообще довольно сильный тренд на создание местных коммун - соседи-друзья, обычно друг друга знают, вместе тусуются, общаются, барбекю разные, рождество. Дети играют вместе, например тут наблюдал довольно большое празднование ДР в парке напротив дома - примерно 20 детей, куча родителей, всякая развлекательная программа. В общем локально тут очень тесно связанные и общающиеся группы людей. И это имхо тоже очень правильно и хорошо. Люди обрастают связями и корнями, не чувствуют себя чужими в стране (учитывая что тут очень много иммигрантов вообще) - это важно и очень приятно.

    Из того что не очень нравится - с одной стороны все такие зеленые, экологию берегут, с другой стороны - дома особо не утепляют. Под входной дверью (входишь сразу в зал\гостинную а не в аналог нашего коридора) - щель в палец толщиной, окна - чисто для вида, тоже везде щели и сквозняки. Я конечно понимаю что тут широта кипра-сочи, но зимой то дубак будет, особенно в мельбурне. Да и летом тут не жарко - везде гуляют сквозняки и в доме холодно. Более-менее тепло становится когда на улице +35 и в общем тепло можно запустить с улицы. Та же самая ситуация с сантехникой… Я конечно понимаю мб это некая викторианская классика - краны неподвижные ( хорошо хоть не раздельные горячая-холодная) и душ в кабинке без шланга, просто вмурован в стену. Но епрст - это же так неудобно, ни мыться - дольше времени тратишь на смывание мыла, ни убирать - неудобно смывать со стенок кабинки или раковины т.к. Душ\кран стационарные. Получается что расход, по сути, повышается из-за неудобства использования.

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

     
  13. Маленькие, но полезные макросы для Visual Studio

    Подумал и решил опубликовать 2 простых макроса для Visual Studio, которые тем не менее сильно облегчают мне жизнь.

    Очень часто при падении Visual Studio (версий 2005 2008 2010) портятся настройки этой самой студии. А именно - файл CurrentSettings.vssettings. Как они умудрились это не поправить на протяжении стольких выпусков - я не знаю, но т.к. это все еще происходит - я написал себе 2 макроса чтобы последствия таких падений можно было легко устранять. Итак, о чем эти макросы:

    • SaveCurrentSettings экспортирует настройки Visual Studio в переданный файл.
    • RestoreCurrentSettings импортирует в Visual Studio настройки из переданного файла.

    Есть маленький нюанс - это все дело не работает если в имени файла, в переменной_settingsFilePath, есть пробелы. То ли движок макросов глючит, то ли надо как-то хитро кодировать пробелы в VB - я не разобрался, хотя пытался это расковырять несколько раз (правда, без особого энтузиазма).

    Как это использовать - скопируйте нижеприведенный код в ваш macro проект в студии (ALT+F11 для вызова Macro IDE). Исправьте путь к файлу где будут лежать сохраненные настройки (“memento про пробелы!”) и собственно все. Теперь можно повесить выполнение конкретных макросов на горячие клавиши или в виде кнопок вывести на панель инструментов (мне такой вариант понравился больше)

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

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

    Т.к. в новой 2012 студии поддержки макросов уже не будет - надеюсь MS все-таки поправит все проблемы с потерей настроек при падении и тогда эти маленькие полезняшки будут уже не так нужны.

    Хотя лично мне нравилось использовать такие же макросы и для быстрого переключения конфигураций: когда дома был 1 монитор, а на работе 2 - студия, размазанная на 2 монитора, при заходе терминалом смешивала все свои окна в кучу и приходилось по 10 минут только перемещать и ресайзить окна, чтобы настроить рабочий инструмент. С этими макросами я просто сделал 2 конфига и переключался между 1 и 2х мониторными конфигурациями.

    Сами макросы вот.

    PS: Там еще внизу затесался макрос для включения выключения Resharper, таким способом удобно его прибивать если начинает сильно тормозить. Ну вдруг кому будет тоже полезен (хотя он официально задокументирован в доке решарпера, в исходном виде он у меня не заработал…)

    Imports System
    Imports EnvDTE
    Imports EnvDTE80
    Imports EnvDTE90
    Imports EnvDTE90a
    Imports EnvDTE100
    Imports System.Diagnostics
    
    Public Module SupportHacks
    
        Private _settingsFilePath As String = "D:\Projects\VS2010\CurrentSettings.Exported.vssettings"
    
        Public Sub RestoreCurrentSettings()
            DTE.ExecuteCommand("Tools.ImportandExportSettings", "-import:" + _settingsFilePath)
        End Sub
    
        Public Sub SaveCurrentSettings()
            DTE.ExecuteCommand("Tools.ImportandExportSettings", "-export:" + _settingsFilePath)
        End Sub
    
        Sub Resharper_ToggleSuspendedMacro()
            DTE.ExecuteCommand("Resharper_ToggleSuspended")
        End Sub
    
    End Module
    
     
  14. Прогресс и интеграция в офисных и вне-офисных коммуникациях

    До чего дошел прогресс… Вот с утра не удается затерминалиться на работу. Подумал - в очередной раз моя машинка повисла. Надо бы попросить коллег ее перезагрузить.

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

    Помимо того, что сам Web-mail уже стал довольно удобным (насколько вообще может быть удобен Outlook, помещенный внутрь браузера), так и коммуникатор это какой-то отдельный праздник жизни: можно вести активное (мгновенное, что ощутимо) общение, видны изменяющиеся статусы людей, подтянуты мои собственные группы контактов из Lync, ведется счетчик активных бесед и входящее сообщение легко порождает новые pop-up'ы. Не говоря уже про полную адресную книгу из AD. 

    И все это счастье без перезагрузки страницы, всяких традиционных подмигиваний экрана и пр. В совсем не дружественном к MS браузере на букву G. Это праздник онлайн-общения с офисом через веб-сайт. А главное - такой доступ удивительно удобен ( имхо, у Gmail не так удобно чатиться…) и с очень отзывчивым интерфейсом - скорость реакции на любые действия всерьез удивляет.

    И вот пока терминальный доступ восстанавливался (как оказалось, что проблемы с доступом не по вине моей машины) я поймал себя на мысли - Skype я запускаю редко, только когда сам звоню, ICQ\MSN\Jabber вообще забыл когда запускал последний раз. Остальные коммуникации - рабочий телефон тоже не использую, если срочно - звоню с мобилы, остальные обращения - или онлайн или асинхронно в виде почты\twitter\facebook.

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

    И в итоге я поймал себя на том, что вот такая “всё-интеграция” - удобна. Насколько она безопасна - это второй вопрос, которым, кстати, буквально недавно задался в связи с новостью об интеграции скайпа в MS Office. Но все равно - очень удобна, даже вопреки безопасности ;).

    И в связи с этим хочу спросить - а какие способы общения удобны и неудобны для вас ? Нравится ли вам такая всеобщая интеграция ? И главное - какие средства общения у вас раньше были популярны, а потом - просто отмерли ?

     
  15. Twitter 101.

    Решил составить краткое пособие для начинающих пользоваться твиттером. Я понимаю что почти КО, но для быстрого старта - должно помочь:

    • tweets \ твиты - короткие сообщения, основа общения в твиттере :). Ограничение одного твита на длину - 140 символов. Если ваше сообщение не помещается в эту длину - можно написать его в 2-3 твита, при этом хорошей практикой считается в конце каждого “оборванного” твита ставить что-то типа continued / ctd, как индикатор того, что “мысль еще не кончилась”.

    • follow \ фолловить кого-либо - следовать за твитами конкретного человека. Для того чтобы зафолловить кого-то - надо зайти в его твиттер, например в мой ;) https://twitter.com/centur, и нажать кнопку “Follow”. После этого действия, все общие твиты этого человека попадают в вашу основную ленту. По сути - подписка на твиты конкретного аккаунта. При этом человек получит уведомление, что у него появился новый фолловер.

    • unfollow \ расфолловить - отписаться от твиттов конкретного аккаунта - то же самое как фолловить - зайти в аккаунт и нажать Unfollow.

    • re-tweets \ ретвиты - повторение какого-то твита для своих фолловеров. Обычно это делается одной кнопкой в интерфейсе, то твиттер дописывает к тексту сочетание RT, а у исходного твита появляется упоминание что его ретвитнул такой-то аккаунт. Если вы заметно отредактируете текст ретвита, то даже несмотря на RT, данные о ретвите к тому твиту не привяжутся. Такое действие часто называется quote\процитировать твит.

    • mentions \ упоминания - способ указать в твите другой твиттер-аккаунт, делается добавлением в твит текста @имяаккаунта, т.е. чтобы упомянуть соседа Мишу, надо написать что-то типа А мы с соседом @Misha едем в Яхонты. При этом @Misha получит уведомление - вас упоминают в твите и сможет посмотреть ваш твит на странице Connect\Mentions в интерфейсе сайта

    • direct message \ директы - личные сообщения. Чтобы послать личное сообщение - надо набрать d <получатель>, например d AbbyyTeam давайте замутим секретную шутку. Это сообщение увидит только один получатель, @AbbyyTeam. К сожалению сам интерфейс твиттера не очень удобен для чтения таких сообщений, они прячутся за иконкой человечка, рядом с голубой кнопкой “new tweet”. Так что использовать это надо осторожно - бывает что директы не читаются неделями =). Но большинство мобильных клиентов эту проблему обычно решают лучше и директами можно активно и главное приватно чатиться вместо смс ;). Важное НО: отправить такое сообщение вы можете только если вы сами фолловите человека И он тоже фолловит вас.

    • hashtag \ хэштеги - специальные слова, начинающиеся с # - по ним легко искать ВСЕ публичные твиты любых аккаунтов. Часто используются как индикатор какого-то события, например #ABBYY_Yahonty позволяет следить только за упоминаниями #ABBYY_Yahonty в твиттере

    Что еще существенно - твиттер в большинстве своем - довольно публичная штука, тут можно посмотреть чужие диалоги ( если только они не через direct message), посмотреть всех фолловеров любого аккаунта, посмотреть кого фолловит этот аккаунт, влезть в диалог 2х человек, просто поспамить кого-то, упоминая его по поводу или без (твиты из серии “Привет @Misha, это о тебе пишут ?”).

    Так что если вы хотите супер-приватности - делате ваш твиттер непубличным ( очень не интересно) и разрешайте читать его только тем, кому явно доверяете. А еще проще - не пользуйтесь твиттером, он совсем неудобен для приватности. Это такая вселенская “курилка-болталка” - странно ожидать от нее сохранения тайн и секретов ваших сообщений.

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

    Вот наверное и все основные концепции которые нужны для комфортного пользования твиттером. Еще есть lists \ “списки” , но это уже для активных твиттерян, желающих упорядочить ленту и разделить “потоки” твитов по категориям.

    Если есть какие-либо фундаментальные вопросы, которые я забыл или не рассмотрел - пишите в твиттер @centur

    Edit1: поправил инфо о том, что для direct message знак @ не нужен. Creds to kuznetsov_va. Работает кстати и с ним, но позволяет сэкономить 1 букву. Дописал о том, что ограничение одного твита - 140 символов