.
Методика программной инженерии. Урок 2. Культура кода.
Автор megabax   
15.11.2020 г.
New Page 1

Методика программной инженерии. Урок 2. Культура кода.

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

Итак, первый набор правил (это требования к оформлению лабораторных работ в одном из ВУЗ-ов):

  • Структура программы в соответствии с венгерской нотацией.

  • На каждые три строки комментарий (в крайнем случае на четыре).

  • На каждый цикл и на каждое ветвление свой комментарий.

  • В начале любой процедуры или функции текст, который описывает: назначение этой процедуры или функции; параметры, передаваемые в данную подпрограмму; если это функция, которая что-то возвращает, описание возвращаемого результата.

  • Имена переменных, а также процедур и функций должны быть осмысленными, в конце имени переменной ставить ее тип, например, Integer, Double, Float, String.

  • Даже в цикле не следует использовать однобуквенные переменные, например, J или I. Для одномерных циклов допускается использовать переменную с именем Index.

Пример оформления программы в соответствии с этими правилами (лабораторная работа по исследованию переполнения стека при использовании рекурсивной функции, программа выполняет заливку заданного контура):

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.IO;

 

namespace StackOverflowTest

{

    public partial class MainForm : Form

    {

 

        /// <summary>

        /// Записывает отладочную информацию в файл.

        /// </summary>

        protected StreamWriter loggerStreamWriter;

 

        /// <summary>

        /// Указатель на область рисования.

        /// </summary>

        protected Bitmap pictureBitmap;

 

        /// <summary>

        /// Счётчик итераций.

        /// </summary>

        protected uint iterationUint = 1;

 

        /// <summary>

        /// Цвет границы.

        /// </summary>

        protected Color borderColor = Color.White;

 

        /// <summary>

        /// Цвет, которым заполняем область.

        /// </summary>

        protected Color fillingColor;

 

        /// <summary>

        /// Буфер для эмуляции переполнения стека

        /// </summary>

        unsafe struct Foo

        {

            public fixed int emulationBufferArrayFixedInt[200];

        }

 

 

        /// <summary>

        /// Конструктор формы, в которой происходит рисование.

        /// </summary>

        public MainForm()

        {

            //Инициализирует компоненты формы

            InitializeComponent();

 

            //Открывает потковый ввод-вывод, инициализирует фоновый рисунок с областью, которую нужно залить.

            loggerStreamWriter = new StreamWriter("log.log");

            var strStreamReader = new StreamReader("D:\\1\\pict5.png");

            main_panel.BackgroundImage = Bitmap.FromStream(strStreamReader.BaseStream);

 

            //Связывает указатель с физической областью заливки

            pictureBitmap = (Bitmap)main_panel.BackgroundImage;

        }

 

        /// <summary>

        /// Задаёт выбранному пикселю цвет.

        /// </summary>

        /// <param name="xCoordInt">Координата по оси Х</param>

        /// <param name="yCoordInt">Координата по оси У</param>

        protected void SetPixel(int xCoordInt, int yCoordInt)

        {

            //С помощью встроенных средств рисования на объекте Bitmap выполняем смену цвета

            pictureBitmap.SetPixel(xCoordInt, yCoordInt, fillingColor);

        }

 

        /// <summary>

        /// Сравнивает цвет границы и цвет выбранной точки.

        /// </summary>

        /// <param name="xCoordInt">Координата по оси Х</param>

        /// <param name="yCoordInt">Координата по оси У</param>

        /// <returns>Истина - если цвета не совподают, иначе - возвращает ложь.</returns>

        protected bool CompareBool(int xCoordInt, int yCoordInt)

        {

            //С помощью встроенных средств рисования на объекте Bitmap получаем цвет нужного пикселя.

            //Для удобства сравнения конвертируем их в число.

            return pictureBitmap.GetPixel(xCoordInt, yCoordInt).ToArgb() != borderColor.ToArgb();

        }

 

        /// <summary>

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

        /// при этом вызывается переполнение программного стека.

        /// </summary>

        /// <param name="xCoordInt">Координата по оси Х</param>

        /// <param name="yCoordInt">Координата по оси У</param>

        protected void RecursiveFill(int xCoordInt, int yCoordInt)

        {

            try

            {

                //Создаем большой буфер для эмуляции переполнения стека

                //var tempvarForEmulationStackOverflowFoo = new Foo();

 

                //Записываем в лог-файл строку с отладочной информацией

                loggerStreamWriter.WriteLine(iterationUint + ":" + xCoordInt + "," + yCoordInt);

 

                //Увеличиваем счётчик итераций

                iterationUint++;

 

                //Если дошли до границы, то выходим

                if (CompareBool(xCoordInt, yCoordInt)) return;

 

                //Иначе меняем цвет пикселя на нужный

                SetPixel(xCoordInt, yCoordInt);

 

                //Заставляем элемент перерисовать свою область

                main_panel.Refresh();

 

                //Идём в глубь рекурсии

                RecursiveFill(xCoordInt, yCoordInt + 1);

                RecursiveFill(xCoordInt, yCoordInt - 1);

                RecursiveFill(xCoordInt - 1, yCoordInt);

                RecursiveFill(xCoordInt + 1, yCoordInt);

            }

 

            //Пытаемся отловить ошибки

            catch (System.Exception e)

            {

                //Выводим сообщение и прервем выполнение

                MessageBox.Show(e.Message, e.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);

                return;

            }

        }

 

        /// <summary>

        /// Обработчик кликания мышкой

        /// </summary>

        /// <param name="sender">Источник</param>

        /// <param name="e">Параметры</param>

        private void main_panel_MouseClick(object sender, MouseEventArgs e)

        {

            //задаём цвет для рисования

            fillingColor = Color.Red;

 

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

            RecursiveFill(e.X, e.Y);

        }

 

    }

}