Monthly Archives: Вересень 2014

Шлях до JavaScript майстерності

В 2013 почав писати оцейсписок, поки мій Python-проект ще не стартував, і мені дали тимчасово розгрібати купу JS:

  1. jQuery – ok, користуватись вмію, куди без нього.
  2. JavaScript: The Definitive Guide – за один раз не прочитаєш
  3. JavaScript: The Good Parts – за один раз прочитав, але варто перечитати.
  4. JavaScript Web Applications – можливо не найцікавіша книжка яку я читав, але з неї я дізнався про Spine.js, Backbone.js, underscore.js, та паттерн pub/sub.
  5. Прочитати про те як написання коду схоже на поезію
  6. Прочитати про об’єкт Class в Leaflet. Подумати що це варто було б окремою бібліотекою випускати, бо ж не в кожному проекті де треба ООП, треба карти…
  7. Почати модульно організовувати проекти, require.js
  8. Починати скрипти з декларації "use strict";.
  9. Пам’ятати про те що існує underscore.js, писати менше циклів.

А кінця шляху нема.

Нагадування 2014-го: І Smooth Coffescript варто дочитати.


Filed under: Кодерство, Павутина Tagged: JavaScript

Розробка керована питаннями

Чому розробка ПЗ це так важко? Тому що воно займає тисячі рядків коду і їх всіх важко набрати? Та ні, якраз навпаки, в дні коли в мене виходить написати сотні рядків коду я втомлююсь менше ніж коли пишу один, чи взагалі не пишу.

Важко звісно не набирати рядки, а ВИРІШИТИ які рядки потрібно набрати. В дні коли я пишу їх багато – це рішення просте, в дні коли мало – рішення часом взагалі неможливо побачити. І втомлюється людина від прийняття рішень, а також особливо від рішень які ще не прийняті. Навіть існує ефект Зейгарнік, який проявляється в тому, що люди схильні швидко забувати вирішені питання і закінчені справи, а незакінчені будуть триматись в мозку і займати його ресурси.

Качечка теж втомилась :)

Качечка теж втомилась :)

Тому, якщо робота застопорилась, можна спробувати застосувати модифікацію методу каченяти, яку я назвав QDD – розробка керована питаннями. Для цього потрібно написати питання над рішенням якого ви зараз думаєте в якийсь текстовий файл чи на листок паперу. І уявляти при цьому що це чат зі всезнаючим експертом, який обов’язково допоможе. Бо так і є, це час з собою майбутнім. Явне формулювання питання дозволяє сфокусувати думки, а часто зрозуміти що це не те питання яке потребує вирішення.

Якщо ще додавати до кожного запису час, і коротко записувати відповіді на запитання, можна отримати журнал який показує на що йде час розробки, і чому код написаний саме так а не інакше (бо виникали такі питання і знаходились такі відповіді). Якщо код буде написано неправильно – можна буде знайти момент в який неправильне рішення до нього привело. Якщо буде поставлена наступна задача – легше буде оцінити скільки питань і якої складності треба буде вирішити для виконання задачі. Бо розбиття роботи на пункти плану і оцінка їх по аналогії з вже виконаними пунктами – єдині відомі способи оцінити необхідний для роботи час. Для оцінки по аналогії покладаються на пам’ять, хоча журнал був би надійнішим.

Такий метод можна застосувати до вирішення інших проблем, що не стосуються коду. Наприклад до вгризання в якусь складну ідею, чи до пошуку рішення якоїсь життєвої проблеми. Багато великих питань можна розбити на менші питання, головне попрактикуватись.

Ну й наостанок дам приклад того про що я пишу – лог питань що виникають при розробці гри в “п’ятнадцять”: bunyk.github.com/blob/master/fifteen/worklog.txt. Сама гра.


Filed under: Кодерство, Психософія Tagged: психологія, розробка

Прогризання в Хаскель

Потрохи, дуже й дуже повільно гризу граніт науки з Хаскелем. Читаю “Вивчить собі Хаскела на велике щастя!“.

Книжка складна (чи то Хаскель такий), але гумор іноді веселий:

Шукати елемент у порожньому списку теж не варто, бо його там немає (і не тільки його — там немає багатьох інших елементів!)

Дійшов до розділу 8 про написання власних типів і типокласів. Ледве розібрався. Цікаво що в типів та конструкторів типів є типи (кшталти, kinds), і це не типи, як в Python, а щось інше. Не зрозуміло чому типоклас Функтор такий важливий. Ну можна виконувати над ним map. Але напевне важливий, бо десь я бачив слова “Аплікативний функтор, моноїд”, значить то десь до монад не далеко. Але дуже тішусь тим що наступний розділ буде про ввід-вивід, і я НАРЕШТІ зможу написати “Привіт, світе!”. :) Ну тобто ясно що main = putStr "Привіт, світе!", але зрозуміти що повертає putStr.

P.S. Я трохи намагався розібратись з монадами, і здається мені що в хаскелі функції не виконують побічні ефекти, але повертають щось що каже що повинні бути виконані певні побічні ефекти. Як те щось називається, і хто виконує – ще не знаю. Знаю лише що монада це три речі – тип, функція return, і ще якась функція. Що вони роблять – теж поки що не зрозуміло.

А потім може постараюсь пройти Write Yourself a Scheme in 48 Hours.


Filed under: Кодерство, Нещоденник Tagged: haskell

Асемблер x86 на Linux

Давно хотів познайомитись, але все стримувало те що в дитинстві я почав з синтаксису Intel, і хотів програмувати тут теж з синтаксисом Intel. Пройшло багато років, я забув, тому давайте вивчимо AT & T синтаксис. Потім при потребі можна перевчитись.

Ну й крім того, я знайшов книжку Programming from the Ground Up, в якій все дуже зрозуміло (як для дітей) пояснюють.

Ну дууууже коротка теорія

Перше що потрібно знати – x86 – це архітектура Фон Неймана, тобто код програми і дані зберігаються в одній і тій же пам’яті, і для комп’ютера виглядають однаково. (Щоправда операційні системи можуть обмежувати виконання лише областями з кодом, для того щоб запобігти можливим помилкам, якими можуть скористатись хитрі хакери)

Пам’ять – це довгий список байтів (можуть містити цілі числа від 0 до 255), кожен з яких має свою адресу. Адреса – це просто номер байта. Щоправда ми працюватимемо переважно не з байтами, а зі словами (в 32-х розрядній архітектурі це 4 байти, які можуть приймати значення від 0 до 4294967295). Тому що регістри процесора якраз стільки вміщають. Адреси – це теж слова (4 байти).

Найпростіша програма

Надрукуємо “Привіт, світе!”? О, ні, на ассемблері це надто складно. Давайте напишемо програму яка завершує роботу. Ага. В Unix, програма яка завершує свою роботу має повернути статус код. Статус код останньої виконаної команди можна побачити у спеціальній змінній командної оболонки: echo $?

_start – в лінкера за замовчуванням позначає точку входу в програму. Тобто адресу з якої почнеться її виконання. Можна замінити її наприклад на main, але тоді лінкер, якщо йому не вказати опцію -e main скаже:

ld: warning: cannot find entry symbol _start; defaulting to 0000000008048054

Символ відсотка позначає регістр процесора (наприклад %eax), долар позначає константу (наприклад $1, $0x80 (= 128 в шістнадцятковому записі) ).

Переривання – це місце в коді де контроль передається в якесь інше місце (в ядро). Коли ядро виконає своє переривання – воно поверне контроль нам, і програма продовжить виконання (стан регістрів може змінитись). Щоправда після системного виклику exit контроль нам ніколи не повернуть, але так й було задумано.

Щоб перевірити нашу програму, потрібно виконати команди:

as exit.s -o exit.o
ld exit.o -o exit

Перша створює об’єктний файл. Об’єктний файл – це вже код машинною мовою, але ще не до кінця зібраний. Потрібно передати його лінкеру – програмі яка вміє збирати багато об’єктних файлів в одну програму, та додавати інформацію для того щоб ядро знало як працювати з програмою.

Якщо все пройшло без помилок – можна перевірити роботу:

./exit 
echo $?

Також можна спробувати замінити код повернення в %ebx на якісь інші і подивитись результат.

Опис інструкцій

mov – це інструкція переміщення, яка має два операнди – звідки й куди.

Суфікс l означає розмір даних (long = 4 байти). Інші можливі префікси: b byte = (8 біт); s short = (2 байти (16 біт).

Багато інших інструкцій мають два операнди, як наприклад addl (додавання), subl (віднімання). Але, наприклад, інструкція div приймає єдиний аргумент, бере вміст регістрів %edx та %eax як велике 64-х розрядне число (якщо треба менше, %edx має містити нуль) ділить на переданий аргумент а тоді результат поміщує в %eax, а остачу від ділення в %ebx.

Регістри загального призначення, які можна використовувати як аргументи команд переміщення та арифметичних – це %eax, %ebx, %ecx, %edx, %edi, %esi.

Контроль ходу виконання

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

Виконання має повернути 89 (найбільше в списку). Це вже набагато цікавіша програма.

По-перше, ми маємо дані. Окрім типу .long (4 байти), ми можемо використовувати .byte, .int (2 байти), та .ascii – рядок символів, наприклад .ascii "Hello, world!\n".

По-друге, цікава інструкція movl data_items(,%edi,4), %eax. Лівий її операнд означає взяти дані з адреси data_items, але зсунутись на %edi елементів розміру 4. Тобто це як доступ до елементу масиву. Синтаксис паскудний, в Intel здається писали б data_items + %edi * 4, що виглядає зрозуміліше, але маємо що маємо.

Також, якщо ми хочемо отримати значення за адресою – теж використовуємо дужки. Наприклад – %esp – містить адресу вершини стеку. movl %esp, %eax – збереже цю адресу в %eax, а от movl (%esp), %eax – значення з вершини стеку.

Наступна незнайома інструкція – cmpl. Вона порівнює два чотирибайтові числа (суфікс бачите?), а результат порівняння записує в певні біти регістру %eflags. Про нього я дуже давно написав непогану статтю на CybWiki а потім на вікіпедії, тому в деталі не вдаватимусь.

Після порівняння зазвичай йде інструкція зробити стрибок на певну адресу, якщо виконується умова порівняння. Існують такі інструкції стрибків з умовою: je – стрибати якщо рівні, jg – якщо друге значення було більше за перше, jge – більше або рівне, jl – менше, jle – менше рівне.

incl – збільшує аргумент на одиничку. incl %edi – це те саме що й addl $1, %edi, тільки коротше й швидше працює.

Далі буде

Вже скоро ранок, а hello world ми ще так і не написали. Треба розібратись з написанням і викликом функцій, викликом функцій роботи з файлами, щоб можна було писати в STDOUT. Але це вже завтра, бо це вже й так надто червоноока публікація.

Хоча в книжці там ще йде мова про рекурсію, обробку помилок, бібліотеки функцій, та їх створення, менеджер пам’яті і інші цікаві речі.


Filed under: Кодерство Tagged: linux

HTML та LXML. Парсимо онлайн таблиці з Python

За службовою необхідністю в мене з’явилася задача організувати новий сервіс для користувачів. Сервіс простий: в нас є віртуальні площадки з різними OVZ контейнерами. Ці площадки мають своїх хазяїв. Іноді вони про них забувають. Тож треба було написати щось таке, щоби періодично перевіряло актуальність цих площадок, нагадувала власникам про їх нявність та просило би продовжити термін життя площадки або подати заявку на знищення. Все зрозуміло. Але для того, щоб це зробити, спочатку треба було актуалізувати данні по цим площадкам.

Данні в нас зберігались на сторінці в Confluence у вигляді таблиці. Таблиць на сторінці було декілька, з різною кількістю рядків і стовпчиків, з різним форматуванням, і створювались вони в різний час. Можна було б посидіти і вручну витягнути ці данні. Але, по-перше, в майбутньому доведеться обробяти і інші таблиці, по-друге, хотілося розробити інструмент, який би ці данні готував до того аби запхнути їх в базу, і потім використовувати їх. Тож: Confluence, HTML, LXML.

Timeout decorator

Декоратор який використовуючи сигнал Unix SIGALRM перериває роботу функції якщо та працює довше ніж задане число секунд:

import signal

class TimeOut(Exception):
    def __init__(self, msg='Time out error'):
        super(Exception, self).__init__(msg)

def on_alarm(signum, frame): # при надходженні сигналу кидати виняток
    raise TimeOut()

def limit_time(t, default=None):
    signal.signal(signal.SIGALRM, on_alarm) # встановити обробник сигналу

    def decorator(f): 
        def decorated(*args, **kwargs):
            signal.alarm(t) # попросити ОС прислати нам сигнал через t секунд
            try:
                return f(*args, **kwargs)
            except TimeOut:
                return default
        return decorated
    return decorator

import contextlib
# Дякую Алекс!
@contextlib.contextmanager
def time_limit(t):
    signal.signal(signal.SIGALRM, on_alarm)
    signal.alarm(t)
    try:
        yield
    except TimeOut:
        pass


import time

@limit_time(5) # працювати не довше 5 секунд
def test():
    for i in range(10):
        print i
        time.sleep(1)

test()

with time_limit(5):
    for i in range(10):
        print i
        time.sleep()


Filed under: Кодерство Tagged: linux, Python