Обновить
11.6

Проектирование и рефакторинг *

Реорганизация кода

Сначала показывать
Порог рейтинга
Уровень сложности

Разработка простого плагина для JIRA для работы с базой данных: придаем нашему плагину нормальный внешний вид

Время на прочтение7 мин
Количество просмотров18K
В первой части мы сделали простой плагин для JIRA для работы с базой данных. Теперь придадим нашему плагину «стандартный» внешний вид JIRA.



Для начала добавим немного функционала в наш плагин. Пусть теперь для каждого проекта будет свой список студентов, т.е. студент будет привязан к строго одному проекту, и добавим студентам фамилии на всякий случай. Соответственно, нам придется переделать и выдачу студентов. Выдавать теперь будем только студентов, привязанных к определенному проекту. Для этого нам придется переписать класс Students, добавив туда необходимы атрибуты студента; добавить в интерфейс StudentDAO (и само собой класс StudentDAOImpl) новый метод для получения списка студентов именно для проекта; и переписать в классе MyAction методы execute() и doAdd() в соответствии с новыми изменениями.
Читать дальше →

Разработка простого плагина для JIRA для работы с базой данных

Время на прочтение6 мин
Количество просмотров20K
Плагин будет представлять собой вкладку в административной части проекта, через которую и будем осуществлять работу с базой данных.

Плагин буду делать для джира 4.4.4. Для начала создадим пустой проект. Проект можно создать с помощью Atlassian SDK, а затем открыть в любимой IDE. В данном случае я буду работать с Netbeans. Файловая структура проекта будет выглядеть следующим образом:


Читать дальше →

C#: коллекции только для чтения и LSP

Время на прочтение5 мин
Количество просмотров29K
Часто разработчики утверждают, что read-only коллекции в .NET нарушают принцип подстановки Барбары Лисков. Так ли это? Нет, это не так, потому что IList интерфейс содержит флаг IsReadOnly. Исключением является класс Array, он действительно нарушает LSP принцип начиная с версии .NET 2.0. Но давайте разберемся во всем по порядку.
Читать дальше →

Webiny Framework. Первый взгляд

Время на прочтение8 мин
Количество просмотров9K
Есть шутка о типичной карьере разработчика:

  1. Не использует фреймворки
  2. Обнаруживает фреймворки
  3. Пишет свои фреймворки
  4. Не использует фреймворки

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

Все мы знаем, что экосистема PHP не страдает от нехватки различных фреймворков, и поэтому я немного удивился, когда увидел еще один, созданный сравнительно недавно.

Webiny

Он называется Webiny, и, будучи упакованным до краев усовершенствованиями и изменениями, которые они считают необходимыми, фреймворк имеет некоторые действительно интересные компоненты, на которые стоит взглянуть. В этой вводной статье мы не будем обращать внимание на структуру в целом, но осветим самые основные ее компоненты — StdLib.
Читать дальше →

Кросс-публикатор статей — каким он должен быть?

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

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

Несомненно, это нужно для каждого ресурса вообще, но никто (или почти никто) этим не «заморачивается», потому что чаще всего вопрос решается методом «как вывезет» — или автор хранит тексты статей в архиве, или надеется на проверенную надёжность места публикации (сайт, не предвещающий годами своего краха, Google Wave или что-нибудь попроще и малоизвестнее). Часто и сами статьи теряют актуальность. В любом случае, текстов в любом оформлении и картинок к ним в архиве бывает достаточно, чтобы вопросом дублирования публикаций не задаваться.
а как же, если грянет гром?

Снова про AUTO_INCREMENT

Время на прочтение3 мин
Количество просмотров10K
Все, кто работает с базами данных, знают, что такое AUTO_INCREMENT. Про него много всего написано, в том числе и на хабре. В этой статье я хочу изложить свои мысли на эту тему, потому что ранее я не встречал рассуждений именно в таком плане. Но сначала давайте определимся, зачем нам вообще база данных.
Читать дальше →

Приемы при проектировании архитектуры игр

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

Для примеров будет использоваться популярный движок Unity3D. Рассматриваются подходы, применимые в больших играх. Написано из моего личного опыта и из того, как я это понимаю. Конечно, где-то я могу быть не прав, где-то можно лучше сделать. Я тоже все еще в процессе набирания опыта и набивания новых шишек.

В публикации рассматриваются следующие темы:
  • Наследование VS компоненты
  • Сложные иерархии классов юнитов, предметов и прочего
  • Машины состояний, деревья поведений
  • Абстракции игровых объектов
  • Упрощение доступа к другим компонентам в объекте, сцене
  • Сложные составные игровые объекты
  • Характеристики объектов в игре
  • Модификаторы (баффы/дебаффы)
  • Сериализация данных

Читать дальше →

Слой кэширования поверх Linq to SQL

Время на прочтение10 мин
Количество просмотров7.9K
За последний год мы перенесли внушительную часть настроек DirectCRM в базу данных. Множество элементов промо-кампаний, которые мы до этого описывали исключительно кодом, теперь создаются и настраиваются менеджером через админку. При этом получилась очень сложная структура БД, насчитывающая десятки таблиц.

Однако, за перенос настроек в базу данных пришлось расплачиваться. Об архитектуре, позволяющий кэшировать редко меняющиеся Linq to SQL сущности, смотрите под катом.
image
Читать дальше →

Тернии вокруг золота

Время на прочтение4 мин
Количество просмотров4.2K
Примечание автора: это перевод статьи Боба Мартина.
На написание этой статьи меня вдохновила статья Марка Симана «The IsNullOrWhiteSpace trap» (@ploeh). Статья Марка кратко и хорошо изложена. Пожалуйста, прочитайте сначала её, прежде чем продолжать читать данную.
Ловушка, о которой рассказывает Марк, это частный случай более общей ловушки, которую я называю воровством золота. Я могу продемонстрировать эту ловушку, возвращаясь обратно к статье Марка.

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

[InlineData("Seven Lions Polarized"  , "LIONS POLARIZED SEVEN"  )]
[InlineData("seven lions polarized"  , "LIONS POLARIZED SEVEN"  )]
[InlineData("Polarized seven lions"  , "LIONS POLARIZED SEVEN"  )]
[InlineData("Au5 Crystal Mathematics", "AU5 CRYSTAL MATHEMATICS")]
[InlineData("crystal mathematics au5", "AU5 CRYSTAL MATHEMATICS")]

Он уже попал в ловушку. Почему? Потому что он уже украл золото.
Читать дальше →

Money как Value Object

Время на прочтение4 мин
Количество просмотров13K
Описываемая проблема в статье давно и хорошо известна, поэтому она по большей части для новичков, которые не знакомы с темой.

В ПО, которое разрабатывает наша команда используются денежные значения в рублях и копейках. Мы изначально знали, что использование примитивов для выражения денежных значений — это антипаттерн. Однако по мере разработки приложения мы всё никак не могли наткнуться на проблемы связанные с использованием примитивов, нам, видимо, везло и всё было нормально. До поры до времени.
Мы совсем забыли про эту проблему и использование примитивов типа int и decimal расползлось по всей системе. И теперь, когда мы написали первый метод, в котором прочувствовали проблему, пришлось вспомнить про это технический долг и переписать всё на использование денежной абстракции вместо примитивов.
Читать дальше →

Декларативная разработка на Caché

Время на прочтение3 мин
Количество просмотров3.6K
    В Caché есть несколько различных способов пройтись по коллекции и выполнить какие-нибудь действия с ее элементами. Самым простым является while-цикл. Такой способ позволяет решить поставленную задачу в императивном стиле. Разработчику приходиться явно заботиться об итераторе, о переходе к следующему элементу и о проверке выхода за пределы коллекции.
    Но разве это то, о чем должен заботиться разработчик?! Разработчик должен решать поставленную перед ним задачу, за максимально короткое время с максимально хорошим качеством кода. Было бы очень здорово просто взять коллекцию и применить к ней функцию, которая выполняет необходимые действия на каждом элементе этой коллекции. Не проверять границ, не создавать итератор, не вызывать вручную функцию на каждом элементе. Такой способ решения задач называется декларативным программированием.
Declarative programming is when you write your code in such a way that it describes what you want to do, and not how you want to do it.
(c) 1800-information
Давайте подумаем, как же решить поставленную задачу декларативно, используя средства и возможности Caché.
Читать дальше →

Триггерные рассылки

Время на прочтение11 мин
Количество просмотров9.5K
Последнее время в Email-маркетинге все чаще используются автоматические рассылки определенным группам потребителей. Типичные задачи:
  • поздравить с днем рожденья
  • позвать на сайт, если потребитель на него долго не заходил
  • сделать персонализированное предложение (делим потребителей на сегменты и рассылаем каждому сегменту свое письмо)

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

Первые реализации

3 года назад подобные задачи возникали крайне редко и мы каждый раз реализовывали их с нуля. При этом возникали одни и те же вопросы:
  1. Как помечать потребителей, которым мы уже отправили это письмо?
  2. Как максимально быстро обработать всех потребителей и при этом не тормозить работу сайтов (которые обращаются к тем же записям в БД)?

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

На втором вопросе мы набили множество шишек, связанных с блокировками в БД, и в итоге пришли к следующему шаблону:
  1. Отправка рассылок идет из windows-сервиса, который периодически проверяет не появилось ли новых потребителей, подходящих под условия.
  2. В сервисе первым шагом делается один запрос к БД с уровнем изоляции Read Uncommitted. Этот запрос вытаскивает Id всех потребителей, которым надо отправить письмо. Из-за низкого уровня изоляции такой запрос не накладывает блокировок на записи в БД и, как следствие, крайне слабо влияет на работу сайта. Однако он не гарантирует чистоту данных и их надо повторно проверить с более высоким уровнем изоляции.
  3. После того, как мы вытащили Id потребителей, для каждого потребителя мы выполняем отдельную транзакцию с уровнем изоляции Serializable. В этой транзакции мы заново проверяем подходит ли потребитель под условия и если да, отправляем ему письмо и выдаем действие-маркер. Так как мы обрабатываем каждого потребителя в отдельной транзакции, блокировки накладываются только на данные одного потребителя и на работу остальных потребителей не влияют. Так как такая транзакция очень короткая, у потребителя, которому отправляют письмо, также не будет особых проблем, если он в это время ходит по сайту. Уровень изоляции транзакции должен быть именно Serializable, чтобы ненароком не отправить одно письмо дважды, или не отправить письмо тому потребителю, который внезапно перестал подходить под условия. Хотя, если мы гарантируем, что отправка одной и той же рассылки может идти только из одного потока и с одного сервера, а также забьем на небольшую вероятность того, что одному потребителю могут отправится две рассылки с взаимоисключающими условиями, то можно использовать и Read Committed транзакцию.

Само собой после реализации нескольких рассылок по этому шаблону, мы решили вынести шаблонный код. Для этого был создан класс BatchMailing, и для каждой новой рассылки мы создавали и регистрировали в специальном реестре его наследника. В наследнике необходимо было перегрузить следующие свойства и методы:
  • шаблон действия-маркера (раньше мы называли шаблон типом действия: думаю, для разработчиков это более понятный термин), которое выдается при отправке письма
  • метод, отправляющий письмо
  • метод, выполняющий дополнительные действия (например, вместе с отправкой поздравления с днем рожденья, мы можем выдавать потребителю баллы на счет)
  • метод, который формирует Expression<Func<Customer, bool>>, проверяющий, что потребитель подходит под условие

Свойство и первые два метода никогда никаких проблем не вызывали, но вот составить Expression было довольно таки не просто. Этот Expression использовался два раза — сначала в Read Uncommitted запросе, чтобы вытащить Id потребителей, а затем в Serializable транзакции, чтобы повторно проверить подходит ли потребитель под условие. Его было нужно написать так, чтобы Linq to SQL смог его транслировать в T-SQL. Условия могли быть довольно сложными и в них всегда возникали проблемы. Ни одну рассылку нельзя было завести не написав на нее кучку тестов. Кроме того, для отправки СМС и email мы завели разных промежуточных наследников от BatchMailing. Когда же нам надо было отправить и email и СМС, приходилось копипастить. У меня были идеи как это исправить, но так как автоматические рассылки клиенты просили не так уж и часто, это была низкоприоритетная задача.

Замена наследования композицией

2 года назад при разработке очередной рекламной кампании клиент попросил сделать ему сразу 8 разных автоматических рассылок. При этом частично условия в рассылках повторялись. Тут уже не оставалось сомнений, что больше так жить нельзя, и я взялся за переписывание нашей архитектуры. Для того чтобы справится со всеми описанными выше проблемами достаточно было применить наш любимый прием: замену наследования композицией. Этот прием настолько много раз нам помогал, что я советую использовать композицию вместо наследования везде, где это возможно (ну или как минимум рассматривать такой вариант). Если вы создаете базовый абстрактный класс с мыслью “для каждой конкретной задачи у меня будет наследник перегружающий методы и свойства”, сразу спрашивайте себя “а почему бы мне вместо этого не регистрировать для каждой задачи экземпляр класса, передавая ему разные настройки”. И только если вы уверены, что композиция здесь не подходит, используйте наследование. Если подходит и то и то, всегда склоняйтесь к композиции — так получается гораздо более гибкая и понятная архитектура.

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

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

Регистрация триггера выглядела примерно следующим образом:
Add(new Trigger(“Приглашение на сайт для пришедших через канал one-to-one”)
{
	MarkerActionTemplateSystemName = “InvitationMarker”,
	TriggerAction = new TriggerActionCombination(
		new GeneratePasswordForCustomerTriggerAction(),
		new SendEmailTriggerAction(“InvitationMailing”)),
	TriggerCondition = new AndTriggerConditionSet(
		new CustomerHasSubscripionCondition(),
		new CustomerHasEmailTriggerCondition(),
		new CustomerHadFirstActionOverChannelCondition(“OneToOne”)),
});

Интерфейс TriggerAction’а крайне прост:
public interface ITriggerAction
{
	void Execute(
		ModelContext modelContext, // класс для работы с БД 
		Customer customer);
}

Базовый класс для условий триггера выглядит следующим образом:
public class TriggerCondition
{
	private readonly Func<ModelContext, Expression<Func<Customer, bool>>> triggerExpressionBuilder;

	public TriggerCondition(Func<ModelContext, Expression<Func<Customer, bool>>> triggerExpressionBuilder)
	{
		if (triggerExpressionBuilder == null)
			throw new ArgumentNullException("triggerExpressionBuilder");

		this.triggerExpressionBuilder = triggerExpressionBuilder;
	}

	public Expression<Func<Customer, bool>> GetExpression(ModelContext modelContext)
	{
		return triggerExpressionBuilder(modelContext, brand);
	}

	// Используется в Read Uncommitted транзакции для получения спиcка Id потребителей, подходящих под условие
	public IQueryable<Customer> ChooseCustomers(ModelContext modelContext, IQueryable<Customer> customers)
	{
		if (modelContext == null)
			throw new ArgumentNullException("modelContext");
		if (customers == null)
			throw new ArgumentNullException("customers");

		var expression = GetExpression(modelContext);
		return customers.Where(expression).ExpandExpressions();
	}

	// Используется в Serializable транзакции, для проверки, что потребитель все еще подходит под условие
	public bool ShouldTrigger(ModelContext modelContext, Customer customer)
	{
		if (modelContext == null)
			throw new ArgumentNullException("modelContext");
		if (customer == null)
			throw new ArgumentNullException("customer");

		var expression = GetExpression(modelContext);
		// Можно бы было просто вызывать expression.Evaluate(customer),
		// но тогда для сложных условий выполнилось бы несколько запросов в БД вместо одного
		return modelContext.Repositories.Get<CustomerRepository>().Items
			.Where(aCustomer => aCustomer == customer)
			.Where(aCustomer => expression.Evaluate(aCustomer))
			.ExpandExpressions()
			.Any();
	}
}
Для часто используемых условий мы создавали наследников от TriggerCondition, в которых строился конкретный Expression в зависимости от переданных в конструктор параметров.

Все, надоело, сами заводите свои триггеры

С использованием архитектуры, описанной выше, мы заводили триггер менее чем за пол часа, за счет комбинирования уже написанных условий и TriggerAction’ов. Однако и этого нам было мало. Следующим шагом мы захотели полностью исключить разработчиков из процесса заведения триггеров. Причем как это делать в общих чертах я понял уже через пару месяцев после реализации предыдущей версии архитектуры. Условия триггеров были один в один похожи на фильтры, которые мы используем в админке. Наша система фильтров позволяет описывать сложные условия, включая запросы к связанным сущностям, а также позволяет комбинировать их через И/ИЛИ. Фильтр формирует Expression, с помощью которого уже можно отфильтровывать сущности в БД. И для всего этого уже был написан UI и сериализация. Оставалось лишь добавить пару фильтров, которые часто нужны для триггеров, но не имели смысла при обычной работе со списком потребителей (например: “с действия прошло N дней”). Для TriggerAction’ов надо было написать UI и структуру для хранения их в БД, но тут тоже в общем все было понятно. Однако оставались еще небольшие вопросы, над которым пришлось поломать голову:
  • отсылку любого письма мы к этому времени стали регистрировать как действие, и действие-маркер стало лишним — мы и так могли определить, кому мы отправляли письмо, и вообще хотелось бы избавиться от выдачи лишних действий везде, где это было возможно
  • кроме простых триггеров, которые выполняли определенный набор операций один раз над каждым потребителем, у нас появились периодические триггеры. Надо было придумать как это все перенести в БД и при этом позволить использовать произвольные маркеры
  • маркетологи придумывают триггеры не отдельно друг от друга, а в качестве цепочек, в которых есть как триггеры так и операции, выполняемые потребителем на сайте (письмо с предложением зайти на сайт и что-то сделать → потребитель выполняет несколько операций на сайте → начисляются бонусные баллы и посылается письмо об этом). Хотелось бы если и не реализовать это сразу, то оставить задел на будущее, чтобы было не сложно описывать зависимости между триггерами и операциями
Все эти три проблемы связаны с тем, как мы определяем выполнился ли триггер над потребителем или нет. Если заводить для каждого триггера и операции на сайте свой маркер, задача сильно упрощается, но плодить лишние действия в системе очень не хотелось. Была даже идея заставлять менеджеров составлять фильтр таким образом, чтобы он полностью отвечал за то, можно ли сейчас выполнить действие над потребителем (и соответственно частота повторения триггера описывалась бы условием в фильтре), однако данный подход слишком уж располагает к ошибкам. После долгих мучительных размышлений мне все-таки пришла идея, как отслеживать выполнение триггеров без дополнительных сущностей и без усложнения работы менеджера.

Нужно больше Expression’ов

Так как триггер выполняет абстрактный шаг операции (бывший TriggerAction) над потребителем, причем почти всегда этот шаг операции уникален (например, определенное письмо отсылается или определенный приз выдается только из этого триггера), то в этот шаг можно вынести логику проверяющую выполнился ли он. Так как в триггере может быть несколько шагов операции, то менеджеру надо будет выбрать какой из них является маркером (проверять выполнение каждого шага не имеет смысла). Однако просто, реализовать в шаге операции метод, возвращающий Expression<Func<Customer,bool>> нельзя, так как пришлось бы в каждом шаге операции формировать один Expression для одноразовых триггеров, другой для периодических. Тут нас спасает то, что практически любая операция над пользователем в нашей системе выдает ему действие. Соответственно шаг операции может отфильтровать те действия, которые были выдан им. Большинство шагов операции выдают конкретное действие и для них метод, формирующий Expression для фильтрации действий, выглядит вот так:
public sealed override Expression<Func<CustomerAction, bool>> GetIsMarkerExpression(ModelContext modelContext)
{
	return action => action.ActionTemplateId == ActionTemplateId;
}

Но, например, у шага, выдающего приз, он выглядит следующим образом:
public override Expression<Func<CustomerAction, bool>> GetIsMarkerExpression(ModelContext modelContext)
{
	IQueryable
Читать дальше →

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

Время на прочтение7 мин
Количество просмотров48K
Чтобы направить всю энергию системы в необходимом направлении, нужно эту систему ограничить правилами.


Привет, Хабр! Продолжаем серию статей об архитектурном дизайне мобильных приложений. Под катом поговорим о проектировании слоёв UI. Добро пожаловать!
Читать дальше →

Ближайшие события

Legacy-код — это рак

Время на прочтение7 мин
Количество просмотров84K
Все чаще и чаще я вижу, что люди уклоняются от новейших технологий, делая выбор в пользу обратной совместимости. «Мы не можем повышать минимальные требования к PHP до 5.5, потому что у нас 50% пользователей еще на 5.4» говорят они. «Нет никакого способа обновиться до Guzzle 4+, у нас бекенд на версии 3 и переделывать его слишком долго и дорого». И самый лучший аргумент от WordPress: «Мы не может придти к полному ООП, потому что большинство пользователей сидят на shared-хостингах с 5.1 или не знают про MVC».

Нонсенс.

Legacy-код – это большое НЕТ


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

Антипаттерны проектирования: Functional Decomposition

Время на прочтение5 мин
Количество просмотров47K
Наименование: Functional Decomposition (функциональная декомпозиция)
Другие наименования: No Object-Oriented AntiPattern «No OO»
Масштаб: приложение
Рефакторинг: объектно-ориентированный реинжиниринг

Функциональная декомпозиция — хорошая практика процедурного программирования, так как она позволяет разделить приложение на отдельные функциональные модули.

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

Буриданов осел и композиция конфигурации

Время на прочтение4 мин
Количество просмотров6.8K
Сегодня немного лирики: как мы решаем, что попадает в базовый функционал решения, а что нет.
Тему настоящего текста дала известная (на хабре) статья про 1С, освещавшая помимо прочего, подход уважаемой корпорации к развитию функционала коробочных конфигураций.

Нашу платформу объединяет с 1С концепция монолита (в противовес модульной схеме некоторых коллег, что на слуху), а вот подход к композиции базовой конфигурации у нас по сравнению с 1С совершенно противоположный.
Читать дальше →

Антипаттерны проектирования: Dead End

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

Наименование: Dead End (тупик)
Другое наименование: Kevorkian Component (мертвый компонент)

Суть проблемы


Антипаттерн «тупик» получается в результате модификации повторно используемых компонентов, если компонент больше не поддерживается и не сопровождается его поставщиком. После внесения изменений в компонент, бремя его сопровождения перекладывается на разработчиков прикладной системы. Улучшения в повторно используемом компоненте не могут быть легко интегрированы а сделанные изменения могут стать причиной проблем при его поддержке.
Читать дальше →

Архитектура Android-приложений… Правильный путь?

Время на прочтение5 мин
Количество просмотров95K
От переводчика: Некоторые термины, которые использует автор, не имеют общепринятого перевода (ну, или я его не знаю:), поэтому я решил оставить большинство на языке оригинала — они всё равно понятны и для тех, кто пишет под android, но не знает английский.
Куда писать об ошибках и неточностях, вы знаете.


За последние несколько месяцев, а также после дискуссий на Tuenti с коллегами вроде @pedro_g_s и @flipper83 (кстати говоря, 2 крутых Android-разработчика), я решил, что имеет смысл написать заметку о проектировании Android-приложений.

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

Антипаттерны проектирования: Poltergeists

Время на прочтение5 мин
Количество просмотров36K
«Я точно не знаю, что делает этот класс, но я уверен, что это важно!»

У паттернов проектирования — типовых решений, есть антиподы — типовые ошибки в проектировании. О паттернах проектирования написано достаточно книг, о антипаттернах — единицы. Вашему вниманию представлен вольный перевод статьи с сайта SourceMaking, описывающий один из таких антипаттернов (всего на сайте в разделе Software Development Antipatterns их представлено 14).

Наименование: Poltergeists (полтергейсты)
Другие наименования: Gypsy (цыган), Proliferation of Classes (рост количества классов), Big DoIt Controller Class
Масштаб: приложение
Рефакторинг: Ghostbusting (охота за привидениями)
Причина появления: непонимание концепций ООП, лень продумать архитектуру классов
Читать дальше →

Стадии рождения новой функциональности в программном продукте

Время на прочтение7 мин
Количество просмотров21K
В данной статье речь пойдет о процессе добавления новой функциональности в программу. Мы рассмотрим все стадии от зарождения идеи до релиза, включая донесение требований аналитиками до тех, кто собственно всё это дело и должен претворять в жизнь, то есть до наших любимых (без кавычек и иронии) разработчиков. Статья в первую очередь нацелена на передачу практического опыта (в том числе неудачного) построения данного процесса.

КДПВ (эта картинка актуальности не потеряет, наверно, никогда):



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