Итоги 2014 года и планы на будущее
2014 год для меня выдался очень бурным. В апреле я покинул компанию АйТеко, где работал менеджером по развитию бизнеса, а до этого архитектором решений. За время работы в АйТеко я приобрёл огромный опыт продажи и создания бизнес-решений, разобрался как работает крупный бизнес (в основном банки и телеком) и понял как можно помогать им делать работу более эффективно.
После айтеко я еще несколько месяцев работал part-time архитектором, параллельно развивая свой бизнес. С июля я работаю исключительно на себя и безмерно этому рад.
Последние три месяца 2014 года выдались очень “горячими”, было много проектов и все хотелось закрыть до нового года, чтобы в 2015 войти без хвостов и с кучей денег. К счастью мне это удалось, но пришлось отодвинуть на второй план блогинг и другие активности. Зато удалось заработать в два раза больше, чем я зарабатывал, работая в интеграторе.
Рынок в 2014-2015 году
Еще с начала 2014 года была очевидна тенденция снижения размеров проектов. Мало кто заказывал типичные корпоративные порталы с длинными циклами планирования и внедрения, все хотели быстро получить результат . В 2015 году эта тенденция усилится из-за экономического кризиса.
С другой стороны появилась тенденция повышения спроса на автоматизацию с целью снижения издержек со стороны бизнеса. Очень много появилось заказов на системы анализа и управления персоналом, а также системы автоматизации бизнес-процессов с упором на снижение издержек. Но, скорее всего, из-за кризиса такой ажиотажный спрос пойдет на спад.
В 2015 году для тех, кто занимается разработкой и внедрением, самым важным будет вопрос повышения эффективности свой деятельности. Нужно повышать ценность решений и скорость внедрений. А достигнуть этого можно только использованием новых методов и обучением разработчиков.
Развертывание ферм SharePoint
Как ни странно самая высокая маржа получилась на развертывании ферм SharePoint. На практике спланировать и развернуть развернуть ферму SharePoint 2013 очень непросто. Встроенный configuration wizard делает от силы треть необходимых настроек, а развертывание на несколько серверов требует недели работы.
Используя правильные инструменты мне удалось разворачивать многосерверные фермы буквально за один день, а развертывание тестовых и разработческих сред вообще можно выполнить за несколько часов. В итоге я заработал на развертывании SharePoint более 200,000 рублей, потратив суммарно около 5 дней работы.
В начале февраля я планирую провести тренинг на эту тему, где слушатели сами будут планировать и разворачивать фермы в очень сжатые сроки. На днях опубликую анонс.
PowerPivot и PowerView
Год назад я начал использовать PowerPivot и PowerView в SharePoint как инструмент разработки решений и это дало просто потрясающий эффект. PowerPivot помог реализовать решения, которые обрабатывают сотни тысяч элементов списков, не написав при этом ни единой строчки серверного кода SharePoint, а PowerView позволил делать отчеты за считанные минуты. Рукопашная реализация всех расчетов заняла бы несколько недель чистого времени на разработку и пару месяцев на отладку и внедрение.
Этими знаниями и навыками я тоже хочу поделиться с вами и буду проводить тренинг на эту тему в середине февраля.
Сообщество
В прошлом году был перезапущена юзер-группа по SharePoint и родилось фактически два формата мероприятий – встречи для разработчиков и инженеров, с короткими докладами для желающих и бизнес-ориентированные мероприятия с упором на передовые (читай облачные) продукты и технологии Microsoft. Я планирую и в этом году провести несколько подобных мероприятий.
Кстати для тех, кто дочитал до сюда, бонус – записи с декабрьской встречи юзер-группы - http://www.youtube.com/playlist?list=PLfB6mTkgdUsILmayFAM41h0Wr8YQyE7ma
В онлайн-сообществе на facebook количество участников подбирается к 500, надеюсь и дальше будет расти, пополняясь интересным контентом.
Мне нужен партнер
Количество активностей, которыми я занимаюсь и собираюсь заниматься уже приближается к пределу моих возможностей, даже аутсорсинг части работ не сильно помогает снизить нагрузку. Поэтому я ищу человека, который поможет мне развивать бизнес.
Мне не нужен просто сотрудник, который будет “кодить по ТЗ за зарплату”, я ищу именно партнера, который будет получать часть прибыли, помогать с поиском клиентов, продажей проектов и проведении тренингов. Я ищу человека, который сам хотел бы заниматься бизнесом, готов рисковать и брать на себя ответственность, настроен постоянно развиваться, и будет “крутиться”, чтобы зарабатывать больше.
Если вам интересно работать в таком режиме - пишите.
Мне нужен специалист по SharePoint, с навыками программирования C#, JavaScript и PowerShell, готовый изучать другие языки и технологии, например Microsoft Dynamics, BizTalk и даже 1C, а в дальнейшем сможет развиваться как менеджер.
Подборка материалов о серверной оптимизации ASP.NET
Серия постов о кешировании на хабре:
- Стратегия кеширования
- Как прикрутить кеширование к ASP.NET приложению
- Применение инфраструктуры кеширования ASP.NET
- Интеграция кеша ASP.NET с Redis и зависимости кеша от БД
Какие темы вам еще будут интересны?
7 способов улучшить поля в формах SharePoint 2013
Кастомизация форм – очень больная тема в SharePoint. InfoPath фактически умер, новые способы кастомизации появятся не раньше следующего релиза (назначенного на конец 2015 года), а для использования SPServices нужен jQuery старой версии, что само по себе несет проблемы, так еще и требует знания отображаемых имен полей, что делает решение ненадежным. Подробнее в моем курсе по клиентской разработке SharePoint.
Создавая TypeScript-определения для клиентской библиотеки SharePoint сделал несколько примеров полей. Недавно я провел большой рефакторинг и выделил кастомные поля в отдельные, повторно используемые функции.
Все функции содержатся в файле typescripttemplaes.ts. Тем, кто не пользуется TypeScript (зря!), можно скачать .js файл в том же каталоге.
Как пользоваться typescripttemplates:
- Скачать файл и добавить .js в проект
- Сделать свой файл скрипта для полей, такого вида:
module _ { function init() { CSR.override() .lookupAddNew("Master", "Add New Master item", true) .register(); } SP.SOD.executeOrDelayUntilScriptLoaded(init, "typescripttemplates.ts"); SP.SOD.executeOrDelayUntilScriptLoaded(function () { RegisterModuleInit(SPClientTemplates.Utility.ReplaceUrlTokens("~site/YOUR_SCRIPT_PATH.js"), init); }, "sp.js"); }
- Вписать адрес скрипта в ReplaceUrlTokens и вызовы функций между .override() и .register()
- В атрибут JSLink поля\формы\типа контента вписать строку такого вида: “~site/PATH/typescripttemplates.js|~site/YOUR_SCRIPT_PATH.js”.
Итак сами функции:
№1 Установка начального значения поля в формах
CSR.override() .setInitialValue("FieldInternalName", ANY_VALUE) .register();
Пригодится когда значения полей передаются в Url или через локальный кеш. Значение нужно передавать во внутреннем формате, который использует CSR.
№2 Скрытие поля
CSR.override() .makeHidden("FieldInternalName") .register();
Скрывает поле на форме, в представлении, и даже в режиме редактирования таблицы.
№3 Установка поля в Read-Only в формах
CSR.override() .makeReadOnly("FieldInternalName") .register();
Заменяет контрол ввода на контрол отображения. Пока не работает в для поля выбора пользователя.
№4 Вычисляемое значение поля
CSR.override() .computedValue("Title", function(x) {return SPClientTemplates.Utility.ParseLookupValue(x).LookupValue; }, "SOME_LOOKUP_FIELD") .register();
Автоматически задает значение поля при изменении в связанном поле.
№5 Добавление ссылки на добавление нового элемента в Lookup
CSR.override() .lookupAddNew("Master", "Add New Master item", true) .register();
Добавляет рядом с Lookup-полем ссылку, которая открывает форму добавления в связанный список. Последний параметр задает открывать ли форму в диалоге или переходом на страницу формы
№6 Фильтрация Lookup
CSR.override() .filteredLookup("Master", '<BeginsWith><FieldRef Name ="Title" /><Value Type = "Text" >{Title}</Value></BeginsWith>') .register();
Вместо статического списка выбора связанного значения делает динамический запрос с помощью предиката. В предикат также можно указать ссылки на другие поля.
№7 Lookup на основе поиска
CSR.override() .seachLookup("LookupFieldInternalName") .register();
Заменяет стандартный элемент выбора на компонент autofill, входящий в SharePoint. Для получения связанных элементов используется поиск. Будет работать даже для очень больших списков. В ближайшее время будет добавлена возможность указывать запрос, который выполняется при получении элементов.
Для этого поля надо в JSLink добавить ссылки на файлы autofill.js и sp.search.js – “~site/PATH/typescripttemplates.js|~site/YOUR_SCRIPT_PATH.js|autofill.js(d)|sp.search.js(d)”
Заключение
Качайте, пользуйтесь, пишите фидбек здесь и на сайте проекта - http://sptypescript.codeplex.com/workitem/list/basic. Кроме указанных выше готовых контролов, есть еще куча хелперов, которые вам помогут делать свои шаблоны полей.
Если хелперы будут популярны, то я выложу библиотеку в NuGet.
Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server с помощью LINQ
К сожалению, как обычно я не показал все что хотел, часть материала не попала на видео запись. Но я восполню этот недостаток.
Как вы думаете, можно ли на Linq делать запросы, которые работают быстрее рукопашных? Оказывается да, и очень просто.
Например надо сделать функцию, которая отбирает заказы по дате отгрузки. Если параметр указал, то выбрать заказы за эту дату. А если не указана дата, то выбрать все заказы, у которых дата отгрузки пустая. Обычный разработчик напишет такую процедуру:
CREATE PROCEDURE [dbo].[GetTransactionsByShipDate] @shipDate datetime AS SELECT t.Id, t.ProductId, t.TransactionDate from Transactions t where (@shipDate is not null and t.ShippedDate = @shipDate) or (@shipDate is null and t.ShippedDate is null)Эта процедура подвержена parameter sniffing problem. Проблема заключается в том, что план процедуры генерируется один раз при первом вызове с учетом фактических параметров при вызове. Если при первом вызове ShipDate был NULL (низкая селективность), то сгенерируется план с Index Scan. Если же первый вызов был с конкретным значением даты, то получится Index Seek, который будет неэффективно работать для значений с низкой селективностью.
Простой тест:
DBCC FREEPROCCACHE GO EXEC [dbo].[GetTransactionsByShipDate] NULL GO declare @shipdate datetime = getdate() EXEC [dbo].[GetTransactionsByShipDate] @shipdate GO DBCC FREEPROCCACHE GO declare @shipdate datetime = getdate() EXEC [dbo].[GetTransactionsByShipDate] @shipdate GO EXEC [dbo].[GetTransactionsByShipDate] NULL GOРезультаты:

Как видите план оказывается далеко не оптимальным в обоих случаях.
А с помощью Linq можно написать так:
private static IQueryable<Transaction> GetValues( IQueryable<Transaction> query, DateTime? dateTime) { if (dateTime.HasValue) { return query.Where(t => t.ShippedDate == dateTime.Value); } else { return query.Where(t => t.ShippedDate == null); } }Тогда буду сгенерированы два разных запроса, каждый со своим, оптимальным для данного запроса, планом.
Более того, такая оптимизация для null value встроена в провайдер Linq2DB. Там можно непосредственно nullable значения подставлять в linq.
Более того, можно использовать filtered index, когда больше 2% значений по индексируемому полю равны NULL.
Записи докладов по Business Intelligence c DevCon 2014
Недавно были опубликованы видеозаписи. Выложу их в блоге, чтобы проще было найти.
Первый доклад по Power Pivot в SharePoint 2013 (on-premises), в котором я показываю пример мини-erp решения для управленя отделом, которое можно собрать за несколько часов совершенно без программирования.
Второй доклад посвящен возможностям PowerBI в Office 365. Особое внимание было уделено инструменту Power Query, его использованию в Excel, а также настройке гибридной среды для получения доступа из облака к данным on-premises.
А вы используете в своей работы BI инструменты SharePoint? Напишите в комментах в каких сценариях применяли или почему не применяли.