Wednesday 10 August 2011

Хеш код для папки (MD5).

Сьогодні я хочу написати дещо про задачу з якою стикнувся на роботі. Суть її в тому що мені треба промоніторити чи змінились файли в конкретній папці і при наявності будь яких змін вивести повідомлення і тд. Відслідковувати необхідно сам факт зміни даних в каталозі отож логічно було зроблено припущення що по папці нам необхідно генерувати якийсь хешкод і порівнювати його при заупуску програми.
Для діставання хешу файлу досить скоро було знайдено рішення, але нічого схожого бля папки не було…

try
{
    FileStream file = new FileStream(fileName, FileMode.Open);
    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] retVal = md5.ComputeHash(file);
    file.Close();
 
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < retVal.Length; i++)
    {
        sb.Append(retVal[i].ToString("x2"));
    }
    return sb.ToString();
}
catch (FileNotFoundException e)
{
    Log.Debug(e.Message);
}

Отож якщо в нас в папці 100 файлів ми отримуємо 100 хешів і їхнє зберігання та порівняння не є приємлимим рішенням. Після недовгих роздумів було знайдено просте як дошка рішення яким і хочу з вами поділитись, суть його заключається в тому що ми можемо взяти хеш або для стріма або для масиву байт, в даному випадку ми беремо всі хеші для файлів і обєднуємо їх, після чого цю стрічку перетворюємо в масив байтів і генеруємо для неї свій хеш. Ось як виглядає код:
public string GetMD5ForFolder(IEnumerable<FileInfo> listOfFiles)
       {
           string result = string.Empty;
           try
           {
               foreach (FileInfo file in listOfFiles)
               {
                   result = result + GetMD5HashFromFile(file.FullName);
               }
 
               MD5 md5 = new MD5CryptoServiceProvider();
               byte[] computeHash = md5.ComputeHash(Encoding.Default.GetBytes(result));
 
               StringBuilder sBuilder = new StringBuilder();
               for (int i = 0; i < computeHash.Length; i++)
               {
                   sBuilder.Append(computeHash[i].ToString("x2"));
               }
               return sBuilder.ToString();
           }
           catch (ArgumentNullException ex)
           {
               Log.Error(ex.Message);
               throw new ServiceAgentsException(ex.Message);
           }           
       }
Я не тестував це рішення на великих каталогах, але для каталогу з кількістью файлів до 100 я думаю що воно працюватиме без проблем. Як завжди буду радий почути будь які коменти що до коду і побачити кращі варіанти реалізації цієї задачі.

Tuesday 9 August 2011

Що необхідно знати для того щоб стати Intermediate Software Developer.

Доброго дня всім.

Сьогодні я б хотів поговирити про карєрне зростання і підхід до нього в моїй компанії. Отож компанія досить велика і можливості зростання теж досить хороші, для цього навіть налагоджена відповідна система і якщо ви хочете перейти на наступну позицію по карєрній мапі то ви можете ознайомитись з усіма необхідними вимогами, підготуватись і назначити дату для провірки вашої відповіднсті даній позиції. В моєму випадку наступною для мене позицією є Intermid Software Devoloper. Окрім загальних знань по технологіям з якими я працюю також необхідно як мінімум одна презентація, знання англійської на рівні Intermediate low і як мінімум 2 роки досвіду.

Що до знань яких вимагає дана позиція я напишу трохи пізінше а на даний час давайте розглянемо інші деталі. З досвідом все зрозуміло і чесно кажучи досить серйозно, дуже рідко можна піднятись по карєрній мапі немаючи відповідного досвіду, тому тут вище голови стрибнути практично неможливо, щодо англійської то тут дещо краща ситуація і на скільки я знаю якщо рівень трішки не дотягує то можна просто пообіцяти його підтягнути і попрацювати над ним вже на позиції інтерміда. Презентація це в певному сенсі найпростіша частина, для переходу на інтерміда потрібна як мінімум презентація для власної команди. Я вирішив ознайомити команду з ASP MVC 3. На скільки я знаю майже ніхто з тімки окрім мене реального досвіду в даній технології немає тому з однієї сторони зможу подати корисний матеріал а з іншого ймовірність що завалять компетентними питаннями невелика ) .

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

Design – OOD(Обєктно Орієнтований Дизайн)

CL1 (Beginner)

Abstraction

Encapsulation

Inheritance vs. Aggregation

Modularity

Polymorphism

Types vs. Classes

Abstraction Qualities (cohesion, coupling, etc)

CL2 (Competent)

GoF Design Patterns

Architectural Patterns: Layered Architecture

Architectural Patterns: MVC

Architectural Patterns: SOA and EDA

Architectural Patterns: IoC

.Net

CL1 (Beginner)

System types (value, reference, boxing, generic, type forwarding)

Declare classes, interfaces, class members, static and member

Common Exceptions an exception handling

Type conversion

Equality comparison

System collections

Generic collections.

Events and delegates.

Strings and StringBuilder

Configuration files (System.Configuration namespace)

Serializers, serialize/deserialize objects to binary format

Serialization, serialize/deserialize objects to XML format

Files and Folders (System.IO namespace)

Streams (Stream, FileStream, etc.)

TextReader, TextWriter

XML manipulations

CL2 (Competent)

Specialized collections (CollectionsUtils BitVector32, HybridDictionary etc.)

Implement special .NET interfaces (IConvertible, IDisposable, IComparable etc.)

Managing Application domains

Custom serialization

Custom attributes

Garbage collection

Expose COM components to the .NET Framework and .NET Framework components to COM.

SQL

CL1 (Beginner)

DDL for tables, relationships, primary keys, foreign keys

Data Types (character string, binary string, exact numbers, approximate numbers, date and time, boolean, null)

Data manipulation (insert, update, delete)

Retrieving data (simple select statement)

Using of standard SQL functions

Multi-table queries (inner joins, outer joins)

CL2 (Competent)

Creating and modifying database objects (indexes, views)

Using complex criteria (ORDER BY, GROUP BY, HAVING, IN, ... )

SQL operators

Sessions, transactions, locks

Implementing of custom SQL functions

SQL procedural language, stored procedures, triggers

Retrieving data; Combining the results of multiple queries (union, excep, subqueries)

Handling errors in SQL statements

Cursors

Verification - Automated Testing - .Net

CL1 (Beginner)

Unit testing fundamentals and elementary tests

CL2 (Competent)

Organizing and building unit tests (Nunit, VS 2008, mbUnit)

Managing test suites

Working with test data

Running unit tests

Reporting unit results

Mocks/Stubs (Nmock, POCMock, etc.)

Code Coverage Tools (NCover)

Design – Modeling

CL1 (Beginner)

UML: Basic Diagram Types

UML: Use Case Diagram (Essentials)

UML: Class Diagram (Essentials)

Entity Relationship Diagrams

Data Flow Diagrams

Refactoring

CL1 (Beginner)

Refactoring Concept (what/when/why)

Moving Features Between Objects (basic)

Move Method

Move Field

Organizing Data (basic)

Encapsulate Field

Encapsulate Collection

Composing Methods (basic)

Extract Method

Inline Method

Inline Temp

Replace Temp with Query

Split Temporary Variable

Simplifying Conditional Expressions (basic)

Decompose Conditional Expression

Consolidate Conditional Expression

Consolidate Duplicate Conditional Fragments

Remove Control Flag

Replace Conditional with Polymorphism

Concurrency - .Net

CL1 (Beginner)

Understand CLR threading

Using ASync methods

lock keyword or System.Threading.Monitor

Mutual exclusion and condition synchronization problems

Deadlock problem

В даний список я виніс основні як на мене вимоги, але токож до нього входять вимоги по якості коду, англійскій мові, роботі з SVN репозиторієм і кінцевою інтеграцією. Список як бачите досить великий і я по можливості буду додавати цікавий матеріал з яким зустрінусь по мірі підготовки. На даний час я маю реальний досвід у розробці і відповідно в деяких темах мені лише треба навести порядок. В основному підготовка йде за принципом памятаю непамятаю і незнаю. Відповідно відмічаю кожен пункт, після чого переходжу до навчання. Щодня по можливості перечитую ту чи іншу тему роблю невеличкі записи і обговорюю прочитане з іншими девелоперами…

Успіхів у підготовці!

Saturday 30 July 2011

Що таке патерни в програмуванні (II)

В минулому пості, я намагався обяснити що таке патерни в програмуванні, я назвав три види патернів і привів приклад патерну “стратегія”. Метою цього посту буде заповнити пробіли які залишились та виправити деякі проблеми з кодом.

Теорія

Патерн – це підхід до вирішення частих задач в програмуванні.
Програміст пишучи код може організувати його так як треба навіть незнаючи про патерни але це зазвичай займає більше часу, тому всі найбільш часті проблеми та способи їх вирішення були описані в книзі “банди чотирьох”. До цього їх використовували але автори першими додумались обєднати найкращі практики програмування в одній книзі за що й здобули всесвітню славу. Серед основних переваг які дає знання патернів, є те, що вам не треба довго описувати те, що ви хочете зробити і як ви це будете реалізовувати, вам необхідно лише вказати назву патерну і все, для всіх зразу ж стане зрозуміло що ви маєте на увазі. Також ці знання дають можливість краще зрозуміти сам принцип роботи деяких механізмів .NET. Дуже часто просто їхнє перечитування не дає жодного ефекту до того часу, поки ви самі не захочете їх реалізувати в конкретному прикладі…
Отож повертаємось до типів патернів, в нас як я вже писав є три типи: породжувальні, поведінкові та структурні.
Породжувальні патерни використовують для створення екземплярів обєктів. Наприклад іноді для більшої гнучкості створення всіх обєктів ми виносимо в один класс. Маючи доступ до цього класу в любому місці програми ми можемо отримати необхідний нам обєкт. Це знову ж таки в простих прикладах буде вимагати багато “лишнього” коду, але такі практики досить часто використовуються в великих системах і саме там вони дозволяють полегшити життя.
Поведінкові патерни використовують для того щоб запрограмувати певну поведінку обєкту, наприклад ця ж стратегія, в якій працюючи з обєктом приведеним до базового ми можемо досягати різної поведінки, хочемо добавити новий функціонал – без проблем пронаслідувались від базового класу, реалізували те що нам треба і добавили в список з іншими обєктами.
Структурні патерни описують те як можна на основі декількох малих обєктів створити більший, призначений для конкретної цілі.
Повертаємось до нашого славнозвісного проекту. Сьогодні я постарюсь обяснити чому той “лишній код” насправді не є лишнім і ми попробуємо виділити з нашої прорами той код який би можна було перевикористовувати.
Отож спочатку приведемо наш код до такого вигляду:
Program.cs
using System;
 
namespace StringValidator
{
    internal class Program
    {
        private static string[] strings = { "one", "two", "three", "four" };
 
        private static void Main(string[] args)
        {
            Console.WriteLine("Введіть одне з правил валідації (length, space, other)");
 
            string validationType = Console.ReadLine();
 
            Validate(validationType);
        }
 
        private static void Validate(string validationType)
        {
            Logic logic = new Logic();
            BaseValidation validator = logic.GetRule(validationType);
 
            foreach (string s in strings)
            {
                validator.CheckString(s);
            }
        }
    }
}
BaseValidation.cs
namespace StringValidator
{
    public abstract class BaseValidation
    {
        public abstract bool CheckString(string s);
    }
}
Logic.cs
namespace StringValidator
{
    public class Logic
    {
        public BaseValidation GetRule(string pravylo)
        {
            if (pravylo == "length")
            {
                return new LengthValidation();
            }
            if (pravylo == "space")
            {
                return new SpaceValidation();
            }
            if (pravylo == "other")
            {
                return new OtherValidation();
            }
            return null;
        }
    }
}
LengthValidatoin.cs
using System;
 
namespace StringValidator
{
    public class LengthValidation : BaseValidation
    {
        public override bool CheckString(string s)
        {
            Console.WriteLine("Check length");
            return true;
        }
    }
}
SpaceValidation.cs
using System;
 
namespace StringValidator
{
    public class SpaceValidation: BaseValidation
    {
        public override bool CheckString(string s)
        {
            Console.WriteLine("Check space");
            return true;
        }
    }
}
OtherValidation.cs
using System;
 
namespace StringValidator
{
    public class OtherValidation: BaseValidation
    {
        public override bool CheckString(string s)
        {
            Console.WriteLine("Check other");
            return true;
        }
    }
}
В принципі я лише перейменовував змінні та назви класів, так що відслідкувати, що де змінилось важко не буде.
Тепер попробуємо з нашого проекту виділити ту частину яка б відповідала за валідацію. Нашим завданням буде розробка бібліотеки, яка б могла валідувати стрічки по певним правилам. Самі правила можуть добавлятись до неї динамічно в залежності від того що нам треба в даному випадку. Отож додаємо новий проект до солюшина типу ClassLibrary і називаємо його StringValidatorLib. В нього переносимо всі файли окрім Program.cs . В перенесених файлах міняємо неймспейси, для того щоб вони відповідали новій локації.
В результаті ми отримуємо :
image
Не забуваємо про референс з нашої консольної аплікації на нашу бібліотеку.
Тепер давайте зробимо наш клас з логікою універсальним, щоб він нічого не знав про існуючі рули.
using System.Collections.Generic;
 
namespace StringValidatorLib
{
    public class Logic
    {
        Dictionary<string, object> rules = new Dictionary<string, object>(); 
 
        public void AddRule(string ruleName, object rule)
        {
            if(!rules.ContainsKey(ruleName))
            {
                rules.Add(ruleName, rule);
            }
        }
 
        public BaseValidation GetRule(string ruleName)
        {
            if(rules.ContainsKey(ruleName))
            {
                return (BaseValidation)rules[ruleName];
            }
            return null;
        }
    }
}
Тепер ми зможемо додавати нові рули і отримувати рули по назві. Погодьтесь це досить гнучко так як наша логіка нічого про те з якими обєктами вона працює не знає(далі можна буде приймати не object а нащадків BaseValidation і це забезпечить нас від хибних обєктів в словнику).
Для того щоб використати нашу логіку нам тепер спочатку треба зареєструвати всі необхідні правила, тобто ми можемо на підставі певних умов додавати ті чи інші рули при тому логіка в нас абсолютно незмінна і відповідно ймовірність нових помилок зменшується в рази. Виглядає це наступним чином:
using System;
using StringValidatorLib;
 
namespace StringValidator
{
    internal class Program
    {
        private static string[] strings = { "one", "two", "three", "four" };
 
        private static void Main(string[] args)
        {
            Console.WriteLine("Введіть одне з правил валідації (length, space, other)");
 
            Logic logic = new Logic();
            logic.AddRule("length", new LengthValidation());
            logic.AddRule("space", new SpaceValidation());
            logic.AddRule("other", new OtherValidation());
 
            string validationType = Console.ReadLine();
 
            Validate(validationType);
        }
 
        private static void Validate(string validationType)
        {
            Logic logic = new Logic();
            BaseValidation validator = logic.GetRule(validationType);
            if (validator != null)
            {
                foreach (string s in strings)
                {
                    validator.CheckString(s);
                }
            }
        }
    }
}
Також слід зазначити що навіть у випадку втрати коду бібліотеки, ми всеодно зможемо розширювати її новими правилами а це дуже великий плюс.
PS
Це далеко не вершина оптимізації та гнучкості і тут ще багато чого можна спростити та вдосконалити але на даному кроці я думаю варто зупинитись, тому що метою є показати те як застосовують паттерни і надіюсь і цією задачою я справився. На часте питання “як взанти який патерн використати?” відповідь досить проста -- знаючи їх просто треба знати. Якщо щось висвітлив недостатньо буду радий доповнити і тд.