01 април 2009

Lisp за Web приложения

Пол Греъм

(Това е част от разговор в BBN Labs в Cambridge, MA, през април 2001.)
Оригинал : Lisp in Web-Based Applications

Език по желание

Една от причините за използването на Lisp за написване на Web базирани приложения е че той *може* да се използва. Когато се пише софтуер, който ще се изпълнява на собствен сървър може да се използва който и да е език.
Дълго време програмистите нямаха голям избор на език за написването на приложни програми. Доскоро писането на приложни програми означаваше писане на софтуер, който се пуска на настолни компютри. Този софтуер се пише на езика на операционната система. Практически всички приложения се пишеха на С.
Това се промени от Web базираните приложения. Вие контролирате сървъра и може да пишете на който език си поискате.Може да се приеме, че имате едновременно изходния код на операционната система и компилатора. Може да оправите всеки проблем на езика с операционната система .
Обаче тази свобода е нож с две остриета. Наличието на избор принуждава да се мисли върху въпроса какво да се избере. Преди беше по-лесно . Ако отговаряхте за софтуерен проект и някой предложеше да се използва различен от обичайното език може просто да се каже, че това няма да е практично и да се сложи точка на разговора.
Сървърните приложения промениха всичко. Пазарните сили определят избора на език. Ако се правите, че нищо не станало,както повечето от конкурентите ни, и си използвате С и С++ , ще попаднете в собствения си капан. Малка стартираща компания използваща по-мощен език ще ви изяде пазара.

Инкрементална разработка

Програмирането на Lisp има специфичен стил. Една от основите му е инкременталната разработка : написва се колкото се може по-бързо програма, която не прави почти нищо. След това към нея постепенно се добавят елементи, като винаги има работещ код.
По мое мненние се произвеща по-бързо по-добър софтуер. Lisp програмистите работят вече тридесет години по този начин и всичко в Lisp е подчинено на този стил на програмиране.
Редакторът на Viaweb е краен пример за инкрементална разработка. В началото той беше 120 редова програма за генериране на Уеб сайтове, която бях използвал като пример в книга , която написах преди да се захванем с Viaweb. Постепенно този редактор нарастна до около 25 000 реда код. Нито веднъж не седнах да го пренапиша. Не мисля че е имало ден или два, без да променя нещо по кода. Цялата разработка беше дълга серия от постепенни промени.
Този стил на разработка се вписва добре в постоянните версии на Уеб базирания софтуер. Той е и по-бърз начин за писане на софтуер по принцип .

Интерактивна обвивка

Интерактивната обвивка на Lisp помага много при ускорената разработка на софтуер, но най-голямото ни предимство вероятно беше при намирането на бугове. Както споменах при Уеб базираните приложения имате всички потребителски данни на сървърите и обикновено бъговете могат да бъдат репродуцирани.
Когато някой потребител се обърнеше към мен, съобщавайки за грешка в редактора, зареждах кода му в Lisp интерпретатор и се логвах в потребителския акаунт. Ако можех да репродуцирам проблема го прихващах в цикъла за грешка, който показва точно какво се е обърклао. Често поправях кода и публикувах поправката веднага. Като казвам веднага имам предвид докато потребителя е все още на телефона.
Такова бързодействие при оправянето на бъгове ни предостави много изкушаваща възможност. Ако можехме да разберем и оправим проблем, докато потребителя е на линия, се изкушавахме да създадем впечатление , че никога не го е имало. И понякога хората от отдела за подръжка (за тяхна огромна радост) казваха на потебителя просто да опита да се логне отново и да види дали все още го има проблема . Естествено потребителя се логваше в новата версия на софтуера, в която е оправен проблемът, и всичко работи добре. Може би по този начин постъпвахме малко подло, но беше и доста забавно.

Макроси за HTML

Макросите на Lisp бяха друго голямо предимство за нас. Използвахме ги интезивно при редактова на Viaweb. Той може да бъде точно описан като един голям макрос. Това може да даде идея колко много зависихме от Lisp, защото нито един друг език няма макроси в същата степен като Lisp.
Ние използвахме макроси, за да генерираме HTML. Връзката между макросите и HTML е естествена - HTML и Lisp са с префиксна нотация и са рекурсивни. Въпреки че извиквахме макроси , вложени в други макроси , които генерираха най-сложният HTML код, процесът беше доста управляем.

Вградени езици

Друга полза от макросите беше използването на езика ни за описване на страници, наречен Rtml .(Имаше различни обяснения за значението на Rtml, в действителност го нарекох на съоснователя на Viaweb Робърт Морис, неговото потребителско име е Rtm.)
Всяка страница беше генерирана от програма, написана на Rtml. Нарекохме тези програми темплейти, за да ги направим по-малко плашещи, но те бяха истински програми. Програми на Lisp. Rtml беше комбинация от макроси и вградени в Lisp оператори.
Потребителите можеха да правят техни собствени Rtml шаблони, в които да описват как да изглеждат страниците им. За редактирането на шаблоните използвахме структурен редактор, приличащ много на този от InterLisp. Заменихме писането на свободен текст с копиране и поставяне на цели части код. Така се избегнаха синтактичните грешки. Също така избегнахме показването на скобите на s-изразите, които се получават от кода - показвахме стуктурата му чрез отместване и форматиране. С всичко това езикът ни изглеждаше доста по-малко заплашителен.
Rtml беше проектиран да не дава никакви грешки - всяка програма на Rtml генерираше някаква Уеб страница и чрез дебъг може да се достигне до вида на страницата, който искаме.
Отначало очаквахме потребителите ни да са Уеб консултанти, които да използват често Rtml. Осигурихме няколко прости шаблона за секциите и страниците на продуктите, като идеята беше потребителите да ги променят по собствено желание.
Оказа се , че Уеб консултантите не харесаха Viaweb. По принцип те харесват продукти, които са прекалено сложни за техните клиенти, като по този начин си гарантират постоянно наемане. Консултантите посещаваха сайта ни, в който навсякъде е казано, че софтуерът ни е толкова лесен за употреба и всеки може сам да си направи онлайн магазин за пет минути, и си казваха , че няма начин да използват това. Така нямаше много интерес от страна на консултанти. Вместо това потребителите ни бяха същинските търговци. Те харесаха идеята да контролират техните Уеб сайтове. Този тип потребители не искаха да програмират каквото и да е. Те просто използваха готовите шаблони.
По тази причина Rtml не стана основен интерфейс към програмата. Той изпълняваше две други функции. На първо място той беше вариант за наистина напредналите потребители, които искаха нещо, които липсва в нашите шаблони. Някой ми беше дал ценен съвет : потребителите винаги искат да има възможност за подобрения, дори и никога не ги правят. Нашата възможност за подобрения беше Rtml. Може да поемеш абсолютен контрол върху страниците си, стига да искаш.
Само един от няколко стотин потребители написаха свои шаблони действително. Това води до второто предимство на Rtml. Наблюдавайки какво променят тези потребители в нашите шаблони, знаехме какво да добавим в тях. Дори си поставихме цел никой да няма нужда да използва Rtml . Нашите вградени шаблони трябва да вършат всичко, което искат хората. При този нов подход Rtml служеше като сигнал, че нещо липсва в нашия софтуер.
Третата и най-голяма полза от използването на Rtml беше предимството, което ни донесе. Дори и ние да бяхме единствените хора, които го използват, това се отплащаше достатъчно. Този нов слой абстракция в софтуера ни ни донесе голяма предимство пред конкурентите. От една страна дизайна на софтуера ни стана много по-чист. Нашите Уеб страници се генерираха от език от много високо ниво, вместо от истински С или Perl код. Това направи кода много по-чист и лесен за модифициране. Вече споменах , че Уеб базираните приложения са поредица от множество малки модификации. За да се прави това трябва да се знае колко сериозна е дадена модификация. Това се определя по-лесно след разделянето на кода на слоеве. Модификации на ниско ниво (смаият Rtml) се правеха рядко и след голямо обмисляне. Модификациите в по-горните нива(кода на шаблоните) бяха нещо, което може да се направи бързо и без много притеснения за последиците.
Rtml беше продължение на Lisp. На първо време той беше основно Lisp макроси. Онлайн редактора обабротваше s-изрази. А когато хората стартираха шаблон той се компилираше в Lisp функции чрез извикване на компилация по време на изпълнението.
Rtml дори зависеше силно от ключови думи, зададени като параметри, което до тогава смятах за една от най - съмнителните особености на Common Lisp. Но поради начина на обнновяване на Уеб базирания софтуер той трябва да е проектиран за лесни промени. Rtml трябваше да е лесен за променяне, както всяка друга част от софтуера. Повечето от операторите в Rtml бяха проектирани да приемат като параметър ключова дума и това беше от голяма полза. За да добавя ново измерение в действието на някой оператор трябваше само да добавя нов параметър, като съществуващите шаблони продължаваха да работят. Малко от операторите в Rtml не приемаха ключови думи като параметри, защото не мислех че някога ще се налага да се променят, и горчиво съжалявах за това впоследствие. Едно от нещата, които щях да променя ако можех да върна времето назад и да започна всичко отначало , щеше да е това, че всеки Rtml оператор да приема ключови думи като параметри.
Всъщност ние имахем няколко езика в редактора. Друг, който не беше директно за потребителите, беше за описание на изображения. Viaweb съдържаше написан на С генератор на изображения , който приема описание на изображение, създава самото изображени и връща неговият адрес. Отново използвахме s- изрази за описанието на изображенията.

31 март 2009

Програмиране отдолу-нагоре

1993
Оригиналната публикация - Programming Bottom-up
(Това есе е част от въведението на On Lisp . Червеният текст обяснява произхода на името Arc)
Стар принцип в програмирането е функционалните елементи на програмата да не са много големи. Ако някой компонент от програмата премине границата на четимост той придобива голяма сложност, която прикрива грешките както големият град прикрива престъпленията. Подобен софтуер е труден за четене, труден за тестване и труден за дебъгване.
Спрямо този принцип големите програми трябва да се разделят на части и колкото по-голяма е програмата на толкова повече части трябва да се раздели. Как да се раздели програмата ? Традиционният подход се нарича отгоре надолу - "тази програма трябва да прави тези седем неща, така че ще я разделя на седем големи процедури. Първата процедура трябва да прави тези четири неща, затова тя ще има четири собствени подпроцедури...". Този процес продължава до достигането на опрелена степен на гранулиране - всяка част е достатъчно голяма, за да върши нещо, и достатъчно малка, за да не може да се разделя повече.
Опитните Lisp програмисти разделят своите програми по различен начин. Те използват принцип, наречен отдолу-нагоре -- променят езика според проблема . С Lisp не само програмата се пише на езика, но и езика се изгражда спрямо програмата . Докато пишете програмата може да си помислите "Искам Lisp да има такъв и такъв оператор" . След това си го написвате. В последствие разбирате , че използването на новият оператор може да опрости друга част от програмата и така нататък. Езика и програмата се развиват заедно. Границите между ези ки програма се чертаят и пречертават като граница между воюващи държави, докато не стигнат до планини и реки, които да са естествени граници . В края програмата изглежда така, сякаш езикът е проектиран за нея. А когато езикът и програмата са един за друг кодът е чист, малък и ефиктивен.
Струва си да се отбележи, че проектирането отдолу-нагоре не означава просто различен ред за написване на програмата. При работа отдолу-нагоре в края имаме различна програма. Вместо една монолитна програма имаме по-голям език с повече абстрактни оператори и по-малка програма , написана на него.Имаме арка вместо греда.
След намирането на абстракните части, които често са известни, от нормалния код остава доста малко; колкото повече се допълва езика , толкова по-малко разстояние остава за да се достигне целта. Това има няколко предимства:
  1. Когато езика върши повече работа самата програма е по-мала и по-лесно променима. По-малката програма не трябва да се разделя на много компоненти, а малкото компоненти правят програмта по-лесна за четене и модифициране. По-малкият брой компоненти води и до по-малко връзки между тях , както и до по-малка вероятност за грешки в тях. Опитните Lisp програмисти използват проектирането отдолу-нагоре за намаляване на размера и сложността на техните програми по подобие на индустриалните проектанти, които намалят броят на движещите се части в машините.
  2. Проектирането отдолу-нагоре увеличава повторното използване на кода. Много от полезните елементи написани за една програмамогат да се използват и в следващите я. След насъбирането на голям набор от малки части код писането на нова програма заема малка част от усилията ,които ще трябват ако се пише начисто.
  3. Проектираните отдолу-нагоре програми са по-лесни за четене. Този тип абстракция налага читателят да разбере оператор с общо предназначение; функционалната абстракция налага читателя да разбере процедура със специално предназначение. [1]
  4. Работата отдолу-нагоре помага за изясняването на дизайна на програмата, тъй като изисква постоянно търсене на шаблони в кода. След забелязването на сходност в два отдалечени компонента в програмата може да се стигне до препроектирането й в по-проста форма
Проектирането отдолу-нагоре е възможно и в езици, различни от Lisp. Всяка библиотечна функция е част от такъв дизайн. Въпреки това Lisp дава много по-голяма свобода в това направление и нарастването на езика играе голяма роля в стила на Lisp. Толкова голяма, че Lisp не е само различен език, а различен стил на програмиране.
Истина е че този стил на програмиране е пригоден за програми, които се пишат от малки групи. Въпреки това той разтегля границите на това, което може да се направи от малка група. Фредерик Брукс, в книгата си The Mythical Man-Month предполага, че продуктивността на групата не зависи линейно то размера й. С нарастването на размера на групата се намалява продуктивността на отделния програмист. Опитът от програмиране на Lisp води до по-оптимистичен вариант на този закон : Намаляването на групата води до увеличаване на продуктивността на отделния програмист . Малките групи печелят , относително погледнато, просто защото са по-малки. Когато малка група се възползва от предимствата на Lisp , тя може да спечели.


Download On Lisp for Free.

[1] Но никой не може да разбере програмата без да разбира всички нови оператори." Това твърдение е опровергано в Секция 4.8.