56
Якісний код Аудиторія: розробники Олександр Павлишак, 2010 [email protected]

Clean code (UA)

Embed Size (px)

Citation preview

Якісний код

Аудиторія: розробники

Олександр Павлишак, 2010

[email protected]

Чому «якісний код»?

• Maintainability

• >50%

– Зміни

– Багфікси

– Підтримка

• Ітеративні методи розробки

Maintainability == $

Maintainability == Якісний код

Якісний код == $$

Стандартні питання до розробника

• Що робить система, коли відбувається Х?

• Як конкретно працює функціональність Y?

• Звідки дістаються опції Z?

• Скільки часу займе реалізувати Х?

Де відповіді?

• В специфікації

• Якщо у вас вона є ;)

• В коді

• Код є завжди

• Only the Code Tells the Truth

В реальному житті

• Неякісний код сповільнює розробку

• Щоб дотриматись графіка, розробники швидко пишуть неякісний код

Парадокс!

Якісний код

• Як писати якісний код?

• Не пишіть поганий код

Імена

Осмислені іменa

public void Copy(char[] a1, char[] a2){

for (int i = 0; i < a1.Length; i++){

a2[i] = a1[i];}

}

Осмислені іменa

public void Copy(char[] source, char[] destination){

for (int i = 0; i < source.Length; i++){

destination[i] = source[i];}

}

Ім’я відображає наміри і суть

• d, tot, res, srv, c, cc, c1, c2 – BAD!

• createdDate, totalCount, result, storageService, characters – GOOD!

• Довге змістовне ім’я краще короткого незрозумілого

• Змістовне ім’я краще чисельної константи

Константи

...if (!resource.Exists){

result = 404;}else if (resource.WasMoved){

result = 301;}else if (user == null){

result = 401;}...

Константи

...if (!resource.Exists){

result = HttpStatusCode.NotFound;}else if (resource.WasMoved){

result = HttpStatusCode.MovedPermanently;}else if (user == null){

result = HttpStatusCode.Unauthorized;}...

Коротке ім’я – коротка видимість

int[] elements = …for (int i = 0; i < elements.Count(); i++){

elements[i] = elements[i] * 2;}

Послідовні імена

• Get, Fetch, Retrieve, Obtain, AcquireFeed feed = FeedService.ObtainSyndicationFeed();if (feed.IsValid){

Storage feedStorage = GetFileStorage(path);List<Post> posts = feed.RetrievePosts();feedStorage.Save(posts);

}

• Виберіть одне і послідовно дотримуйтесь його

Надлишковість

• nameString, customersArray

• sName, iCount, arrCustomers

string nameString = "Kenny";string[] girlsArray = FindAllAttractiveGirls();

FileStream ouputFile = File.Open("c:\\autoexec.bat");Url urlToBashOrg = new Url("http://bash.org.ru");

Імена з предметної області

List<Person> list =

country.GetAllUnemployedPeople();if (list.Count > 1000 * 1000){

presidentFacebookPage.CurrentStatus =

"Still working...";}

Імена з предметної області

List<Person> unemployedPeople =

country.GetAllUnemployedPeople();if (unemployedPeople.Count > 1000 * 1000){

presidentFacebookPage.CurrentStatus =

"Still working...";}

Імена з предметної області

if (pageIdsByUserId.Get(user.Id).ContainsKey(page.Id)) {...}

Map<int, Map<int, int>> pageIdsByUserId;

if (user.HasAccessTo(page)){...}

Типові імена

• Імена зміннихcustomer, currentPosition, isCompleted, result

• Імена класів – іменникиCustomer, UrlParser, Page, SortAlgorithm

• Імена методів – дієсловаGetCustomers(), CreateDirectory(), OpenSocket(), Save(), Close()

Ваш код будуть читати

Функції

Розмір має значення

• Максимальний: 20 рядків

• Оптимальний: <= 5 рядків

• Рівень відступів: <= 2

Коротка функція

if (user.IsAuthenticated){

SendProcessingCompletedEmail();}else{

RedirectUserToLoginForm(user);}

Сприяє документуванню коду

Рівень абстракції

• Функція виконує лише одну операцію

• Всередині функції – один рівень абстракції

Рівень абстракції

public void SynchronizeNewTasks(){

string database = "DBGLOBAL";if (user.HasAttribute("LOCAL")){

database = service.GetDatabaseBaseName() +"_LOCAL";

}if (user.Tasks.ContainsNewTasks()){

SaveNewTasks(database, user.Tasks.GetNewTasks());}

}

Рівень абстракції

public void SynchronizeNewTasks(){

if (user.Tasks.ContainsNewTasks()){

string database = GetDatabaseForUser(user);

SaveNewTasks(database,

user.Tasks.GetNewTasks());}

}

Аргументи функцій

• Без аргументів, Save() – найкращі :)

• Один аргумент, Send(address) – теж нічого

• Два, Copy(source, destination) – ОК

• Три – вже не дуже

• Більше – значно погіршують читабельність :(

Булеві аргументи

char[] source = ...char[] destination = ...Copy(source, destination, true);

:(

Булеві аргументи

List<Task> tasks = ...;Storage storage = ...;SaveNewTasks(tasks,

storage,true,false,false,true,true);

:(

Вихідні аргументи

byte[] fileContent = ...byte[] compressedContent;Compress(fileContent, out compressedContent);

Побічні ефекти

public bool IsPasswordValid(string userName, string password){

User user = Database.FindUserByName(userName);string encryptedPassword = Encryptor.Encrypt(password);bool result = user.EncryptedPassword == encryptedPassword;if (result){

Session.Initialize();}return result;

}

Shared state

• Мінімізуйте спільні дані

Exceptions замість кодів помилокif (FindUserByName(userName, out user) == STATUS_OK)

{if (Encrypt(password, out encryptedPassword) == STATUS_OK)

{bool result = user.EncryptedPassword == encryptedPassword;if (result)

{if (Session.Initialize() == STATUS_OK)

return true;else

LogError(...);}

...

Обробляйте помилки

...

// Catching exceptions is for communists

...

Wrong!

http://stackoverflow.com

Граничні умови

• Враховуйте граничні умови

• Тестуйте граничні умови

public void Sort(int[] array){

...}

Непотрібний код

• Функції, які не ніде не використовуються –видаляйте їх!

• Код, який ніколи не викликається –видаляйте його!

• Історія – в системі контролю версій

Здоровий глузд

• Код не повинен викликати здивування

• Поведінка має бути очевидна

• «Ви працюєте з чистим кодом, якщо кожна функція робить приблизно те, що ви очікуєте»

Ваш код будуть читати

Коментарі

...

/////////////////////////////////////// this is a well commented line

...

http://stackoverflow.com

Про коментарі

• Надавайте перевагу коду

• Коментуйте те, що не можна виразити в коді

• Проблема коментарів – супровід

• Неточні коментарі – гірше відсутності коментарів

• Коментарі не компенсують поганого коду

vs.

if (server.IsRedirectNeeded())…

// check if we should redirect to another URLif (server.HasResponse &&

server.HttpResponseCode == 301)…

vs.

bool isRedirectNeeded = server.HasResponse &&server.HttpResponseCode == 301;

if (isRedirectNeeded)…

Як коментувати

• Коментуйте публічний API

• Коментуйте внутрішній API тільки якщо він складний

• Не використовуйте коментар там, де можна використати функцію або змінну

• Видаляйте закоментований код

Класи

Single responsibility

• Класи повинні бути компактні

• Компактність визначається кількістю відповідальностей (responsibilities)

• Клас повинен мати одну відповідальність (single responsibility)

• Клас повинен мати одну причину для зміни

• Багато компактних класів

if-statements• Чим більше if-statements, тим більше

потенційних помилокpublic int GetHours()

{

if (_numberOfManuals <= SMALL)

{

if (_serviceType == "writing")

return 30 * _numberOfManuals;

if (_serviceType == "analysis")

return 10;

}

else if (_numberOfManuals <= MEDIUM)

{

if (_serviceType == "writing")

return (SMALL * 30) + (20 *

_numberOfManuals - SMALL);

if (_serviceType == "analysis")

return 20;

}

else //i.e. LARGE

{

if (_serviceType == "writing")

return (SMALL * 30) + (20 *

(MEDIUM - SMALL)) + (10 *

_numberOfManuals - MEDIUM);

if (_serviceType == "analysis")

return 30;

}

return 0; //Just a default fallback

for this contrived example

}

Ваш код будуть читати

Ще кілька думок

Робота

• Робота розробника не закінчується після того, коли програма запрацювала

• Після цього потрібно покращити структуру і чистоту коду

Правило

• Дотримуйтесь «правила бойскаута»

кожен раз коли ви працюєте з кодом, залишайте його трохи чистішим, ніж він був до цього

Це просто

• Переважно неважко покращити код

• Лише трохи переіменувать, введення нових функцій, трохи реструктуризації

• Це не rocket science

• Навіть якщо це не просто, ...

• ... це все одно цікаво

• Чому б цим не зайнятись?

Тести

• Чистка коду тісно пов’язана з тестами

• Тести – впевненість

Код – це ще не все

• Управління

• Маркетинг

• Команда

• Комунікації

• Бачення

• Замовник

Професіоналізм

• Будьте професіоналом

• Професіонали не пишуть неякісний код

• Якщо професіонал написав неякісний код, він його почистить

Книги

Code Complete, Steve McConnell

Clean Code, Robert C. Martin

Code Craft, Pete Goodliffe