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

Что такое спецификация в программировании

  • автор:

Учебники. Программирование для начинающих.

Programm.ws — это сайт, на котором вы можете почитать литературу по языкам программирования , а так-же посмотреть примеры работающих программ на С++, ассемблере, паскале и много другого..

Программирование — в обычном понимании, это процесс создания компьютерных программ.
В узком смысле (так называемое кодирование) под программированием понимается написание инструкций — программ — на конкретном языке программирования (часто по уже имеющемуся алгоритму — плану, методу решения поставленной задачи). Соответственно, люди, которые этим занимаются, называются программистами (на профессиональном жаргоне — кодерами), а те, кто разрабатывает алгоритмы — алгоритмистами, специалистами предметной области, математиками.
В более широком смысле под программированием понимают весь спектр деятельности, связанный с созданием и поддержанием в рабочем состоянии программ — программного обеспечения ЭВМ. Более точен современный термин — «программная инженерия» (также иначе «инженерия ПО»). Сюда входят анализ и постановка задачи, проектирование программы, построение алгоритмов, разработка структур данных, написание текстов программ, отладка и тестирование программы (испытания программы), документирование, настройка (конфигурирование), доработка и сопровождение.

Delphi для начинающих

Глава 1. Основы программирования

Спецификация

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

Понятие «спецификация программы»

Средства спецификации — это любые средства получения и построения таких описаний. Язык спецификаций — это рационально организованный и синтаксически оформленный набор таких средств.

  • 3. [163] Спецификация программы — это точная и полная формулировка задачи, содержащая информацию, необходимую для построения алгоритма (программы) решения этой задачи.
  • 4. Команда-комментарий — это спецификация программы, выраженная с помощью помещённого в программу утверждения (или приказа) на псевдокоде.

Мы часто вынуждены обращаться к формальным спецификациям, так как естественный язык (используемый в псевдокоде) обладает таким свойством, как полисемия.

Определение [141].

Полисемия — это наличие различных (но в какой-то мере связанных) смыслов и(или) значений у одного и того же слова (словосочетания, фразы), различных интерпретаций у одного и того же знака или знакосочетания.

Пусть PL — некоторый язык программирования (в частности, им может являться один из модельных языков Н, D, М), АР1— его алфавит, G — алфавит языка первого порядка.

Определение (синтаксическое).

1. Формальной спецификацией программы S будем называть слово

в алфавите G и АР1 и [1] , где Q, и R — формулы языка первого порядка, S — программа на языке PL.

Предусловием программы S называется формула Q.

Пустым предусловием программы S называется предусловие Q= S H

Постусловием программы S называется формула R.

2. Языком спецификаций назовём язык для записи предусловий и постусловий.

1. [88, с. 107] Для задачи о суммировании элементов массива В [0: п -1] и помещении результата в переменную S предусловие и постусловие имеют следующий вид:

2. Для вычисления целой части квадратного корня из натурального числа п и помещения результата в целочисленную переменную S предусловие и постусловие имеют следующий вид:

3. Для задачи сортировки массива В [0: п — 1] предусловие и постусловие имеют следующий вид:

Определение (no [88, c. 106]) (семантическое).

Интерпретация формальной спецификации S такова: если выполнение программы S началось в состоянии, удовлетворяющем Q, то имеется гарантия, что оно завершится через конечное время в состоянии, удовлетворяющем R.

  • 1. Утверждением будем называть содержательную или формальную спецификацию, включённую в текст программы.
  • 2. Аннотированной программой будем называть программу, содержащую утверждения между каждой парой соседних команд.

Итак, аннотированная программа является «формулой» в языке вида:

Язык программирования + Язык спецификаций.

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

Спецификация программной системы

Спецификация программной системы — описание системы, которое полностью определяет ее цель и функциональные возможности. Различают:
— словесные спецификации на естественном языке;
— модельные спецификации;
— формальные спецификации.

См. также: Спецификации программных систем Спецификации Жизненный цикл программного обеспечения

Финансовый словарь Финам .

  • Спецификация опциона
  • Спецификация фьючерса

Смотреть что такое «Спецификация программной системы» в других словарях:

  • Функциональная спецификация — Разработка программного обеспечения Процесс разработки ПО Шаги процесса Анализ • Проектирование • Программирование • Докумен … Википедия
  • Формальная спецификация — В информатике формальная спецификация это математическое описание программной или аппаратной системы, которая может быть реализована в соответствии с этим описанием. Специфицируется, что должна делать система, но не то, как она должна это… … Википедия
  • UML — (англ. Unified Modeling Language унифицированный язык моделирования) язык графического описания для объектного моделирования в области разработки программного обеспечения. UML является языком широкого профиля, это открытый… … Википедия
  • Unified Modeling Language — UML (сокр. от англ. Unified Modeling Language унифицированный язык моделирования) язык графического описания для объектного моделирования в области разработки программного обеспечения. UML является языком широкого профиля, это открытый стандарт … Википедия
  • Гради Буч — UML (сокр. от англ. Unified Modeling Language унифицированный язык моделирования) язык графического описания для объектного моделирования в области разработки программного обеспечения. UML является языком широкого профиля, это открытый стандарт … Википедия
  • ГОСТ Р МЭК 61508-4-2007: Функциональная безопасность систем электрических, электронных, программируемых электронных, связанных с безопасностью. Часть 4. Термины и определения — Терминология ГОСТ Р МЭК 61508 4 2007: Функциональная безопасность систем электрических, электронных, программируемых электронных, связанных с безопасностью. Часть 4. Термины и определения оригинал документа: 3.7.4 анализ влияния (impact analysis) … Словарь-справочник терминов нормативно-технической документации
  • Требования к программному обеспечению — Для улучшения этой статьи желательно?: Найти и оформить в виде сносок ссылки на авторитетные источники, подтверждающие написанное. Проставив сноски, внести более точные указания на источники. Пере … Википедия
  • Разработка программного обеспечения — Когда Грейс Хоппер работала с компьютером Гарвард Марк II в Гарвардском университете, её коллеги обнаружили эту моль, застрявшую в реле и таким образом помешавшую работе устройства, после чего она отметила, что они «отлаживали»(debug) систему.… … Википедия
  • Прецедент (UML) — У этого термина существуют и другие значения, см. Прецедент (значения). Основная статья: Сценарий использования Прецедент (англ. Use Case), также: вариант использования, сценарий использования спецификация последовательностей действий… … Википедия
  • Use case — Прецедент (англ. Use Case, а также: вариант использования, сценарий использования) спецификация последовательностей действий (варианты последовательностей и ошибочные последовательности), которые может осуществлять система, подсистема или класс,… … Википедия
  • Обратная связь: Техподдержка, Реклама на сайте
  • �� Путешествия

Экспорт словарей на сайты, сделанные на PHP,

WordPress, MODx.

  • Пометить текст и поделитьсяИскать в этом же словареИскать синонимы
  • Искать во всех словарях
  • Искать в переводах
  • Искать в ИнтернетеИскать в этой же категории

Поделиться ссылкой на выделенное

Прямая ссылка:

Нажмите правой клавишей мыши и выберите «Копировать ссылку»

Паттерн проектирования «Спецификация» в .NET

Паттерн проектирования

Сталкиваясь с DDD парадигмой вы точно столкнетесь с спецификацией. Спецификация часто используется вместе с паттерном «Репозиторий». Паттерн «спецификация» предоставляет возможность описывать требования к бизнес-объектам, и затем использовать их (и их композиции) для фильтрации не дублируя запросы. в Википедии этот паттерн описан так:

«Спецификация» в программировании — это шаблон проектирования, посредством которого представление правил бизнес логики может быть преобразовано в виде цепочки объектов, связанных операциями булевой логики.

  • Шаблон проектирования «Спецификация»;
  • Шаблон проектирования «Спецификация» в C#;
  • Прогноз на Specification pattern в Domain layer — ожидаются проблемы;
  • Specification pattern: C# implementation;

я решил объединить информацию с нескольких источников и описать полноценно этот паттерн в этой статье.

Начнем с того что рассмотрим UML схему классического шаблона спецификация:

спецификация паттерн

Классическая реализация спецификации в .NET будет выглядеть следующим образом:

 public interface ISpecification < bool IsSatisfiedBy(object candidate); ISpecification And(ISpecification other); ISpecification AndNot(ISpecification other); ISpecification Or(ISpecification other); ISpecification OrNot(ISpecification other); ISpecification Not(); >public abstract class CompositeSpecification : ISpecification < public abstract bool IsSatisfiedBy(object candidate); public ISpecification And(ISpecification other) < return new AndSpecification(this, other); >public ISpecification AndNot(ISpecification other) < return new AndNotSpecification(this, other); >public ISpecification Or(ISpecification other) < return new OrSpecification(this, other); >public ISpecification OrNot(ISpecification other) < return new OrNotSpecification(this, other); >public ISpecification Not() < return new NotSpecification(this); >> public class AndSpecification : CompositeSpecification < private readonly ISpecification _leftCondition; private readonly ISpecification _rightCondition; public AndSpecification(ISpecification left, ISpecification right) < _leftCondition = left; _rightCondition = right; >public override bool IsSatisfiedBy(object candidate) < return _leftCondition.IsSatisfiedBy(candidate) && _rightCondition.IsSatisfiedBy(candidate); >> public class AndNotSpecification : CompositeSpecification < private readonly ISpecification _leftCondition; private readonly ISpecification _rightCondition; public AndNotSpecification(ISpecification left, ISpecification right) < _leftCondition = left; _rightCondition = right; >public override bool IsSatisfiedBy(object candidate) < return _leftCondition.IsSatisfiedBy(candidate) && _rightCondition.IsSatisfiedBy(candidate) != true; >> public class OrSpecification : CompositeSpecification < private readonly ISpecification _leftCondition; private readonly ISpecification _rightCondition; public OrSpecification(ISpecification left, ISpecification right) < _leftCondition = left; _rightCondition = right; >public override bool IsSatisfiedBy(object candidate) < return _leftCondition.IsSatisfiedBy(candidate) || _rightCondition.IsSatisfiedBy(candidate); >> public class OrNotSpecification : CompositeSpecification < private readonly ISpecification _leftCondition; private readonly ISpecification _rightCondition; public OrNotSpecification(ISpecification left, ISpecification right) < _leftCondition = left; _rightCondition = right; >public override bool IsSatisfiedBy(object candidate) < return _leftCondition.IsSatisfiedBy(candidate) || _rightCondition.IsSatisfiedBy(candidate) != true; >> public class NotSpecification : CompositeSpecification < private readonly ISpecification _wrapped; public NotSpecification(ISpecification x) < _wrapped = x; >public override bool IsSatisfiedBy(object candidate) < return !_wrapped.IsSatisfiedBy(candidate); >>

С появлением Generic’ов код можно переписать проще:

public interface ISpecification  < bool IsSatisfiedBy(T candidate); ISpecificationAnd(ISpecification other); ISpecification AndNot(ISpecification other); ISpecification Or(ISpecification other); ISpecification OrNot(ISpecification other); ISpecification Not(); > public abstract class LinqSpecification : CompositeSpecification < public abstract Expression> AsExpression(); public override bool IsSatisfiedBy(T candidate) => AsExpression().Compile()(candidate); > public abstract class CompositeSpecification : ISpecification  < public abstract bool IsSatisfiedBy(T candidate); public ISpecificationAnd(ISpecification other) => new AndSpecification(this, other); public ISpecification AndNot(ISpecification other) => new AndNotSpecification(this, other); public ISpecification Or(ISpecification other) => new OrSpecification(this, other); public ISpecification OrNot(ISpecification other) => new OrNotSpecification(this, other); public ISpecification Not() => new NotSpecification(this); > public class AndSpecification : CompositeSpecification  < readonly ISpecification_left; readonly ISpecification _right; public AndSpecification(ISpecification left, ISpecification right) < _left = left; _right = right; >public override bool IsSatisfiedBy(T candidate) => _left.IsSatisfiedBy(candidate) && _right.IsSatisfiedBy(candidate); > public class AndNotSpecification : CompositeSpecification  < readonly ISpecification_left; readonly ISpecification _right; public AndNotSpecification(ISpecification left, ISpecification right) < _left = left; _right = right; >public override bool IsSatisfiedBy(T candidate) => _left.IsSatisfiedBy(candidate) && !_right.IsSatisfiedBy(candidate); > public class OrSpecification : CompositeSpecification  < readonly ISpecification_left; readonly ISpecification _right; public OrSpecification(ISpecification left, ISpecification right) < _left = left; _right = right; >public override bool IsSatisfiedBy(T candidate) => _left.IsSatisfiedBy(candidate) || _right.IsSatisfiedBy(candidate); > public class OrNotSpecification : CompositeSpecification  < readonly ISpecification_left; readonly ISpecification _right; public OrNotSpecification(ISpecification left, ISpecification right) < _left = left; _right = right; >public override bool IsSatisfiedBy(T candidate) => _left.IsSatisfiedBy(candidate) || !_right.IsSatisfiedBy(candidate); > public class NotSpecification : CompositeSpecification  < readonly ISpecification_other; public NotSpecification(ISpecification other) => _other = other; public override bool IsSatisfiedBy(T candidate) => !_other.IsSatisfiedBy(candidate); >

Перейдем от абстракций к более-менее реальному примеру.

Допустим, у нас есть портал который хранит в себе список фильмов и отдает их по определенному запросу:

public class Movie : Entity < public string Name < get; >public DateTime ReleaseDate < get; >public MpaaRating MpaaRating < get; >public string Genre < get; >public double Rating < get; >> public enum MpaaRating

Давайте представим, что пользователям нужно будет получать фильмы по дате, рейтингу, жанру.

Для этого мы создадим IMovieRepository :

 public interface IMovieRepository < IReadOnlyListGetByReleaseDate(DateTime maxReleaseDate); IReadOnlyList GetByRating(double minRating); IReadOnlyList GetByGenre(string genre); >

Теперь, когда мы захотим объединить все критерии поиска, код может усложниться, пока добавим еще один метод Find, который обработает все возможные критерии и вернет консолидированный результат:

public class MovieRepository < public IReadOnlyListFind( DateTime? maxReleaseDate = null, double minRating = 0, string genre = null) < /* . */ >>

Проблема возникает тогда, когда нам нужно делать проверку не только на этапе запроса к БД. но и в бизнес логике как тут:

public ResultBuyChildTicket(int movieId)

Если на уровне БД нам так же нужно фильтровать фильмы, мы добавим такой метод:

public class MovieRepository < public IReadOnlyListFindMoviesForChildren() < return db .Where(x =>x.MpaaRating == MpaaRating.G) .ToList(); > >

Проблема этих двух примеров в том, что они нарушают DRY принцип, поскольку метод проверки того, что является детским фильмом теперь «расплывается» в 2 метода (а по факту даже в 2 слоя приложения DAL и BLL). В таких случаях нас может выручить паттерн «спецификация». Мы можем создать класс-спецификацию который будет проверять можно ли показывать этот фильм детям и выдавать нам результат:

public ResultBuyChildTicket(int movieId) < Movie movie = _repository.GetById(movieId); var spec = new MovieForKidsSpecification(); if (!spec.IsSatisfiedBy(movie)) return Error("The movie is not eligible for children"); return Ok(); >public class MovieRepository < public IReadOnlyListFind(Specification specification) < /* . */ >>

Этот подход позволяет не только убрать дублирование кода в разных доменных областях, но и позволяет комбинировать спецификации. Это в свою очередь позволяет «Аплаить» сколько спецификаций, сколько нам нужно.

Три случая когда стоит использовать шаблон проектирования «спецификация»:

  1. Поиск данных в базе данных. Это поиск записей который соответствуют спецификации, которую мы имеем реализовали.
  2. Проверка объектов в памяти. Другими словами, проверка того, что объект, который мы извлекли из БД соответствует спецификации.
  3. Создание нового экземпляра, который соответствует критериям. Это полезно в тех случаях, когда вы не заботитесь о реальном содержании экземпляров, но все же должны иметь определенные атрибуты.

GenericSpecification

Создавая спецификацию. у может нас появится желание создать генерик который будет обслуживать нужную нам спецификацию, например:

public class GenericSpecification < public Expression> Expression < get; >public GenericSpecification(Expression> expression) < Expression = expression; >public bool IsSatisfiedBy(T entity) < return Expression.Compile().Invoke(entity); >> // Controller public void SomeMethod() < var specification = new GenericSpecification( m => m.MpaaRating == MpaaRating.G); bool isOk = specification.IsSatisfiedBy(movie); // Exercising a single movie var movies = _repository.Find(specification); // Getting a list of movies > // Repository public IReadOnlyList Find(GenericSpecification specification)

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

Помните (!) Вынос проблемы на другой уровень абстракции не решает эту проблему.

Generic спецификация не помогает решить DRY диллему, а значит не сильно нам подходит, да и в целом GenericSpecification — это плохая практика тк сами по себе они бесполезны.

Строго-типизированные спецификации

Как мы можем исправить проблему которая у нас возникла выше?

Решением этой проблемы будет создание строго-типизированной спецификации. Эта спецификация будет в себе иметь все нужные доменные знания без возможности изменять их извне.

Перепишем наш код:

public abstract class Specification < public abstract Expression> ToExpression(); public bool IsSatisfiedBy(T entity) < Funcpredicate = ToExpression().Compile(); return predicate(entity); > > public class MpaaRatingAtMostSpecification : Specification  < private readonly MpaaRating_rating; public MpaaRatingAtMostSpecification(MpaaRating rating) < _rating = rating; >public override Expression> ToExpression() < return movie =>movie.MpaaRating > // Controller public void SomeMethod() < var gRating = new MpaaRatingAtMostSpecification(MpaaRating.G); bool isOk = gRating.IsSatisfiedBy(movie); // Exercising a single movie IReadOnlyListmovies = repository.Find(gRating); // Getting a list of movies > // Repository public IReadOnlyList Find(Specification specification) < using (ISession session = SessionFactory.OpenSession()) < return session.Query() .Where(specification.ToExpression()) .ToList(); > >

Благодаря такому уровню абстракции, нам не нужно теперь следить за тем как мы создаем спецификации и за их экземплярами, так же это решает проблему дублирования. Спецификации легко поддаются таким операциям как And, Or, Not и тд, для этого нам нужно добавить соответствующий код, например для And операции:

public abstract class Specification  < public SpecificationAnd(Specification specification) < return new AndSpecification(this, specification); > // And also Or and Not methods > public class AndSpecification : Specification  < private readonly Specification_left; private readonly Specification _right; public AndSpecification(Specification left, Specification right) < _right = right; _left = left; >public override Expression> ToExpression() < Expression> leftExpression = _left.ToExpression(); Expression> rightExpression = _right.ToExpression(); BinaryExpression andExpression = Expression.AndAlso( leftExpression.Body, rightExpression.Body); return Expression.Lambda>( andExpression, leftExpression.Parameters.Single()); > > var gRating = new MpaaRatingAtMostSpecification(MpaaRating.G); var goodMovie = new GoodMovieSpecification(); var repository = new MovieRepository(); IReadOnlyList movies = repository.Find(gRating.And(goodMovie));

Чего просто не возвращать IQueryable в репозитории?

Действительно

Разве не проще позволить клиентам запрашивать те данные которые они хотят реализовав метод Find который возвращает IQueryable ?

// Repository public IQueryable Find() < return session.Query(); >

и потом уже использовать в контроллере (или любом другом месте где вы юзаете этот репозиторий) нужный запрос

public void SomeMethod() < Listmovies = _repository.Find() .Where(movie => movie.MpaaRating == MpaaRating.G) .ToList(); >

Этот подход, по сути, имеет тот же недостаток, что и наша первоначальная реализация: он побуждает нас нарушать принцип DRY, дублируя знания предметной области. Этот метод не предлагает нам ничего с точки зрения консолидации в одном месте.

Вторым недостатком здесь является то, что мы открываем контроль над DAL напрямую в контроллер. Что является болезненной и плохой практикой в многоуровневой архитектуре. Стоит помнить что, реализация IQueryable в значительной степени зависит от того, какой «поставщик» LINQ используется за кулисами, поэтому клиентский код должен знать, что потенциально существуют запросы, которые не могут быть скомпилированы в SQL.

Так же этот код нарушает еще один принцип The Liskov Substitution Principle​ (LSP).

Extension method vs specification

Возникает вопрос: а зачем городить спецификацию, если можно просто создать Extension, например:

 public class MoviesExtensions < public static IQueryableIsForChild(this IQueryable users, MpaaRating rating) < return users.Where(x =>x.MpaaRating == rating); > >

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

Спецификация так же отлично работает и в паре с экстеншн методами.

Например, если вы реализуете SoftDelete подход через Extension:

public static IQueryable Undeleted(this IQueryable queryable) where T : Entity < return queryable.Where(x =>!x.IsDeleted); >

вы можете спокойно юзать Extension, который будет общим для каждого из DBSet’ов где нужна поддержка SoftDelete и использовать его в паре с конкретными спецификациями в конкретных сервисах (репозиториях).

Итоги:

  • Не используйте GenericSpecification в паре с Expression> в качестве реализации шаблона спецификаций, они не позволяют фактически собрать знания о предметной области в одно место.
  • Не возвращайте IQueryable из репозиториев, это вызывает проблемы с нарушением DRY и LSP.
  • Тот или иной паттерн не панацея от всех проблем, используйте паттерны с умом и применяйте их там где они действительно нужны, помните и про такие принципы как YAGNI и KISS.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *