четверг, 31 июля 2008 г.

Очередное сообщение ни о чем

Итак... "нас было много на челне" (с) кто-то когда-то, и примерно так вот.

Что сделано

Общие вопросы:
Хостинг не заказал из-за (известных моим друзьям) проблем. :(
Закажу через 2 недели.
Одна дизайнер отказалась от работы. С другой еще не начал работать. Так что дизайн будет не скоро.
И отказался еще один программер, который делал клиентскую часть.
В общем, из действующих на данный момент помошников, только Умная-Лапулькина-Аналитик.

Сделал по коду:
1. Возможность добавления комментариев.
2. Просмотр миникопий фотографий в списказ и больших копий фотографий отдельно. (добавление еще не сделано).
3. Ленивая загрузка выпадающих списков (комментариев, фотографий и т.д.)

Посмотрел по требованиям:
Посмотрел программульку от Borland Caliber Define IT 2008 (ну... во всяком случае так назывался exe-файл).
Что я могу сказать... не очень понравилось. Хорошие картинки рисует :) Но картинки мне не очень нужны. Плюс методология которую я не очень знаю (а "знаю" [условно] я только Коберна). В общем... может попробую, но вряд ли...
Наверное опять буду описывать в стиле Коберна. Сам уже в конец запутался что хочу описать. Так что работа по проекту еле движется....

среда, 23 июля 2008 г.

Давно не писал ничего....

Чего-то я давно ничего не писал... Исправляю... правда не сильно :)))
А не писал я потому, что у меня небыло дома инета.

Собственно, за это время:
1. Почти определился с доменным названием сайта.
2. Почти выбрал хостинг.
3. Сделал добавление комментариев к маршруту.
4. Не знаю что из чего я чего там и, главное, почему вот.
5. Выяснил что дизайна в ближайшее время не будет :(
6. Договорился, но еще не начал работу, с другим дизайнером.
7. Поиграл, в первые за 10-20 лет, в настольный теннис на работе.
8. Несколько раз поел, попил, ..., ..., поспал, тоже несколько раз...

Ну... ладно...
Прошлое - забыто, грядущее - закрыто, настоящее - даровано.

В настоящем начало 4го утра и пора спать.

Теперь о будущем:
Антон.Ка нашел какую-то софтину от Borland для описания требований и я ее в ближайшее время притащу домой.
Триал там 30 дней. Так что за это время мне надо будет написать требования по Катальщику и Сусанину.
Я ее еще не видел, но он обещал ее показать. Ждем-с.

За сим - откланиваюсь.

вторник, 15 июля 2008 г.

Конкурс на называние

Организовываю конкурс на название сайта.
У кого есть какие идеи - пишите.
Дабы не светить конкурентам, можно писать в аську, почту и т.д.
Можно писать в комментах.
Пока, как вы знаете, название проекта VeloLife.

Желательно, что б домены были свободными ;-)))))))
Для VeloLife их не так уж и много, поэтому ищу названия по нашей тематике.

четверг, 10 июля 2008 г.

"Малые" покатушки

При начале реализации "малых" покатушек пришел к выводу, что они (в плане реализации) сложнее "больших" покатушек.

Решил отказаться от реализации "малых" покатушек на N-недель (а может быть даже на Q-месяцев)...
Возможно, опишу требования к ним в use-case, но и то не факт.

среда, 9 июля 2008 г.

Новостная страница сайта

Все-таки решил убрать "новые маршруты" с первой страницы для "гостя".
Они там не нужны.
Если человек - "гость", то ему по барабану "что-нового?" ему "все-новое!" и он должен иди на страницу с маршрутами и там смотреть все маршруты.

Список запланированных покатушек - оставлю, так как это ему может быть интересно.

вторник, 8 июля 2008 г.

Первый снимок экрана ;-)

Перегенерил объектную модель на основе модели БД.
Так как у меня каждая сущность отображаются на отдельную таблицу, это было не сложно.
Сделал изменение новостей и маршрутов.
Загрузку из БД.
Надо сделать еще регистрацию покатушки и можно начинать зудеть над дизайнером.
Может кто захочет мне еще дизайн сделать? ;-))
В качестве игры на нервах размещу screenshort текущего дизайна сайта.

Вздрогните!

пятница, 4 июля 2008 г.

Изменение определения объекта "Новость"

Умная Лапулькина сегодня критиковала по поводу понятия "Новость сайта".
Вот что родилось из разъяснений мне:

Ранее у меня несколько одинаково описывалось: "новость" и "показ новостей сайта".
Под этими понятиями подразумевались совершенно разные вещи.
Разделим их.
"Новость" назовем "официальная новость сайта". (хотя... будем продолжать называть ее "Новость").
То что раньше было "Новости сайта" назовем изменения контента сайта.

К чему это приводит: официальная новость сайта - это объект "Новость". Сущность описана в предыдущем посте. В качестве примера Новости, может быть поздравление с "Новым Годом!!!", "23 февраля", "8 марта" (ну... других новостей я еще не придумал... хотя, можно с пятнице еще поздравть).
Изменение контента - это то, что нового на сайте с точки зрения цели пользователя заходящего на сайт.
Немножко не понятно даже мне, но я хочу сказать следующее:
Пользователь заходя на сайт зачем-то это делает. Что он хочет? Основное, что хочет пользователь - покататься. Т.е. при показе изменений его, в первую очередь интересуют запланированные покатушки и новые маршруты.
Таким образом, Гостю надо показывать запланированные покатушки и новые маршруты.
Зарегестрированный пользователь заходит еще "пообщаться" иначе ему регистрироваться нафиг не нужно. Так что можно показать отчеты по покатушкам (так как он "в тусовке"). Плюс зарегестированный пользователь имеет какую-то локацию. Значит можно отфильтровать список маршрутов-покатушек по локации. Этим убрав лишнее с экрана. Хотя, эту возможность, по требования ЛапулькиУмной, можно впихнуть в настройки пользователя.

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

Начало реализации

Ну... чего-то мне поднадоело писать требования.
Подожду пока "критиканы" (кстати, мною уважаемые люди, и если кто-то из них обидится на это название, пусть скажет, буду ее вычищать из текста) критикуют и промоют мне мозги по поводу:
- правильности и способа написания use-case,
- определения целей пользователя,
- value-пользователя (ну... это типа подцель или, по другому, какая-то нужная пользователю штука, позволяющая достичь цели),
- и (поверьте) многого другого.
(сегодня был первый день, когда я достиг целей блога, т.е.когда мне с двух сторон приводили доводы и контр-доводы одного и другого и третье и десятого... по поводу описания use-case и требований к сайту.... боюсь я стока сразу усвоить не могу)

Ну так вот, я решил начать описывать структуру БД и пр.
Начнем со структуры базы данных новостей:



Во-от....

Реализация кода:
Если покликать на участках кода в FireFox и IE - код скрывается. (на моих версиях)

Итак! Что бы реализовать работу с Новостями был реализован следующий behind-код. Т.е. тут не приведены файлы представления данных.


Контроллер, обслуживающий новости:
NewsController.cs

  1. using System;
  2. using System.Web.Mvc;
  3. using System.Collections;
  4. using System.Collections.Specialized;
  5.  
  6.  
  7. using NH = VeloLife.NhProxy;
  8. using VeloLife.Models;
  9. using VeloLife.Environment;
  10. using VeloLife.Security;
  11.  
  12. namespace VeloLife.Controllers
  13. {
  14.   /// <summary>
  15.   /// Контроллер "Новостей"
  16.   /// </summary>
  17.   public class NewsController : MyBaseController
  18.   {
  19.     /// <summary>
  20.     /// Отобразить список новостей.
  21.     /// </summary>
  22.     /// <returns></returns>
  23.     public ActionResult List()
  24.     {
  25.       IList result = NH.News.GetActualNewses();
  26.       ViewData["News"] = result;
  27.       return View();
  28.     }    
  29.     
  30.     /// <summary>
  31.     /// Отредактировать новость с ID...
  32.     /// </summary>
  33.     /// <returns></returns>
  34.     [ExternalSecutityCheckAspect(Permission=SecurityContext.PermissionLevel.Administrator)]
  35.     public ActionResult Edit()
  36.     {
  37.       string id = RouteData.Values["id"].ToString().ToLower();
  38.       News news = new News();
  39.       if (id == "")
  40.       {
  41.         news.DateNews = DateTime.Now;
  42.       }
  43.       else
  44.       {
  45.         news.Load(id);
  46.       }
  47.       ViewData["Object"] = news;
  48.       return View();
  49.     }
  50.  
  51.     /// <summary>
  52.     /// Сохранить новость.
  53.     /// </summary>
  54.     /// <returns></returns>
  55.     [ExternalSecutityCheckAspect(Permission = SecurityContext.PermissionLevel.Administrator)]
  56.     public ActionResult Save()
  57.     {
  58.       News news = new News();
  59.       NameValueCollection param = this.Request.Params;
  60.  
  61.       try
  62.       {
  63.         if (param["IdNews"] != "" && param["IdNews"] != "-1")
  64.         {
  65.           news.IdNews = Int32.Parse(param["IdNews"]);
  66.         }
  67.         if (param["DateNews"] == "")
  68.         {
  69.           this.Errors.Add("Не определена дата");
  70.         }
  71.         else
  72.         {
  73.           news.DateNews = DateTime.Parse(param["DateNews"]);
  74.         }
  75.         if (param["CaptionNews"] == "")
  76.         {
  77.           this.Errors.Add("Не определен заголовок");
  78.         }
  79.         else
  80.         {
  81.           news.CaptionNews = param["CaptionNews"];
  82.         }
  83.         if (param["TextNews"] == "")
  84.         {
  85.           this.Errors.Add("Не определено тело новости");
  86.         }
  87.         else
  88.         {
  89.           news.TextNews = param["TextNews"];
  90.         }
  91.  
  92.       }
  93.       catch (Exception e)
  94.       {
  95.         this.Errors.Add("Системная ошибка: " + e.Message);
  96.       }
  97.  
  98.       if (!this.Errors.HasErrors)
  99.       {
  100.         news.Save();
  101.         return null;
  102.       }
  103.       return View("SimpleMessage");
  104. //      return this.RedirectToAction("SimpleMessage", "Main", new { VLServerErrors = this.Errors });
  105.     }
  106.  
  107.     /// <summary>
  108.     /// Спец метод завершения работы с новостями.
  109.     /// Зачем сделал - плохо помню :)
  110.     /// </summary>
  111.     /// <returns></returns>
  112.     [ExternalSecutityCheckAspect(Permission = SecurityContext.PermissionLevel.Administrator)]
  113.     public ActionResult Done()
  114.     {
  115.       return RedirectToAction("List", "News");
  116.     }
  117.   }
  118. }
* This source code was highlighted with Source Code Highlighter.



Автогенереная часть модели:
Model/News.TG.cs

  1. using System;
  2. using NH = VeloLife.NhProxy;
  3.  
  4. namespace VeloLife.Models
  5. {
  6.   public partial class News
  7.   {
  8.     #region Поля
  9.     ///<summary>
  10.     ///Ид новости
  11.     ///</summary>
  12.     private int _IdNews;
  13.     
  14.     ///<summary>
  15.     ///Дата новости
  16.     ///</summary>
  17.     private DateTime _DateNews;
  18.     
  19.     ///<summary>
  20.     ///Заголовок новости
  21.     ///</summary>
  22.     private string _CaptionNews;
  23.     
  24.     ///<summary>
  25.     ///Текст новости
  26.     ///</summary>
  27.     private string _TextNews;
  28.     
  29.     #endregion
  30.     
  31.     #region Свойства доступа к полям
  32.  
  33.     ///<summary>
  34.     ///Обработка Ид новости
  35.     ///</summary>
  36.     public int IdNews
  37.     {
  38.       get
  39.       {
  40.         return _IdNews;
  41.       }
  42.       set
  43.       {
  44.         _IdNews = value;
  45.       }
  46.     }
  47.  
  48.     ///<summary>
  49.     ///Обработка Дата новости
  50.     ///</summary>
  51.     public DateTime DateNews
  52.     {
  53.       get
  54.       {
  55.         return _DateNews;
  56.       }
  57.       set
  58.       {
  59.         _DateNews = value;
  60.       }
  61.     }
  62.  
  63.     ///<summary>
  64.     ///Обработка Заголовок новости
  65.     ///</summary>
  66.     public string CaptionNews
  67.     {
  68.       get
  69.       {
  70.         return _CaptionNews;
  71.       }
  72.       set
  73.       {
  74.         _CaptionNews = value;
  75.       }
  76.     }
  77.  
  78.     ///<summary>
  79.     ///Обработка Текст новости
  80.     ///</summary>
  81.     public string TextNews
  82.     {
  83.       get
  84.       {
  85.         return _TextNews;
  86.       }
  87.       set
  88.       {
  89.         _TextNews = value;
  90.       }
  91.     }
  92.     #endregion
  93.     
  94.     #region Вспомогательные методы по объекту.
  95.  
  96.     ///<summary>
  97.     ///Загрузка объекта
  98.     ///</summary>    
  99.     public void Load(int id)
  100.     {
  101.       using (NH.News db = new NH.News(this))
  102.       {
  103.         db.Load(id);
  104.       }
  105.     }
  106.  
  107.     ///<summary>
  108.     ///Загрузка объекта по ID в виде строки.
  109.     ///часто будет нужна при работе с controller.
  110.     ///</summary>    
  111.     public void Load(string id)
  112.     {
  113.       using (NH.News db = new NH.News(this))
  114.       {
  115.         db.Load(Int32.Parse(id));
  116.       }
  117.     }
  118.     
  119.     ///<summary>
  120.     ///Загрузка объекта
  121.     ///</summary>    
  122.     public void Save()
  123.     {
  124.       using (NH.News db = new NH.News(this))
  125.       {
  126.         db.Save();
  127.       }
  128.     }
  129.     
  130.     #endregion
  131.     
  132.   }
  133. }
  134.  
* This source code was highlighted with Source Code Highlighter.



Custom-реализация модели:
Model/News.Custom.cs

  1. using System.Collections;
  2. using NH = VeloLife.NhProxy;
  3.  
  4. namespace VeloLife.Models
  5. {
  6.   public partial class News
  7.   {
  8.     public News()
  9.     {
  10.       _IdNews = -1;
  11.     }
  12.  
  13.  
  14.  
  15.     public static IList GetActualNewses()
  16.     {
  17.       return NH.News.GetActualNewses();
  18.     }
  19.   }
  20. }
* This source code was highlighted with Source Code Highlighter.



Автогенереная прокси для Nhibernate:
NhProxy/News.TG.cs

  1. using System;
  2. using M = VeloLife.Models;
  3. using NHibernate;
  4. using System.Collections;
  5.  
  6. namespace VeloLife.NhProxy
  7. {
  8.   public partial class News : IDisposable
  9.   {
  10.     ///<summary>
  11.     ///Ссылка на реальный объект
  12.     ///</summary>
  13.     private M.News _realObject;
  14.  
  15.     ///<summary>
  16.     ///Ид новости
  17.     ///</summary>
  18.     private int _IdNews;
  19.     
  20.     ///<summary>
  21.     ///Дата новости
  22.     ///</summary>
  23.     private DateTime _DateNews;
  24.     
  25.     ///<summary>
  26.     ///Заголовок новости
  27.     ///</summary>
  28.     private string _CaptionNews;
  29.     
  30.     ///<summary>
  31.     ///Текст новости
  32.     ///</summary>
  33.     private string _TextNews;
  34.     
  35.  
  36.  
  37.  
  38.     public News()
  39.     {
  40.       _realObject = null;
  41.     }
  42.  
  43.     
  44.     public News(M.News realObject)
  45.     {
  46.       _realObject = realObject;
  47.       IdNews = _realObject.IdNews;
  48.       DateNews = _realObject.DateNews;
  49.       CaptionNews = _realObject.CaptionNews;
  50.       TextNews = _realObject.TextNews;
  51.     }
  52.     
  53.     #region Свойства доступа к полям
  54.  
  55.  
  56.     ///<summary>
  57.     ///Обработка Ид новости
  58.     ///</summary>
  59.     public virtual int IdNews
  60.     {
  61.       get
  62.       {
  63.         return _IdNews;
  64.       }
  65.       set
  66.       {
  67.         _IdNews = value;
  68.       }
  69.     }
  70.  
  71.     ///<summary>
  72.     ///Обработка Дата новости
  73.     ///</summary>
  74.     public virtual DateTime DateNews
  75.     {
  76.       get
  77.       {
  78.         return _DateNews;
  79.       }
  80.       set
  81.       {
  82.         _DateNews = value;
  83.       }
  84.     }
  85.  
  86.     ///<summary>
  87.     ///Обработка Заголовок новости
  88.     ///</summary>
  89.     public virtual string CaptionNews
  90.     {
  91.       get
  92.       {
  93.         return _CaptionNews;
  94.       }
  95.       set
  96.       {
  97.         _CaptionNews = value;
  98.       }
  99.     }
  100.  
  101.     ///<summary>
  102.     ///Обработка Текст новости
  103.     ///</summary>
  104.     public virtual string TextNews
  105.     {
  106.       get
  107.       {
  108.         return _TextNews;
  109.       }
  110.       set
  111.       {
  112.         _TextNews = value;
  113.       }
  114.     }
  115.     private void FillRealObject()
  116.     {
  117.       _realObject.IdNews = IdNews;
  118.       _realObject.DateNews = DateNews;
  119.       _realObject.CaptionNews = CaptionNews;
  120.       _realObject.TextNews = TextNews;
  121.     }
  122.  
  123.  
  124.  
  125.     #endregion
  126.     
  127.     ///<summary>
  128.     ///Загрузка данных по ИД
  129.     ///</summary>    
  130.     public virtual void Load(int id)
  131.     {
  132.       ISession session = NHibernateStorage.GetCurrentSession();
  133.       session.Load(this, id);
  134.       NHibernateStorage.CloseSession();
  135.       FillRealObject();
  136.     }
  137.     
  138.  
  139.     ///<summary>
  140.     ///Сохранение данных.
  141.     ///</summary>    
  142.     public virtual void Save()
  143.     {
  144.       ISession session =null;
  145.       try
  146.       {
  147.         session = NHibernateStorage.GetCurrentSession();
  148.       }
  149.       catch (Exception e)
  150.       {
  151.         throw e;
  152.       }
  153.       ITransaction tx = session.BeginTransaction();
  154.       if (this.IsNew)
  155.       {
  156.         session.Save(this);
  157.       }
  158.       else
  159.       {
  160.         session.Update(this);
  161.       }
  162.       tx.Commit();
  163.  
  164.       NHibernateStorage.CloseSession();
  165.     }
  166.     
  167.     ///<summary>
  168.     ///Проверяет, является ли объект новым.
  169.     ///</summary>    
  170.     protected virtual bool IsNew
  171.     {
  172.       get
  173.       {
  174.         return _realObject.IdNews == -1;
  175.       }
  176.     }
  177.     
  178.     public virtual void Dispose()
  179.     {
  180.      
  181.     }
  182.   
  183.   }
  184. }
* This source code was highlighted with Source Code Highlighter.




Custom-часть прокси для Nhibernate:
NhProxy/News.Custom.cs

  1. using System;
  2. using System.Collections;
  3. using NHibernate;
  4.  
  5. namespace VeloLife.NhProxy
  6. {
  7.   public partial class News
  8.   {
  9.     public static IList GetActualNewses()
  10.     {
  11.       
  12.       ISession session = NHibernateStorage.GetCurrentSession();
  13.       IList result = session.CreateQuery("from News as n where n.DateNews between :minDate and :maxDate")
  14.         .SetDateTime("minDate", DateTime.Now.AddDays(-10))
  15.         .SetDateTime("maxDate", DateTime.Now)
  16.         .List();
  17.       NHibernateStorage.CloseSession();
  18.       return result;
  19.     }
  20.   }
  21. }
* This source code was highlighted with Source Code Highlighter.



Xml-конфиг для Nhibernate:
NhProxy/News.hbm.xml

  1. <?xml version="1.0" encoding="windows-1251" ?>
  2. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="VeloLife" namespace="VeloLife.NhProxy">
  3.   <class name="News" table="News">
  4.     <id name="IdNews" column="IdNews">
  5.       <generator class="native" />
  6.     </id>
  7.     <property name="DateNews" column="DateNews" type="DateTime"></property>
  8.     <property name="CaptionNews" column="CaptionNews" type="string"></property>
  9.     <property name="TextNews" column="TextNews" type="string"></property>
  10.   </class>
  11. </hibernate-mapping>
* This source code was highlighted with Source Code Highlighter.



И наконец - шаблон для автогенерации кода:
News.tgd

s template = FullGen.tg

;; Имя объекта
s ObjectName = News

;; Колонки сущности
tdef Fields
cols FieldName = "?", \
FieldType = "?", \
Caption = "?", \
DBName = "?", \
DBType = "?", \
IsPK = "false"

r IdNews, int, "Ид новости"; \
IsPK = true

r DateNews, DateTime, "Дата новости"
r CaptionNews, string, "Заголовок новости"
r TextNews, string, "Текст новости"
tend


Воот... так я больше делать никогда не буду....
Не эффективно...
Но - что-то запихну.
Это - текущая версия. Потом буду упрощать.

Обратите внимания на аттрибуты в контроллере:

[ExternalSecutityCheckAspect(
Permission = SecurityContext.PermissionLevel.Administrator)]


Это Security. Т.е. вызов этого метода произойдет только после полной проверки безопасности.
Это - аспект :)
Но об этом - после. Сегодня мне надоело и я пойду спать.

четверг, 3 июля 2008 г.

Цели пользователей

Поступила критика (и вообще, сегодня день богатый на критику меня) что цели пользователя не есть функционал сайта. И цели пользователя вообще не определены в описании.
И сказала (она... критика которая), что "слишкам многа букаф" и нужны картинки.
Встречайте:



Итак, у нас 4 вида пользователей:
Гость, Катальщик, Сусанин и Администратор.
Гость - хочет подобрать себе маршрут для катания. Остальное ему запрещаем. Это его основная цель.
Катальщик - так же имеет желание подобрать себе маршрут для катания. НО, он так же хочет высказывать свои мысли по поводу маршрута. Хочет сам собирать группы для покатушек. Поэтому мы его заставляем регистрироваться.
Сусанин - у него 2 почти равные цели: он хочет кататься и водить группы. Поэтому он - катальщик. Но он хочет сам планировать куда ехать и вести группы в неизведанные места. Поэтому он создает и следит за своими маршрутами.
Администратор - он хочет что б у всех все было хорошо. Поэтому он следит за сайтом. Пока этот пользователь является и обычным пользователем... но несколько условно, потому что не гоже под ним заходить на сайт в повседневной жизни... как root под *nix-системами.

Неактивированный пользователь

Умная Луценко Лапулькина, раскритиковала роль "Неактивизированный пользователь".
Потребовала убрать...
Раскритиковала сложную систему регистрации на сайте... потребовала упросить.
Думаю что делать...

среда, 2 июля 2008 г.

Выделена новая роль

По результатам описания UC выявлена новая роль.
Точнее похожая была раньше, но я ее убрал за "ненадобностью".

"Некативированный пользователь".
Пользователь имеет профиль.
Может зайти на сайт и отредактировать профиль.
Остальные права имеет такие же как Гость.

Внесены соответствующие изменения в сообщение о выделенных ролях.
Роли сайта
Функции сайта

UC: Гость: Регистрация на сайте

Регистрация пользователя на сайте

В данном варианте использования я объединил регистрацию данных пользователя и подтверждение регистрации. Так что этот UC можно считать белым. Но так, думаю, удобнее.
Основной сценарий:
1. "Гость" ввел адрес регистрационной формы в браузере ИЛИ выбрал соответствующий пункт меню.
2. SuD отображает регистрационную форму.
3. Пользователь вводи регистрационные данные на форме. Список будет детализироваться по ходу работы.
Основными являются логин, пароль, Никнейм, почта.
4. Система сохраняет данные пользователя.
5. Система высылает "регистрационный код" на почту пользователя.

6. Пользователь вводит регистрационный код.
(Как вариант это может быть переход по специальным образом сформированной ссылке).
7. Система активизирует аккаунт пользователя.
8. Система сразу считает его "катальщиком". (не надо осуществлять вход в систему).
Расширения:
4а. Не все необходимые данные введены:
4а1. Система уведомляет пользователя о необходимости доввести данные.
4а2. Система переходит к шагу 2. Ранее введенные данные сохраняются.
4б. Такой логин или ник уже есть в системе:
4б1. Система просит сменить ник или логин.
4б2. Система переходит к шагу 2. Ранее введенные данные сохраняются.
5а. Система не может отослать данные на почту, потому что не верный email:
5а1. Система ничего не делает.
6а. Пользователь вводит не верный код:
6а1. Система уведомляет пользователя что код не верный и просит ввести код повторно.
6б. Пользователь несколько раз вводит неверный код:
6б1. Система высылает на почту новый код.

UC: Гость: Просмотр отчета о "большой" покатушке

Просмотр отчета о "большой" покатушке

Думаю необходимо только для того, что бы заинтересовать людей проехать по маршруту.
Основной сценарий:
1. Пользователь ввел адрес конкретного отчета в браузере или выбрал ссылку получения отчета из списка отчетов о "больших" покатушках.
2. SuD показывает пользователю следующую информацию о покатушке:
2.1. Название.
2.2. Карту.
2.3. "Необходимую" информацию о маршруте. (еще не знаю точно что буду тут показывать).
2.4. "Официальный" отчет.
2.хх. Комментарии, пользователи, фотографии и др. информация не отображается.
Расширения:
1а. Запрошенной покатушки не существует:
1а1. SuD выдает сообщение об ошибке о невозможности найти покатушку.
2а. Не все данные введены:
2а1. SuD игнорирует невведенные данные, отображая вместо них "пробелы".

UC: Гость: Просмотр информации о маршруте

Просмотр информации о маршруте

Основной сценарий:
1. Пользователь ввел адрес конкретного маршрута в браузере или выбрал ссылку получения информации о маршруте из списка маршрутов.
2. SuD показывает пользователю следующую информацию о маршруте:
2.1. Название.
2.2. Карту.
2.3. Точки маршрута.
2.4. Описание маршрута.
2.5. Фотографии маршрута.
2.6. Список "больших" покатушек.
2.хх. Комментарии, пользователи и др. информация не отображается.
Расширения:
1а. Маршрут не публичный:
1а1. SuD все равно переходит к п.2. Закрывать от просмотра непубличные маршруты считаю лишним. Непубличные маршруты не показываются в списке маршрутов, считаю этого достаточным.
1б. Маршрута не существует:
1б1. SuD выдает сообщение об ошибке о невозможности найти маршрут.
2а. Не все данные введены:
2а1. SuD игнорирует невведенные данные, отображая вместо них "пробелы".

UC: Гость: Просмотр списка маршрутов

Просмотр списка маршрутов

Основной сценарий:
1. Пользователь ввел адрес списка маршрутов в браузере или выбрал соответствующий пункт меню на сайте.
2. SuD показывает пользователю опубликованные маршруты.
Расширения:
2а. Нет опубликованных маршрутов:
2а1. Система отображает пустой "макет" сайта.

UC: Гость: Просмотр списка изменений на сайте

Просмотр списка изменений на сайте. (Главная)

Предусловия: Пользователь не зарегестрирован на сайте и имеет роль "гость".
Основной сценарий:
1. "Гость" ввел адрес списка новостей в браузере ИЛИ ввел корневой адрес сайта ИЛИ выбрал соответствующий пункт меню.
2. SuD отображает список новостей за последние пару месяцев или последние 2, список всех новых маршрутов, список зерегестрированных покатушек.
Расширения:
2а. Нет новостей для отображения:
2а1. Система формирует пустой "макет" сайта.

вторник, 1 июля 2008 г.

Шаблон варианта использования

Название варианта использования. Указывается на фоне цвета уровня.

Роль: [роль пользователя]
Триггер: [причина запуска сценария]
Предусловия: [априори выполненные условия]
Основной сценарий: [нумерованная последовательность шагов, приводящая пользователя к Цели]
Результат: [результат выполнения основного сценария, если он требует пояснений]
Расширения:[список проблем, которые могут возникнуть при прохождении основного сценария, и их решения]




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

В основном сценарии, "условные конструкции" должны быть сформулированы так, что б по состоянию "истина", выполнение переходило к следующему шагу.
Расширения нумеруются следующим образом: шаг основного сценария, где возникла "ошибка", буква по порядку "номер ошибки". Дальше идет тот же номер и шаги, принятые по исправлению ошибки.


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



Пример сценария.




Вход пользователя в систему

Роль: Гость
Триггер: Пользователь ввел в браузере адрес страницы "логина" или любую другую страницу, с которой имеется возможность осуществить "вход".
Предусловия: нет.
Основной сценарий:
1. Гость вводит логин и пароль.
2. Система проверяет корректность логина и пароля.
3. Система выдает "cookie".
Пользователь имеет cookie и считается "вошедшим" в систему.
Расширения:
2а. Логин и пароль не верны:
2а1. SuD предлагает Гостю повторно ввести логин и пароль.
2a2. Пользователь вводит логин и пароль. И повторяет попытку входа в систему.
2а3. SuD переходит к шагу 2 основного сценария.
2б. Логин и пароль не верны:
2б1. SuD предлагает пользователю зарегистрироваться.
2б2. Пользователь соглашается.
2б3. SuD переходит на страницу регистрации.
2в. Логин и пароль не верны:
2в1. SuD предлагает восстановить пароль.
2в2. SuD задает контрольный вопрос и запрашивает почту пользователя.
2в3. Пользователь вводит ответ на контрольный вопрос и вводит свой email.
2в4. SuD проверяет введенные данные пользователя.
2в5. SuD высылает пароль на почту пользователя.
2в4а. Введенные данные пользователя не верны:
2в4а1. Система ругается и выводит "главную страницу".
3а. SuD не смог выдать cookie (отключены у пользователя и т.д.):
3а1. SuD выдает ошибку.
***3а1. (как вариант на очень далекое будующее) SuD переходит на альтернативный вариант. Например, ведение session_id в строке адреса.

Варианты использования

Пришло время начать описывать функционал сайта. Функционал сайта буду описывать в виде Вариантов использования (Use-Case или User-Story). Причем я буду использовать англоязычный термин User-Story, так как мне это намного больше нравиться.

Собственно, с началом нового месяца, начнем описывать систему :)) (во всяком случае, сейчас еще не 2е число, а очень позднее первое) :)))


В качестве учебника по написанию этих user-story я использовал Коберна "Современные методы описание функциональных требований к системам". Как смогу буду придерживаться его.

В качестве рецензора (или как-там-будет-по-умному), надеюсь, выступит Антон К. Душутин (читать как Антон-ка :)), и сможет найти время, что б высказать много умных замечаний.


Итак, некоторые моменты написания user-story (в основном, перефразированные предложения из книги):

Определение SuD (System under Discussion) - рассматриваемая система.

Актер - человек (или другая система) взаимодействующий с SuD.

Что такое вариант использования?
"Вариант использования описывает поведение системы при ответах на запросы одного из участников".
Таким образом, при описании вариантов использования, скорее всего, будет участвовать "оба" участника (SuD и Актер). Если этого не видно в системе, вариант использования, скорее всего, описан не правильно.

Обязательно буду указывать уровень цели.
Градацию возьму из Коберна. (но иногда буду от нее отступать для удобства описания).
Уровень цели пользователя.
(Голубой уровень) (поскольку у Коберна ассоциации с морем, я решил, что аквамарин - хороший цвет :)))

Уровень варианта использования, когда цель достигается одним актером за "одну транзакцию", т.е. без разрыва сессии, без долгого ожидания реакции системы и т.д.
В качестве примера:
1. Пользователь хочет посмотреть описание маршрута. Для этого он заходит на сайт, открывает список маршрутов, выбирает нужный, смотрит. Таким образом он выполнил все действия в одной транзакции.
2. Пользователь хочет зарегистрироваться на сайте. Для этого, заходит на сайт, вводит информацию о себе, запрашивает подтверждение. Ждет подтверждения по почте. Когда подтверждение пришло, вводит подтверждающий код. Он становиться зарегистрированным пользователем. Таким образом, пользователь не может выполнить весь процесс за одну транзакцию. Их две с точки зрения SuD: первая - ввод регистрационных данных, вторая - ввод подтверждающего кода.
С точки зрения описания вариантов использования, это плохие примеры, так как они не отражают работу SuD. Приведены только для демонстрации уровня цели


Поступила критика по поводу этих примеров.


Луценко Лапуля (15:22:23 3/07/2008)
нормальные у тебя примеры!!!

Луценко Лапуля (15:23:02 3/07/2008)
типа вот на витрине стоит сапог с отломанным каблуком, но вы не пугайтесь, в коробках у нас с каблуками сапоги. этот, так.., для примера стоит



Мнда... нельзя не согласиться. Привел примеры уровня пользователя, и потом сам же кинул их в уровень индиго (см. ниже).
Поскольку переписывать примеры мне лень, то скажу, что это просто примеры Use-case уровня индиго.
Поясню: ЦЕЛЬЮ пользователя при работе с сайтом НЕ может быть регистрация на сайте. Поскольку регистрация ради регистрации - глупость. Голубым этот уровень никак быть не может. Целью пользователя может являться просмотр маршрута, создание и т.д.


Обобщенный уровень.
(Белый уровень.) (ну... так... сероватый :))

Уровень общего варианта использования для достижения некой цели при помощи SuD. Тут может быть разрывы во времени, может участвовать несколько Актеров, обычно, ссылается на другие варианты использования.
В качестве примера:
Необходимо организовать выезд по маршруту, который еще не введен в базу.
"Сусанин", вводит маршрут в базу, "Кататель" регистрирует "покатушку".
Как мы видим, взаимодействовали несколько Актеров, использовались другие варианты использования, такие как "ввод маршрута в базу", "регистрация "покатушки"".

Уровень подфункции.
(Уровень индиго) (ну, идниго не прокатил, взял Lavender, хотя он море мне уже не напоминает, но - сойдет!)

Ну, тут, думаю, уже понятно. Некая детальная информация. Например, сюда я отнесу "вход в систему".
Пользователь вводит логин/пароль. Система проверят логин/пароль. Система считает пользователя зарегистрированным. (с точки зрения технической реализации - "открывает сессию" и выдает cookie).
Данный вариант использования не приводит пользователя к Цели. Т.е. не позволяет выполнить какое-либо действие, полезное для пользователя. Ведь регистрироваться ради регистрации - глупо.

Раскроем книжку, почитаем что я еще хотел вам переписать упомянуть.

Триггер некое событие, которое приводит в действие вариант использования. Обычно это будет "пользователь ввел нужную строку запроса в браузере или выбрал соответствующий пункт меню.

Предусловия условия, которые априори выполнены при старте этого Варианта использования. Обычно это будет "пользователь зарегистрирован в системе".

Основной сценарий последовательность успешных шагов, приводящая Актера к Цели.

Расширения описания исключительных ситуаций по шагам. Т.е. если шаги "основного сценария" были не успешны.

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



Еще пара слов о соглашениях об именах.
Если я буду описывать вариант использования, то заголовок в блоге у него будет следующий:
UC: <роль>: <название>.
Список ролей смотри в прошлых сообщениях.

Ну... теперь осталось описать шаблон, которого я буду стараться придерживаться.