четверг, 29 июня 2017 г.

Рефакторинг говнокода на Observer

Изначальная реализация паттерна проектирования "Наблюдатель" (Observer) для погоды

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
 
namespace lb2
{
 class Program
 {
 public static void Main()
 {
 WeatherData weatherData = new WeatherData();
 CarrentConditionDisplay carrentDisplay = new CarrentConditionDisplay(weatherData);
 //...
 weatherData.setMeasurements(80, 65, 30.4);
 weatherData.setMeasurements(82, 70, 29.2);
 weatherData.setMeasurements(78, 90, 29.2);
 
 Console.Read();
 }
 
 }
 public interface Subject
 {
 public void registerObserver(Observer 0);
 public void removeObserver(Observer 0);
 public void notifyObservers();
 }
 public interface Observer
 {
 public void update(float temp, float hum, float press);
 }
 public interface DisplayElement
 {
 public void display();
 }
 
 public class WeatherData : Subject
 {
// private string SubjectState { get; set; }
 private ArrayList observers;
 
 private float temp;
 private float hum;
 private float pressure;
 
 public WeatherData()
 {
 observers = new ArrayList ();
 }
 public void registerObserver(Observer 0)
 {
 observers.Add(0);
 }
 public  void removeObserver(Observer 0)
 {
 int i = observers.indexOF(0);
 if (i>=0) observers.remove(i);
 }
 public void notifyObservers()
 {
 foreach (Observer obs in Observers)
 Obs.opdate(temp, hum, pressure);
 }
 public  void measurementsChanges()
 {
 notifyObservers();
 }
 public  void SetMeasurements(float temp, float hum, float press);
 {
 this.temp = temp;
 this.hum = hum; 
 this.pressure = press;
 measurementsChanges();
 }
//реализовать другие методы класса
 
public class CarrentConditionDisplay:Observer, DisplayElement
 {
 private float temper;
 private float humid;
 private Subject weatherData;
 
 public CarrentConditionDisplay(Subject wData)
 {
 this.weatherData = wData;
 wData.registerObserver(this);
 }
 
 public void update(float temp, float hum, float press)
 {
 this.temper = temp;
 this.humid = hum;
 Display();
 }
 public void Display()
 {
 System.Console.WriteLine("Текущие условия" + temper + "С и " + humid + "% влажности");
 }
 }
}

вторник, 20 июня 2017 г.

Прощай Codeplex!

Codeplex закрывается. :(

Прошло почти 11 лет с момента создания CodePlex, и теперь настало время сказать "прощай". CodePlex старотовал в 2006 году потому что мы, разработчики, как и все остальные в нашей индустрии, нуждались в хорошей площадке, чтобы делиться софтом.

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

Сейчас отключена возможность создавать на CodePlex новые проекты. В октябре CodePlex заработает в режиме только-чтение, прежде чем окончательно отключится 15 декабря 2017 года.

Подробнее узнать об этом можно здесь

пятница, 14 октября 2016 г.

JavaScript ES5. Пространство имен, наследование, защита от дублирования.

Защита от дублирования скриптов

Следующая функция предотвращает повторную загрузку файла JavaScript

  function scriptLoader(src, callback) {
     "use strict";
      var script = document.querySelector('script[src="'+src+'"]');
      if (script == null) {    
        var head= document.getElementsByTagName('head')[0];
        script= document.createElement('script');
        script.type= 'text/javascript';
        script.src= src;
        script.async = false;
        script.onreadystatechange= function () {
           if (this.readyState == 'complete') callback();
        }
        head.appendChild(script);
      }
      if (script.addEventListener) {
        script.addEventListener("load", callback); 
      } else if (script.attacheEvent) {
        script.addEventListener("onload", callback); 
      } 
  }

Предположим у нас есть следующий скрипт файле alerter.js:

  var Alerter = function() {};
  Alerter.prototype.say = function(smth) { alert(smth); };

Пример использования функции для загрузки alerter.js

  scriptLoader("alerter.js", function() {
    var a = new Alerter();
    a.say("Hi");
  });

  scriptLoader("alerter.js", function() {
    var a = new Alerter();
    a.say("Hi again");
  });

В результате функция выведет в диалоговом окне сначала Hi, затем - Hi again

Функцию можно усовершенствовать, задав на входе массив имен скриптовых файлов.
Также можно модифицировать ее для предотвращения повторной загрузки файлов стилей css.

Предотвращение повторного использования переменных

Для предотвращения повторного использования переменных и ухода от глобального контекста код лучше оборачивать в (function() { //код })();
Например следующий код:

<script>
  var a = 1;
  var v = 2;
</script>

Лучше переписать как:

<script>
(function() {
  var a = 1;
  var v = 2;
})();
</script>

Защита приватных полей

Для защиты приватных полей от внешнего доступа целесообразно использовать конструктор с замыканием. Примерно так:

var MyClass = function() {
  "use strict";
  var _name; // приватная переменная, захватывается функциями getName и setName
  this.getName = function() { return _name}
  this.setName = function(value) {
    _name = value;
  }
 
}

Пример выполнения:

var myObj = new MyClass();
myObj.setName("This is the name");
console.log(myObj.getName()); // Выведет This is the name

Пространство имен

Следующая функция реализует пространство имен из строки, где имена разделены точками. Она возвращает пустой объект

function nameSpace(namespace)
{
  "use strict";
  var parts = namespace.split(".");
  var obj = window;
  for (var i = 0; i < parts.length; ++i) {
    obj[parts[i]] = obj[parts[i]] || {};
    obj = obj[parts[i]];
  };
  return obj;
};

Пример запуска:

   nameSpace("Compsphere.Demo");
   console.log(Compsphere.Demo); //Выводит в консоль Compsphere.Demo

Можно ее использовать и так:

   var obj = nameSpace("Compsphere.Demo");
   obj.NewClass = function() { this.x = "Hi!" }
   console.log((new Compsphere.Demo.NewClass).x); //Выводит в консоль Hi!

Генератор классов с пространством имен

Функцию nameSpace можно модифицировать, превратив ее в генератор классов в некоем пространстве имен.
Вот ее вид:
function createClass(_namespace, _constructor, _prototype) {
  var parts = _namespace.split(".");
  var obj = window;
  for (var i = 0; i < parts.length-1; ++i) {
    obj[parts[i]] = obj[parts[i]] || {};
    obj = obj[parts[i]];
  };

  if (typeof _constructor == "function") {
    obj[parts[i]] = _constructor;
    if (typeof _prototype != "undefined") {
      obj[parts[i]].prototype = _prototype;
    }
  } 
  else {
    obj[parts[i]] = obj[parts[i]] || {};
  }
  return obj[parts[i]];
};

На вход подается пространство имен, функция - конструктор класса и необязательный объект для прототипа. Если конструктор и объект для прототипа не переданы, то createClass отработает аналогично вышеописанной nameSpace. Если не передан только объект для прототипа, то прототип не создастся.

Примеры использования

(function() {
  var myclass = createClass(
    "Compsphere.Demo", 
     function(name) { alert(name) }, 
     {say: function(word) { alert(word); } } 
   ); 

  myclass.prototype.sayAgain = function(word) { alert(word) };
  (new Compsphere.Demo("constructor")).say("Hi");  //Выведет фразу Hi

  var myClassInstance = (new myclass("this is the constructor")); //Выведет фразу this is the constructor
  myClassInstance.say("'say' method"); //Выведет фразу this is the constructor 'say' method
  myClassInstance.sayAgain("'sayAgain' method"); //Выведет фразу 'sayAgain' method
})();

четверг, 28 июля 2016 г.

JavaScript - playing with Canvas. Cellular Automata. Клеточный автомат, играемся с Canvas.

Пример двухмерного клеточного автомата из 6 состояний (0-5) и с начальным состоянием "1" в топ-центре сетки. Каждому состоянию сопоставляется цвет (0 - чёрный, 1 - красный, 2 - синий, 3 - зеленый, 4 - желтый, 5 - белый). В пустой сетке клетки заполняются состоянием "0". Правила переходов (кодовое число) генерируются случайным образом.
Поиграться можно здесь: https://jsfiddle.net/mishau/tja1dpy8/129/

Клеточный автомат

Кодовое число:

пятница, 22 июля 2016 г.

Будущее и настоящее разработки на SharePoint - это чистый JavaScript

Мы занимаемся разработкой на SharePoint для интрасети наших заказчиков и по мере расширения нашей команды, проводим собеседования разработчиков SharePoint developers. В настоящее время, историческому разработчику SharePoint, который работает с C#, ASP.NET, фермерскими решениями, и т.п., приходят на смену разработчики, которые видят SharePoint и Office 365, просто как еще одну платформу JavaScript для веб. Когда мы собеседуем разработчиков SharePoint, мы спрашиваем их об их опыте работы с фреймворками JavaScript, стилями CSS styling, модульным дизайном MVVM и работе с JSOM, REST, и т.п. В данный момент мы нанимаем людей, у которых есть опыт работы с CSS, HTML и фреймворками JavaScript, такими как Knockout JS, Angular, React, и т.п., так как это является видом кастомизации, который мы осуществляем. В последнее время мы не занимаемся активной разработкой на C#, за исключением тех клиентов, которые все еще используют предыдущие версии SharePoint и хотят мигрировать на SharePoint 2016, но сохранив свои существующие фермерские решения, свои рабочие процессы, формы InfoPath, и т.д. Microsoft стимулирует (такой) переход от разработки на серверной стороне к разработке на клиентской стороне уже как несколько лет, начиная с SharePoint 2010 и значительно форсированы с Office 365. Когда Office 365 исключил фермерские решения и серверный код, разработчики перешли на 100% клиентскую разработку с применением JavaScript, HTML, CSS, и т.д. В SharePoint 2016 вы пока еще можете использовать C# или ASP.NET для создания фермерских решений, но главным образом это оставлено для обратной совместимости. Чтобы решение поддерживало, как Office 365, так и SharePoint 2016 рекомендуется использовать кастомизацию только на клиентской стороне.

В выходящем в ближайшее время SharePoint Framework, Microsoft даже еще глубже продвигается в мир JavaScript. Исчезнувшие веб-части / апп-части / и расширения типа контейнеров компонентов IFrame, уступили место встроенным Add-in расширениям JavaScript, которые динамически подключаются к странице. Эти расширения JavaScript могут быть либо развернуты в Office 365, либо загружены из внешней CDN. Фреймворк SharePoint использует 100% кода JavaScript и такие инструменты, как TypeScript, Node.JS, React, JSON, и Gulp для построения кастомизаций. В отличие от текущей модели Add-in, код включается непосредственно в веб-страницу без каких-либо старых контейнеров, базирующихся на IFrame, которые используются в более старых версиях SharePoint.

Если вы являетесь одним из разработчиков SharePoint/C, которые по-прежнему думают, что JavaScript это язык второго сорта, подумайте еще – он должен восприниматься, как первоклассный язык. Microsoft его усиленно продвигает, и разработка на SharePoint, сейчас в основном, является разработкой на клиентской стороне и будет продолжать оставаться таковой в будущем.


Перевод статьи For SharePoint Development, the Future (and Present) is Clearly JavaScript

четверг, 30 июня 2016 г.

Печальное известие

7 июня в Нижнекамске в автокатастрофе в возрасте 34 лет трагически погиб мой бывший коллега по Softline, ближайший сосед в офисе по креслу, руководитель отдела региональных продаж Департамента решений Microsoft Александр Громыко.

Саня всегда был очень веселым парнем.

Буду помнить...

вторник, 19 апреля 2016 г.

Остаток от деления без % в C#. Анализ алгоритмов.

Итак, на собеседовании по C# время от времени попадается задача нахождения остатка от деления (число R) целочисленных положительных чисел M и N без применения оператора %;

Алгоритмы

Первое, что приходит в голову, это следующая формула:

    R = M-M/N*N

Второе, что приходит в голову, это стандартная функция в лоб:

i = 0;
do {
i++;
r = m-n*i;

} while (r>=n)
return n;

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

i = 1;
k = 0;


while (true)
{ r = m - (k + i) * n;

if (r >= 0 && r < n)
{
return r;
}

if (r > 0)
{
i *= 2;
}
else
{
k += (i / 2);
i = 1;
}
}

Исходные коды методов для "стандартного" и "интеллектуального" алгоритмов:

Стандартный
        static int StdReminder(int m, int n)
        {
            if (m < n)
            {
                return m;
            }

            var i = 0;
            var r = 0;
            do 
            {
                i++;
                r = m - i * n;
            } while (r >= n)
            return r;
        }
Интеллектуальный
        static int IntelReminder(int m, int n)
        {

            if (m < n)
            {
                return m;
            }

            var i = 1;
            var k = 0;


            while (true)
            {
                var r = m - (k + i) * n;

                if (r >= 0 && r < n)
                {
                    return r;
                }

                if (r > 0)
                {
                    i *= 2;
                }
                else
                {
                    k += (i / 2);
                    i = 1;
                }
            }

       }

Код для тестирования времени выполнения:

        static void Main(string[] args)
        {
            var rnd = new Random();

            var m = rnd.Next(3, 100000000);
            var n = rnd.Next(1,  19);

            var sw = Stopwatch.StartNew();
            var r = m % n;
            sw.Stop();
            Console.Write("Operator M % N:     ");
            Console.WriteLine(m + " % " + n + " = " + r + "; Time: " + sw.Elapsed.ToString());

            sw = Stopwatch.StartNew();
            r = m - m/n*n;
            sw.Stop();
            Console.Write("Operator M - M/N*N: ");
            Console.WriteLine(m + " % " + n + " = " + r + "; Time: " + sw.Elapsed.ToString());


            sw = Stopwatch.StartNew();
            r = StdReminder(m, n);
            sw.Stop();
            Console.Write("Standard Func:      ");
            Console.WriteLine(m + " % " + n + " = " + r + "; Time: " + sw.Elapsed.ToString());


            sw = Stopwatch.StartNew();
            r = IntelReminder(m, n);
            sw.Stop();
            Console.Write("Intellectual Func:  ");
            Console.WriteLine(m + " % " + n + " = " + r + "; Time: " + sw.Elapsed.ToString());

            Console.ReadKey();
        }

Анализ результатов

Вот, что у меня получилось в консоли

Operator M % N: 17485844 % 13 = 12; Time: 00:00:00.0000009
Operator M - M/N*N: 17485844 % 13 = 12; Time: 00:00:00.0000003
Standard Func: 17485844 % 13 = 12; Time: 00:00:00.0037792
Intellectual Func: 17485844 % 13 = 12; Time: 00:00:00.0001679

Выводы:

- Самым быстрым оказался алгоритм M-M/N*N. Он работает в три раза быстрее, чем стандартный оператор %;
- Самый худший - это "стандартный" алгоритм, он дает существенно большее время, чем все прочие.
- "Интеллектуальный" алгоритм работает примерно в 22 раза быстрее, чем "стандартный" и в 560 раз медленнее, чем формула M - M/N*N.