Pull to refresh
27
0
Тёма Рудневский @timramone

.NET developer

Send message

Как грумить задачу: чек-лист с примерами

Reading time 8 min
Views 11K
Наша разработка постоянно растет, поэтому приходится онбордить по несколько человек в месяц и каждому рассказывать, как правильно грумить задачи. Обучать груму «вручную» больно, потому что это отнимает много времени, какие-то знания теряются по дороге и выскакивают ошибки, которых можно было избежать. Чтобы облегчить жизнь лидам и новичкам, мы собрали чек-лист с описанием этапов грума и примерами. Он будет полезен разработчикам продуктовых компаний, которые онбордят или которых недавно приняли в штат. Чек-лист поможет разбивать задачи на этапы, чтобы ничего не терялось и результат соответствовал ожиданиям.

Все примеры ниже — специфичные и подойдут не каждому, они построены в основном на продуктах Mindbox «Рассылки» и «Программа лояльности». Продукты помогают нашим клиентам запускать автоматические рассылки по триггерам (действиям или событиям), чтобы не спамить пользователей, выдавать промокоды и выстраивать бонусные системы. Если поймете, что чек-лист полезен, можете заменить примеры на свои и использовать.

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

  • цель грума,
  • необходимый минимум,
  • уточнение требований и контекста,
  • типичные этапы,
  • особенности при доработке механик.
Читать дальше →
Total votes 8: ↑4 and ↓4 0
Comments 13

Одних тестов недостаточно, нужна хорошая архитектура

Reading time 11 min
Views 9.2K
Мы все понимаем, что такое автоматические тесты. Мы разрабатываем софт, и хотим, чтобы он решал какие-то проблемы пользователей. Написав тест, мы убеждаемся, что конкретная проблема решается конкретным участком кода. Потом требования изменяются, мы меняем тесты и меняем код соответствующим новым требованиям образом. Но это не всегда спасает. Кроме высокого тестового покрытия наш код должен быть спроектирован таким образом, чтобы защищать разработчика от ошибок ещё при его написании.

В статье я постарался описать одну из проблем, которую может решить хорошая архитектура: связанные участки кода могут разъезжаться между собой, это может приводить к багам, и тесты тут не спасут. А грамотный дизайн может помочь.
Читать дальше →
Total votes 21: ↑20 and ↓1 +19
Comments 24

Трансляция запросов в SQL с использованием LinqToSql в тестах

Reading time 17 min
Views 5.3K
Мы уже несколько лет делаем наш продукт автоматизации маркетинга, и пилить фичи с высокой скоростью нам помогает CI, а точнее — большое количество автоматических тестов.

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

Практически каждая транзакция в нашей системе связана с работой с MS SQL с использованием LinqToSql. Да, технология старенькая, но мигрировать с неё нам довольно сложно, и по бизнесу она нас вполне устраивает. Более того, как я уже писал раньше, у нас даже есть свой форк LinqToSql, где мы чуть-чуть чиним его баги и добавляем кое-какой функциональности.

Для того, чтобы делать запросы к БД, используя LinqToSql, нужно использовать интерфейс IQueryable. В момент получения Enumerator’а или выполнения Execute у QueryProvider’а построенное дерево выражений с помощью Extension-методов к IQueryable транслируется в SQL, который и выполняется на SQL Server.

Так как наша бизнес-логика сильно завязана на сущностях в базе данных, наши тесты много работают с базой данных. Однако в 95% тестов мы не используем реальную базу, так как это очень дорого по времени, а довольствуемся InMemoryDatabase. Она является частью нашей тестовой инфраструктуры, о которой можно написать отдельную статью, и на самом деле представляет из себя просто Dictionary<Type, List> для каждого существующего типа сущности. В тестах наш UnitOfWork прозрачно работает с такой базой, давая доступ к EnumerableQueryable, который просто получить из любого IEnumerable, вызвав у него AsQueryable().

Покажу пример теста для понимания происходящего:
Читать дальше →
Total votes 9: ↑9 and ↓0 +9
Comments 1

Как мы перестали бояться тикетов на UI

Reading time 37 min
Views 18K
Всем привет.
Прошло уже больше года с тех пор, как мы начали использовать ReactJS в разработке. Наконец пришел момент для того, чтобы поделиться тем, насколько счастливее стала наша компания. В статье я собираюсь рассказать о причинах, которые побудили нас использовать эту библиотеку и о том, как мы это делаем.

Зачем всё это


Мы — маленькая компания, наш штат составляет порядка 50 человек, 20 из которых разработчики. Сейчас у нас 4 команды разработки, в каждой из которых сидит по 5 fullstack разработчика. Но одно дело называть себя fullstack-разработчиком, а другое — действительно хорошо разбираться в тонкостях работы SQL Server'а, ASP.NET, разработке на C#, OOP, DDD, знать HTML, CSS, JS и уметь этим всем разумно пользоваться. Конечно каждый разработчик тяготеет к чему-то своему, но все мы, так или иначе, специалисты именно в разработке на .NET и 90% кода мы пишем на C#.
Наш продукт — система автоматизации маркетинга, — подразумевает большой объем настроек для каждого конкретного клиента. Для того, чтобы наши менеджеры могли заниматься настройкой продукта под клиентов, есть административный сайт, в котором можно заводить рассылки, создавать триггеры и другие механики, кастомизировать сервисы и многое другое. Этот административный сайт содержит много различного нетривиального UI'а, и чем более тонкие моменты мы даём настраивать, чем большее количество фич мы выпускаем в продакшн, тем более интересным UI становится.
Читать дальше →
Total votes 27: ↑21 and ↓6 +15
Comments 28

40 ключевых концепций информационных технологий доступно и понятно

Reading time 16 min
Views 159K
Представляю вашему вниманию перевод очень ёмкой, и в то же время достаточно краткой (для такого масштаба проблемы) статьи Карла Чео. Я решил, что очень хочу сделать её перевод практически сразу, как только начал читать, и очень рад, что в итоге сделал это.
Для того, чтобы сделать обучение более веселым и интересным, представляю вам перечень важных теорий и концепций информатики, объяснённых с помощью аналогий с минимальным количеством технических деталей. Это будет похоже на очень быстрый курс информатики для всех с целью просто дать вам общее представление об основных концепциях.

Важные замечания:
  • Пункты с неуказанным источником написаны мной самостоятельно. Поправьте меня, если вы заметите какие-то неточности. Предложите лучшую аналогию, если это возможно.
  • Заголовки ссылаются на соответствующие им статьи в Wikipedia. Пожалуйста, читайте эти статьи для более серьезных и детальных объяснений.
  • Аналогии — отличный способ объяснить материал, но они не идеальны. Если вы хотите по-настоящему понять перечисленные концепции, вам следует начать с фундаментальных азов и рассуждать, исходя из них.

Также зацените эту инфографику (вариант на русском), если вы просто начинающий программист.
Читать дальше →
Total votes 104: ↑96 and ↓8 +88
Comments 37

Интересные моменты работы LINQ to SQL. Опять

Reading time 9 min
Views 13K
С моего предыдущего поста прошёл месяц, по-моему самое время продолжить. В этот раз поговорим об Inheritance Mapping’е, ну а особо интересующихся в конце статьи ждёт сюрприз.

Итак, начнём.

Проблемы с дискриминатором


Разумеется, мы храним в нашей базе данных полиморфные сущности. Например, есть сущность CustomerOperation, которая отражает некоторую операцию, которую можно совершать над потребителем. Операции совершаются в основном через сервисы, поэтому есть наследник CustomerServiceOperation, а так же у нас есть механизм WebTracking’а, для которого есть WebTrackingOperation. Но довольно слов, лучше покажу код:
Читать дальше →
Total votes 15: ↑14 and ↓1 +13
Comments 4

Интересные моменты работы Linq to Sql

Reading time 14 min
Views 16K
Прошло уже больше года с моего предыдущего поста на похожую тему. За это время мы как-то не приблизились к переходу на Entity Framework (по текущей легенде, мы перейдём, когда появится стабильная версия EF 7), ну а у меня накопилось некоторое количество опыта, которым я бы хотел поделиться. Думаю, что эта статья будет интересна тем, кто, как и мы, до сих пор пользуются этой в общем-то неплохой, но позабытой Microsoft технологией.

DbType


Указание подсказки DbType (за исключением enum'ов, об этом ниже) не является обязательным для свойств сущностей в Linq 2 Sql. И уж точно не стоит указывать неправильный DbType. Например, не стоит, если в базе колонка имеет тип nvarchar(50), указывать Linq 2 Sql, что колонка имеет тип nchar(50). И особенно не стоит так делать, если это поле является дискриминатором, как в следующем примере:

	[Table(Name = "directcrm.OperationSteps")]
	[InheritanceMapping(Code = "", Type = typeof(OperationStep), IsDefault = true)]
	// ...
	[InheritanceMapping(Code = "ApplySegment", Type = typeof(ApplySegmentOperationStep))]
	public class OperationStep : INotifyPropertyChanging, INotifyPropertyChanged, IValidatable
	{

		// Некоторое количество кода
		...

		[Column(Storage = "type", DbType = "nchar(50) NOT NULL", CanBeNull = false, IsDiscriminator = true)]
		public string Type
		{
			get
			{
				return type;
			}
			set
			{
				if ((type != value))
				{
					SendPropertyChanging();
					type = value;
					SendPropertyChanged();
				}
			}
		}
	}

Читать дальше →
Total votes 13: ↑13 and ↓0 +13
Comments 0

Не стреляйте себе в ногу, используя LINQ

Reading time 5 min
Views 32K
В статье я описал несколько примеров неочевидных моментов при использовании LINQ to SQL. Если вы гуру .NET, вам, возможно, покажется это скучным, остальным — добро пожаловать!
Начнем с такого примера. Допустим, у нас есть сущность «тип действия». У типа действия есть human-readable имя и системное имя — некий уникальный идентификатор, по которому с объектами этой сущности мы сможем работать из кода. Вот такая структура в виде объектов в коде:

class ActionType
{
	public int id;
	public string systemname;
	public string name;
}

var ActionTypes = new ActionType[] {
	new ActionType {
		id = 1,
		systemname = "Registration",
		name = "Регистрация"
	},
	new ActionType {
		id = 2,
		systemname = "LogOn",
		name = "Вход на сайт"
	},
	new ActionType {
		id = 3,
		systemname = null,
		name = "Некоторый тип действия без системного имени"
	}
};

Для такой же структуры с аналогичными данными создана таблица в БД и вспомогательные объекты для использования LINQ to SQL. Допустим, нам необходимо выяснить, существует ли у нас тип действия с системным именем NotExistingActionType. Вопрос в том, что будет выведено на экран после выполнения этих инструкций:

var resultForObjects = ActionTypes.All(actionType => actionType.systemname != "NotExistingActionType");
var context = new LinqForHabr.DataClasses1DataContext();
var resultForLTS = context.ActionTypes.All(actionType => actionType.SystemName != "NotExistingActionType");

Console.WriteLine("Result for objects: " + resultForObjects + "\nResult for Linq to sql: " + resultForLTS);
Console.ReadLine();
Читать дальше →
Total votes 37: ↑28 and ↓9 +19
Comments 11

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Works in
Date of birth
Registered
Activity