Comments 199
[Да ну нахер...].jpg
Серьезно, автор, вы прям любитель БДСМ.
А если серьезно, можете привести аргументы, почему этим файлам не стоит лежать в одной папке? (кроме js — это случайный мусор, уберу).
А чем nodejs не угодил? Ну кроме мифической неприязни к JS (вам все равно пришлось на нем писать, ибо на сайте есть интерактив).
Для обучения неплохо.
Но если вам для работы, то лучше использовать mORMot (https://synopse.info/).
На самом деле не так он сложен как кажется. Так как с актуальными библиотеками на Паскале (особенно с поддержкой как Delphi так и FPC) все плохо, проект реализует почти весь функционал необходимый для разработки бизнес приложений. Никто не запрещает пользоваться только отдельными кусками. Работа с HTTP там реализована очень неплохо.
Из понавороченнее TMS XData платный, там вообще чуть ли не автоматом встроенный swagger для тестирования и документации.
Ну если сравнивать с перлом, тогда конечно.
У меня сложилось впечатление, что как в 2000 году автор выучил какое-то подмножество Перл, достаточное для каких-то сайтов, так с тех пор его знания о Перле остались на том же уровне.
Знаю о чём говорю, в одиночку писал проекты на Перл в 100 тыщ строк, участвовал в проекте в почте 200 тыщ строк.
В общем, автор поделился своими достижениями в Паскале, что, конечно, не плохо, но Перл является очень недооценнённым языком именно из-за предубеждения знатоков из 2000 года.
Да, всё верно. Для меня Perl — это "язык, похожий на C", где не нужно компилировать, и для которого можно найти модуль на CPAN практически для всего, что касается Веба.
Мне не очень понятно как (и зачем) писать большие проекты на Perl, но раз люди пишут — значит, видимо, смысл есть. Ну и стоит отметить, что популярность Перла в сайтостроении ещё в 2000-х конкретно снизилась, хотя на PHP активно пишут до сих пор.

db.Query('SELECT msg,created FROM messages WHERE topic=%d ORDER BY id LIMIT 1', [id]);
А вы не боитесь SQL injection?
В данном случае ничего страшного нет.
А вот в функции SQLSafe я не увидел обработки одинарной кавычки. Вообще, для SQL родные кавычки одинарные. Двойные БД автора видимо тоже понимает, но могут быть нюансы.
Здесь MySQL, кавычки повсюду использую двойные, поскольку запросы со строками обычно выглядят так:
db.Query('SET param="%s"', [value]);
т.е. поскольку одинарные уже задействованы, логично использовать двойные.
Но вообще спасибо за замечание, действительно стоит обрабатывать и одинарные.
Какие плейсхолдеры?
SELECT * FROM whatever WHERE foo=?
И в чём разница?
Для типичных запросов там есть QueryHash() и QueryValues() — это устраняет дублирование кода, но в целом его очень немного.
Для больших структур есть генератор кода для импорта/экспорта этих структур в БД, но в данном проекте это неактуально.
И в чём разница?
Возьмем этот же зпрос выше: db.Query('SET param="%s"', [value]);
что будет если в переменной value будет " где то в строке?
Оно преобразуется в \", поскольку все строки, передаваемые в Query(), проходят обработку.
Или вы говорите что перед передачей в Query оно проходит обработку?
Если так — то есть высокая вероятность «забыть» эту обрабаботку. И если не сложно — где эта «обработка» происходит?
У автора по сути тоже плейсхолдеры, только с наивной реализацией
По исходникам — очень сложно для такой простой задачи. Странные манипуляции над глобальными переменными, куча мутабельного стейта который нужно учитывать, в кучу смешаны куча разных аспектов, как например АБ-тестирование, генерация жс скриптов и непосредственно вычисление данных для отрисовки.
Ну и сам сайт выдает очень странные ворнинги. О каких таких "плохих последствиях" идет речь боюсь даже представить:
function InsertCardHints(const msgText:AnsiString):AnsiString;
var
i,j,k,l,m,p,f,d1,d2,w,words:integer;
function FormatForumMessages(condition:AnsiString;const profile:TUserProfile;cutNearMsgID:integer=-1):AnsiString;
var
key,key2,list,msgtext,author,pFlags:AnsiString;
messages:THash;
profiles:THash;
players:THash;
attachments:THash;
lastread:THash;
plrID,profileID,face,topicID:variant;
i,n,cnt:integer;
attList,lrd,levelLabel:AnsiString;
arr:IntArray;
attType,attThumb:AnsiString;
moderator:boolean;
r1,r2:TRegExpr;
date:TDateTime;
skipFrom,skipTo,SkipAfter:integer;
Очень сложно.
Как с юнит тестированием на паскалях?
Не очень, но жить можно. Остановился на fptest.
А как тестировать контроллеры, вроде вот этого? В том же дотнете контроллер это обычная функция, её можно вызвать, получить IActionResult и проинспектировать, а всё взаимодействие с HTTP описывается атрибутами, которые в тестах игнорируются, а рантаймом HTTP сервера — используются.
В коде который я смотрел выше у функии параметров нет, она сама достает что-то из эмбиент контекста через всякие Param/IntParam, и возвращает просто строку.
К чему вопрос? Вы сами прекрасно понимаете что это не тестируемый код. Автор отметил что он не профессиональный разработчик, так что это простительно.
А, этот момент я пропустил. Тогда, конечно, вопросов не имею.
Не профессиональный веб-разработчик. Т.е. зарабатываю я не разработкой сайтов, а разработкой игр. Но в играх примерно такой же код и там тоже нет юнит тестов. Больше того, у других разработчиков игр, которых я знаю, тоже нет юнит-тестов!
А у разработчиков игр которых я знаю (в частности, пара работала в нивале и обсидиане) тесты есть.
Извините, не обратил внимания. Чаще всего разработчики в принципе не пишут тесты, что немного печально, особенно когда приходится это потом поддерживать.
Тогда можно вопрос? Почему именно Delphi для разработки игр, если это источник заработка? Все дело в поддержке проектов, или нет желания менять платформу?
Дело и в поддержке, и в преемственности, и в опыте: куда как проще писать новую игру на хорошо знакомом языке, на своём движке. Чем с нуля начинать на Unity и C#. Путь наименьшего сопротивления. Хотя с точки зрения востребованности на трудовом рынке, это, конечно, большой минус.
Есть же стандартные решения в Lazarus — и cgi, и fcgi, и даже стенделон для всякого реста
https://wiki.freepascal.org/fcl-web
И шаблоны там выглядят как-то так:
<br>
Something here for the body
<table border=1>
<tr>
<td valign="center" width=200 height=200>
{+INCLUDETEMPLATE [-TEMPLATEFILE=body_left.html-]+}
</td><td valign="center" width=200 height=200>
{+INCLUDETEMPLATE [-TEMPLATEFILE=body_right.html-]+}
</td>
</tr>
</table>
Но писать в Лазарусе — это боль.
Но писать в Лазарусе — это боль.
Почему?
Ну вот например я недавно скачал свежий официальный дистрибутив и установил Лазарус, запустил его пересборку — ошибка! Скачал 32-битную версию — то же самое. Ну как так?
Другой пример:
var s:string
...
s.ToUpper;
В mode=Delphi — работает, в mode=DelphiUnicode — ошибка. А по документации должно работать.
Нужно ставить правильные версии, тогда все работает.
Рекомендую установить FPC и Lazarus по следующей инструкции:
26.4.2. Setup your dedicated environment with fpcupdeluxe
Затем довести IDE до привычного вида, как в Delphi:
Lazarus Docked Desktops
То есть на официальном сайте Lazarus — неправильная версия? Ну Ok.
Вообще я в курсе, что в инете есть допиленные версии Лазаруса, но сам факт того, что такие версии нужно где-то искать, вместо того, чтобы взять на официальном сайте — уже о чём-то говорит!
На официальном сайте версия просто очень старая — 3.0 была выпущена в 2015 году. И Юникод в ней нормально не работает, для него нужна версия хотя бы 3.1.
Актуальная версия сейчас это 3.3, но так как она находится в активной разработке, то нельзя просто взять любую ревизию из ветки 3.3.
Если хочется фич — типа наконец-то добавленных Generics.Collections с TDictionary и прочее — нужно брать trunk из SVN/git и собирать самому — wiki.lazarus.freepascal.org/Installing_Lazarus/ru (именно /ru — она почему-то поадекватней)
А что не так с Лазарусом? Одна только фича с CodeTemplates по Ctrl-J чего стоит
Imho с грамматикой проблем нет. Основных проблем на мой взгляд две:
- Долгое время не было бесплатного инструмента, тогда как C++, Java, Nodejs, Python — всё бесплатно.
- Долгое время была фактически монополия на язык, который был железобетонно связан с библиотеками. Получается закрытая проприетарная экосистема, которая пусть и хороша как коммерческое решение, но долгосрочно с ней связываться стрёмно: мало ли что… С развитием FPC/Lazarus стало менее стрёмно.
Синтаксис — это все фантики, за пару недель привыкаешь. Если рассматривать другие языки похожего назначения они все будут достаточно многословны. А вот проблемы с библиотеками куда существеннее.
На самом деле минимальное консольное приложение сравнимо
program helloworld;
begin
WriteLn('Hello World!');
end.
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Что касается отдельного декларирования классов, функций, процедур — это особенность похожих языков, такая же как в С/С++. Зато скорость компиляции одна из самых высоких в своем классе.
- Во-первых джава тоже достаточно быстро собирается.
- Во-вторых в эпоху микросервисов ждать 1 секунду или 2 на полную пересборку приложения — не так уж критично? Особенно если собирать инкрементально, тогда на моей машине (при редактировании одного файла контроллера) сборка занимает 600мс.
- В-третьих даже если разница в пару секунд (а как мы помним, даже её нет), оно не стоит той когнитивной нагрузки, которую оно с собой несет. Всё же сейчас 2020 год, и трейдофы сильно отличаются от принятых в 1970.
Справедливости ради, минимальное консольное приложение выглядит так:
{$APPTYPE CONSOLE}
begin
end.
Многословность не есть недостаток, зачастую она повышает читаемость кода. Код гораздо чаще читают, чем пишут, поэтому читабельность важнее "писабельности", тем более что с последней хорошо помогает IDE — автодополнение, шаблоны.
почему декларация класса вынесена отдельно от имплементации в Delphi
Возможно, вам бы понравился Оберон. А мне не понравился. Мусорка.
Мне нравится вот так:
package Ada.Real_Time
with Nonblocking is
type Time is private;
Time_First : constant Time;
Time_Last : constant Time;
Time_Unit : constant := implementation-defined-real-number;
type Time_Span is private;
Time_Span_First : constant Time_Span;
Time_Span_Last : constant Time_Span;
Time_Span_Zero : constant Time_Span;
Time_Span_Unit : constant Time_Span;
Tick : constant Time_Span;
function Clock return Time;
function "+" (Left : Time; Right : Time_Span) return Time;
function "+" (Left : Time_Span; Right : Time) return Time;
function "-" (Left : Time; Right : Time_Span) return Time;
function "-" (Left : Time; Right : Time) return Time_Span;
То есть, вот есть Time и Time_Span. Если к Time прибавить Time_Span, получим Time. Time можно получить у функции Clock, а Time_Span можно получить как разность двух Time. Самая суть выражается, читать одно удовольствие. А детали выносятся в «примечания» (private).
Delphi, хоть и не такой мусорный язык, но там уже is private нет. Вынь да положь содержимое всех кишков на всеобщее обозрение вперемешку с действительно интересными методами.
Вот аналог на Delphi.
unit System.Diagnostics;
interface
{$HPPEMIT LEGACYHPP}
uses System.Classes, System.TimeSpan;
type
TStopwatch = record
strict private
class var FFrequency: Int64;
class var FIsHighResolution: Boolean;
class var TickFrequency: Double;
strict private
FElapsed: Int64;
FRunning: Boolean;
FStartTimeStamp: Int64;
function GetElapsed: TTimeSpan;
function GetElapsedDateTimeTicks: Int64;
function GetElapsedMilliseconds: Int64;
function GetElapsedTicks: Int64;
class procedure InitStopwatchType; static;
public
class function Create: TStopwatch; static;
class function GetTimeStamp: Int64; static;
procedure Reset;
procedure Start;
class function StartNew: TStopwatch; static;
procedure Stop;
property Elapsed: TTimeSpan read GetElapsed;
property ElapsedMilliseconds: Int64 read GetElapsedMilliseconds;
property ElapsedTicks: Int64 read GetElapsedTicks;
class property Frequency: Int64 read FFrequency;
class property IsHighResolution: Boolean read FIsHighResolution;
property IsRunning: Boolean read FRunning;
end;
implementation
Ну что, приятно такое читать? А со встроенными телами методов ещё больший кошмар.
Стресс-тест: 20 запросов в секунду в течение 20 секунд.
Домашняя страница (самая тяжелая):
Не упадёт — всё везде завёрнуто в try/except. Ну и есть же способы следить за процессом и запускать его в случае падения.
Перезапуск при обновлении — да, на 2-3 секунды сайт отключается. При большом желании можно повозиться чтобы этого избежать.
Спасибо!
Насчёт memory leaks и падений: у меня там запущено еще 2 сервера старых игр, написанных на Delphi, которые уже года 3-4 никто не трогал. Кроме рестартов, связанных с обновлением системы (примерно раз в полгода), они не перезапускались. И вот они работают, люди играют — ни одного падения за эти годы, и память не течет. Конечно, так получилось не сразу, но постепенно я пришел к простому выводу: если не создавать объекты, не выделять явно память, а использовать лишь managed-типы, то и течь нечему :) Включенный Range Check защищает от выходов за пределы массивов, тем самым предотвращая порчу памяти. А повсеместные блоки try/except не дают мелким проблемам перерасти в крупные.
Вероятно в ближайшее время на Patreon'е будет достигнута следующая цель: тогда опубликую код сервера игры и напишу новую статью о его устройстве.
Всего один процесс, и если какой-то поток словит ошибку, все приложение упадет.Это не так. Потоки можно вполне перезапускать и без try/except (это как раз таки скорее вредно). По опыту разработки серверных приложений с сотнями потоков на Delphi).
Однако сюда еще можно добавить memory leaks в компонентах и коде. В результате чего нужно регулярно перезапускать процесс. В целом все это не критично, но держит в напряге. В случае со скриптовыми языками проще. Отработал скрипт, клиенту отдал содержимое и умер.Лики довольно просто чистятся — есть как минимум штук 5 инструментов для Delphi, которые прямо строчку кода могут указать где случилась утечка. Ничто не мешает, и Делфи приложения так же как скрипты: запускать — забирать результат. Но, как правило, это непрактично, так не делают.
Вообще — наших веб-серверов на Delphi по стране стоят сотни, работают круглосуточно месяцами и годами, достаточно нагруженные и ответственные приложения (медицина). В том числе, бывает, смотрят и в интернет. Пока не заломали ни один (тьфу * 3).
Но, конечно, так как автор, мы не пишем :) (по поводу sql инжекции).
Вообще результат сильно зависит от того, как написана реализация конкретной страницы. Можно запросто обрабатывать и тысячи запросов в секунду, если не делать в каждом запросе десятки обращений к БД, а использовать только данные в памяти.
Другой тест — на 150 клиентов, тут уже видно, что некое равновесие наступает при нагрузке в ~45 запросов в секунду, сайт при этом уже тормозит:
Судя по логам, worker тратит на выполнение запроса 20-100 мс, в среднем примерно 40 мс. Запросы сложились в очередь — отсюда большое время ожидания.
Вот автора поста как раз можно упрекнуть в недостатке любопытства.Вместо того чтоб взять наиболее подходящий инструмент для веба он костылит свое решение на мертвом паскале. Хотел чтоб получилось как лучше но в итоге воюет с собственным поделием пытаясь внести свои изменения.
Как самообразовательный проект может быть полезным. Как продакшн решение явно нет.
Как самообразовательный проект может быть полезным. Как продакшн решение явно нет.
Тем не менее, сайт в продакшене, сервер игры — тоже, как и сервера еще 3-х игр. В продакшене с 2004-го (один правда уже закрылся).
Огромная куча ошибок просто бы не возникла.
А где можно посмотреть на эту кучу? И вообще, откуда вы решили что эта куча существует?
Из опыта. Или вы думаете, у автора с первого раза все получилось и работало без ошибок и исправлений? Чем больше кода написано вручную, тем больше возможных ошибок и исправлений.
Как думаете, где проще совершить ошибку? Здесь
db.Query('UPDATE profiles SET notify="%s" WHERE id=%d',[profile.id,profile.notificationMode]);
или здесь?
profile.save();
А profile.save();
это нам наверное господь спустил с небес? Потихоньку подключается по ночам к github и пилит веб фреймворки?
Нет – там тоже какой нибудь update profiles set...
точно так же возможно написанный криво и уязвимо человеком. Но закопанный глубоко в сорсы в которыми вы никогда не заглянете. И кроме разработчики и искатели 0-day никто и не заглядывает.
Нет – там тоже какой нибудь update profiles set
Да, там именно update, и именно поэтому его надо использовать. Потому что он там уже написан и проверен, и вам не надо его писать самому. Только там не update profiles
, а что-то вроде этого:
$primaryKeyField = $this->getPrimaryKey();
$values = $this->getFieldValues();
$sql = "update " . $this->table
. " set " . implode(' = ?, ', array_keys($values)) . " = ?"
. " where " . $primaryKeyField . ' = ' . $values[$primaryKeyField];
$this->db->query($sql, $values);
и работает оно не только для profiles, а вообще для любых сущностей в проекте. И для них вам тоже не надо это писать самому.
И если оно написано криво и уязвимо, оно работает криво и уязвимо для всех сущностей, а значит вероятность это заметить повышается, и исправить это проще, чем накопированные по всему проекту запросы. А так как это фреймворк, то им пользуется много людей, и вероятность это заметить и исправить повышается еще больше. Вы возможно не заглядываете в исходный код библиотек, а есть люди, которые заглядывают. Потому что этот код работает у них в продакшене, и уязвимости им не нужны. А уж если у кого-то из-за уязвимости произошел взлом, то тем более заглянут. А исправление будет доступно сразу всем, в том числе и вам, и совершенно без усилий с вашей стороны.
К сожалению, чудес не бывает: если нужна определенная логика — её нужно где-то написать. За исключением фантастического случая, когда готовое решение реализует на 100% то, что нужно. Вопрос лишь в том, что выгодней: допиливать чужое решение под свои условия, или реализовать своё. Выбор не всегда очевиден.
если нужна определенная логика — её нужно где-то написать
Да. И зачем вам писать логику генерации SQL-запроса, которая уже написана?
Вопрос лишь в том, что выгодней: допиливать чужое решение под свои условия, или реализовать своё.
Фреймворки не допиливаются, фреймворки используются.
В логике генерации запроса есть смысл, если есть множество однотипных запросов. Например, у меня есть много однотипных SELECT'ов — для них написаны обобщённые методы. А если запрос уникальный или их пара штук, то замена их на генератор выглядит как создание избыточного уровня абстракции. Это снижает понятность кода: когда видишь "UPDATE xxx WHERE yyy" — сразу понятно что это и как работает, потому что это SQL. А когда видишь this->update('xxx','yyy') — уже не очень понятно, потому что это придуманный кем-то интерфейс, у которого неизвестно что под капотом.
А что касается фреймворков, которые не допиливают: наверно их бы просто не было в таком количестве, если бы их создатели руководствовались принципом: "Зачем писать, лучше взять уже готовое".
Вопрос лишь в том, что выгодней: допиливать чужое решение под свои условия, или реализовать своё
Добавлю, что вы неправильно оцениваете масштабы. В данном случае такого вопроса нет. Вам несколько человек говорит про фреймворки, потому что то своё, которое вы реализовывали, в 90% функциональности ничем не отличается от чужого. Сколько времени вы разбирались со спецификацией CGI, неделю, две? А можно было в это время разбираться с PHP. FastCGI сервер там уже есть готовый.
Я тоже сначала писал на компилируемых языках. После перехода на PHP и тем более на фреймворки много узнал о том, как правильно писать код. По сравнению с тем, что есть в Delphi, современный PHP это шаг вперед.
Описание SCGI в вики занимает страницу текста, чтобы с ней разобраться, достаточно 10 минут. Час-полтора — написать реализацию. После написания и отладки эту инфу можно навсегда выбросить из головы.
Для изучения языка программирования нужно гораздо больше времени. И гораздо больше "памяти" в голове, чтобы запомнить основные стандартные функции.
Что касается PHP, то я его в принципе не рассматривал из-за его репутации. Может быть в современном PHP всё не так, как было раньше, но в памяти отложилось, что с PHP лучше не связываться, т.к. на каждом шагу — то выстрел в ногу, то уязвимость.
В принципе любой интерпретируемый язык, в котором есть eval() — это пороховая бочка.
Добавлю, что вы неправильно оцениваете масштабы.
Добавлю, что на фоне общего времени, потраченного на создание сайта, время на разработку этого модуля SCGI — это просто капля в море. Основное время занимают создание макета, нарезка HTML, написание кода на JS и кода функционала бэкенда, локализация, тестирование и т.д.
это придуманный кем-то интерфейс, у которого неизвестно что под капотом
Почему "this->update" это "интерфейс, у которого неизвестно что под капотом", а "mysql_real_query" это не такой интерфейс? И то и то это сторонний код, и на оба из них есть документация, которую надо изучить, чтобы узнать как их использовать.
А что касается фреймворков, которые не допиливают: наверно их бы просто не было в таком количестве, если бы их создатели
Так мы не говорим про создание фреймворка, мы говорим про его использование. Вы в своем проекте фреймворк не допиливаете, а используете как есть.
Час-полтора — написать реализацию. После написания и отладки
Ну а можно не писать и не отлаживать, а вместо этого заняться логикой самого сайта. Тем более вы же simple написали, а на полную реализацию ушло бы больше времени.
Для изучения языка программирования нужно гораздо больше времени. И гораздо больше "памяти" в голове, чтобы запомнить основные стандартные функции.
Для изучения PHP после Delphi/C++ не надо много времени. Функции запоминать вообще мало смысла, в PHP они одни, в JavaScript другие, в Delphi третьи. Достаточно поиска в интернете и документации.
Что касается PHP, то я его в принципе не рассматривал из-за его репутации.
А уж у Delphi-то репутация на высоте)
В принципе любой интерпретируемый язык, в котором есть eval() — это пороховая бочка
А вас кто-то заставляет его использовать?) В JS тоже есть eval, вы же этот язык используете, и ничего.
Добавлю, что на фоне общего времени, потраченного на создание сайта
Так вам именно об этом и говорят. Вы могли на создание сайта потратить гораздо меньше времени.
По сравнению с тем, что есть в Delphi, современный PHP это шаг вперед.Ого, соревнование по остроте каменных топоров накаляется! =)
Дейстивтельно, какая куча ошибок? Как-раз таки куча ошибок возникла бы начни я писать всё это на каком-нибудь PHP-фреймворке. Из-за незнания особенностей языка, фреймворка, незнакомых и непривычных инструментов разработки и отладки.
Собственно, достаточно взглянуть на JS-код этого же сайта, чтобы понять, как мог бы выглядеть код сайта на PHP :-) ПРи том, что JS для меня не такой уж незнакомый, ведь я использую его для фронтенда сайтов достаточно давно.
Собственно, достаточно взглянуть на JS-код этого же сайта, чтобы понять, как мог бы выглядеть код сайта на PHP
А вот для этого как раз и нужны фреймворки. Они вас ограничивают, показывают как надо делать правильно стандартные вещи.
Если не ошибаюсь, компания Borland в 2002 году при выходе Delphi 7 позиционировала написание веб-приложений как одно из основных направлений использования своего продукта.
Вы ошибаетесь. Профессионал это когда знает тонкости языка а не когда скачет по всем языкам одновременно.
С чего бы это? Вот мой личный пример: я на сишарпе в основном пишу, фулл бекенд разработчик уже 4 года, веб не трогал очень давно, еще со времен jquery-UI. И вот понадобилось мне пдфку рисовать. Смотрю библиотеки на этом моём сишарпе — а они все платные, с ценами сравнимыми с годовым бюджетом небольшого города
Пошел гуглить, нашел PDFKit — бесплатную простую либу на жс. Скачал ноду, поставил тайпскрипт, запилил сервис, настроил сваггер (опять же с помощью гугла). В итоге за пару дней задача решена, и дешевле чем за 70к$.
typescript-eslint — 0 варнингов выдает, с кодом ощущения что он плохо написан и не масштабируется нет.
Какой ваш совет "нескакателя по языкам" в такой ситуации?
Ну покажите пару примеров. Сразу скажу, что нужно именно рисовать, поэтому всякие wkhtmltopdf не подходят. Syncfusion платный, ironpdf не умеет что нужно, PdfiumLight имеет нативные зависимости,…
Вот 3 первых строчки гугла. Дальше всё то же самое. Больше всего порадовала библиотека libharu
, которая вообще даже мсбилд не использует, а для сборки нужно руками в csc файлы совать.
Как видите, я всё же искал, и не нашел. Причем я не скрываю, что возможно что-то подоходящее есть, но я не нашел. Но в чуть более редком случае библиотеки точно не будет.
Всё еще надеюсь получить пример библиотеки из "вашего" гугла.
Любопытно, спасибо, но опять же я рассчитывал найти чисто managed-вариант, потому что у нас разработчики пользуются и виндой, и маком, и линуксом, кому какой вариант больше нравится. Поэтому любая необходимость настраивать окружение это сразу жирный минус решению.
А тайпскрипт очень привычен C#-разработчикам, поэтому я решил что небольшая потеря в том, чтобы сделать на ноде (которая уже у всех стоит, т.к. требуется для запуска фронтенда).
Профессионал это когда знает тонкости языка а не когда скачет по всем языкам одновременно.
Профессионал — это когда есть результат: задачи закрыты, оплата получена.
Это профессионал по тонкостям языка и такой профессионал востребован в области разработки языков программирования скорее всего, а с точки зрения бизнеса он только вредит — поднимая планку требований к программистам в команде (делая стоимость часа команды суммарно выше).
Если от такого языкознания есть полезный выход (т.е. скажем код надежнее или быстрее, то это может быть оправдано), а в противном случае от такого умника убытки: сложно коллегам читать/понимать код, сложно модифицировать и т.д.
Чаще всего это герои одиночки и с ними крайне сложно работать коллегам.
> То в ларавел проекте вместо встроенных обьектов работает с прямым sql запросами
и глобальными обьектами запросов
А причем тут языки программирования? Это культура программирования и желание переиспользовать кода фреймворка и к знанию языков программирвоания отношения не имеет. Более того я могу скзаать, что в какой-то ситуации это может быть оправдано особенно если решение MVP и сроки сдачи очень небольшие, то можно и вовсе ограничиться интерфейсом на jQuery.
> То вместо правки скрипта сборщика пишет
Так тут я вообще потерял суть. В данном случае идет какой-то эникейщик работающий в разных ролях: разработка фронтенда и серверной стороноы и это уже вообще уходит в административные какие-то проблемы. Это вообще к делу отношения не имеет.
> Вот автора поста как раз можно упрекнуть в недостатке любопытства
А почему Вы считаете, что Ваша ценность «любопытство» (прим. любопытство к уже готовым продуктам) должна быть у автора поста? Это разновидность экономии денег заказчика за счет использования чужого кода и многих разработчиков заставляют учитывать это в разработке, что в каждом конкретном случае приводит как к ряду достоинств так и ряду недостатков.
> Вместо того чтоб взять наиболее подходящий инструмент для веба он костылит свое решение
Вместо того что бы «купить» уже готовый инструмент Вы хотели сказать, т.е. делегировать работу другим людям. Думаете такая покупка выйдет дешевле? С учетом всех тонкостей «купленного» решения?
> на мертвом паскале
В смысле мертвый? Основы синтаксиса языка можно освоить за несколько часов. Интерпретатор FPC работает под все популярные платформы (хотя я не совсем понял ситуацию с x86_64). Исходный код открыт и можно дописать необходимый функционал в RTL при острой необходимости. Рынок труда Pascal сегодня в основном конечно жив благодаря банковским решениям, но все равно специалистов на рынке найти можно. А Вы скорее говорите про модные языки вроде: Ruby, JavaScript и PHP говорите, так как любой школьник в любом форуме найдет решение, так не думаю, что это как раз хорошо. Это огромная проблема, так как происходит переход в ИТ людей далеких от программирования (т.е. без технического образования). С другой стороны они тоже нужны типовые сайты делать.
> в итоге воюет с собственным поделием
По подробнее с чем у него проблема. Я возможно пропустил.
> Как продакшн решение явно нет.
Так основная проблема это низкая популярность языка программироания Pascal? Высокая стоимость специалистов? В чем проблема для бизнеса здесь?
Ну, найти спецов которые пишут на ассемблере, конечно труднее. Но я бы не сказал что на паскале нельзя найти хороших программистов. Тем более в России где традиции Паскал/Делфи все еще не исчезли совсем.
И да, бизнес строит сайты на веб фреймворках и платит меньше за поддержки, но очевидно намного больше за хостинг и администрацию этого хостинга. Для очень популярных проектов, это совсем не мало.
Я с вами совершенно согласен, что для бизнеса по созданию сайтов, паскаль — очень плохой вариант. Это очевидно. Но если это бизнес, использующий Delphi в основной своей деятельности, и у этого бизнеса появилась побочная задача сделать себе сайт и поддерживать его, то не исключена ситуация, когда окажется выгоднее не нанимать для этого отдельного веб-разработчика, а справиться своими силами.
Вообще, по определению слова, профессионал — это тот, кто зарабатывает себе на жизнь профессией. Тонкостей языка здесь нет, и использовать для каждой подзадачи подходящий язык вполне может быть нормой.
Модули. Именно это я и сделал — выделил модуль SCGI для самостоятельного использования.
Так я в статье как-раз и привел пример "Hello World" на SCGI.
Стандартного менеджера пакетов к сожалению нет — imho это серьёзная проблема, возникшая из-за исторически сложившейся дистрибуции бинарных пакетов.
Сейчас в Delphi есть GetIt Package Manager, но там ловить в общем-то нечего — все классные библиотеки нужно искать на сайтах.
Perl, CGI, Pascal… Сколько ж лет с тех времён прошло, 20 так уж точно. Прям машина времени ) Интересно жив ли ещё mod_perl апачевский.
Люди нажимали F5, чем ещё больше усугубляли проблему. Оказалось, что даже 4-5 запросов в секунду к CGI-скрипту, запускаемому в виде отдельного Perl-процесса, ощутимо замедляют сервер, а >10 запросов в секунду делают его совсем недоступным.
1. Нет смысла писать на голом CGI и Perl, когда есть uWSGI Perl.
2. Можно кешировать таблицу веб-сервером (nginx)
Так есть и FastCGI и SCGI. Но идея писать, а тем более дебажить такое на Perl меня весьма пугала. Хотя вероятно для опытного Perl-разработчика это норм.
Если таблицу можно кэшировать сервером, значит её можно и вовсе сделать статической. Что, собственно, я в итоге и сделал. Ведь смысл скрипта как-раз в том, чтобы генерировать уникальный контент.
Если таблицу можно кэшировать сервером, значит её можно и вовсе сделать статической. Что, собственно, я в итоге и сделал. Ведь смысл скрипта как-раз в том, чтобы генерировать уникальный контент.
Простите, я больше сисадмин, чем программист. Но зачем мучаться и делать статический контент самому, когда кеш в вебсервере — 1 строка конфига?
И да. uWSGI точно выдержали бы ту нагрузку, от которой падал CGI.
В конфиге nginx вроде можно указать, что кеш ответа бекенда будет валиден, допустим, 1 секунду. Этого хватит, чтобы выдержать любой наплыв посетителей.
Кэш валиден только для того конкретного пользователя, для которого этот ответ сформирован.
Но если контент статический, то действительно не вижу особой разницы между включением кэширования и рендером статической страницы.
Да полноте, на FastCGI обычный скрипт даже в те времена переписывается банальным оборачиванием в
while (my $cgi = CGI::Fast)
Проблемы с отладкой совершенно непонятны — какая разница с другими языками?
Я могу неделями мучаться мыслями о том, что ну вот это технология вроде более популярна, а вот этот язык вроде лучше будет использовать вот в этом сценарии, а вот так писать как-то неправильно, а вот этот кусок кода какой-то не такой. И при этом у меня нет ни одного законченого pet projec'a (что логично). Как вам это удаётя? У вас настолько стабильная самооценка? Если да, то за счёт чего? Программирование — ваша основная работа?
Извините за такой лютый офтоп, но мне правда очень интересно узнать.
Как вам это удаётя?
"Без тени сомнений, не пряча лица — идти к своей цели дорогой бойца."
function UpdateAccount
db.Query('UPDATE profiles SET notify="%s" WHERE id=%d',[profile.notificationMode,profile.id]);
if db.lastError='' then result:='OK'
else result:='Internal error';
Результат конечно занимательный, но так уже даже на PHP не пишут)
Серьезно, со знаниями Delphi разобраться в PHP можно за пару недель. Но на чистом PHP тоже писать не надо, лучше использовать фреймворк. Там уже предусмотрены защиты от основных уязвимостей и работа с базой. Для начинающего подойдет Yii 2, он простой и у него неплохая документация.
Но форматирование кода в примерах это ад какой-то. Пробелы Вам кто запретил использовать?
P.S. В целом хотел бы попробовать разработать что-то на FPC для сайта, но сотанавливает какая-то темнота во всех WSGI, uWSGI, SCGI и прочих протоколах, а орагнизовать парсер HTTP на Pascal на мой взгляд задача сложная (дорогая). Так что было бы интересно увидеть библиотеки или даже какой-то форум по разработке Web решений на Pascal.
P.P.S. Удачи и успешного движения вперед.
Список множества Web фреймворков Delphi:
community.idera.com/developer-tools/b/blog/posts/evaluating-web-development-frameworks-for-delphi
От себя отмечу:
unigui.com
www.tmssoftware.com/site/tmswebcore.asp
С первым работаю плотно сам. О втором хорошие отзывы. Но, правда, оба платные.
FPC/Lazarus:
wiki.lazarus.freepascal.org
forum.lazarus.freepascal.org/index.php?topic=47999.0
Delphi Community Edition, бесплатная версия (с условиями):
www.embarcadero.com/ru/products/delphi/starter
Lazrus/FPC весь бесплатный. Проще всего его устанавливать с помощью fpcupdeluxe:
wiki.freepascal.org/fpcupdeluxe
Поддерживаемый список бесплатных компонент и библиотек:
github.com/Fr0sT-Brutal/awesome-pascal
Платных живых пакетов можно найти намного больше, по вебу конкретно — по ссылкам выше.
но с другой стороны непонятно, что там с потоками, асинхронной обработкой запросов и реализацией уймы вещей вроде: списков, словарей, соединений с базой данных и т.д.Всё конечно же со всем этим хорошо, больше проблема выбора чем наличия инструментов.
Можете с вопросами заходить поинтересоваться на телеграмм каналы (живые и весьма активные, не только веб):
t.me/Delphi_Lazarus
t.me/DelphiCommunity
непонятно, что там с потоками, асинхронной обработкой запросов и реализацией уймы вещей вроде: списков, словарей, соединений с базой данных и т.д.
Готовые решение есть в вышеупомянутом mORMot. Чтоб не заморачиваться с *SGI, разумно просто слушать порт, а впереди поставить тот-же nginx для удобного управления статикой, кешированием и т.п.
Картинки форума Унигуя
А сайт Унигуя сделан на Унигуе? ;)
Все конечно хорошо, только привязка к Delphi, который сам по себе не дешев + минимум $400 за unigui
Community Edition бесплатный, а если доход >$5K, то можно и раскошелиться на лицензию. Я слышал много нытья от разных людей про дороговизну лицензии, но серьёзно — на фоне burn rate программиста это не такая уж значительная сумма. Хотя я, конечно, предпочёл бы чтобы он стоил дешевле. Тот же 3D Max стоит дороже, но им вовсю пользуются, несмотря на наличие бесплатного Blender'а.
У меня сайт и сами игры написаны вообще в Turbo Delphi Explorer, который бесплатный без ограничений по доходу.
Не понял, что значит "всегда использует стековую память"? Насколько я помню, там точно такая же типичная алголовская схема со стекфреймом на каждый вызов функции и аллокации в куче для всяких "динамических массивов" и прочего.
На стеке паскаль наверное хранить по-дефолту может только строки, потому что они всегда известной длины, но даже в этом я не уверен. Хип наверняка исползуется плюсовым типом vector по-дефолту, но можно же взять подходящий тип с аллокацией не стеке?
и аллокации в куче для всяких «динамических массивов» и прочего
Сейчас посмотрел ради интереса и действительно fpc_dynarray_setlength (rtl/inc/dynarr.inc) использует вызов getmem (подозреваю, что это аналог malloc), так что тоже хип.
Тогда с точки зрения производительности нет разницы использовать C/C++ или Pascal?
И то и то алгол, отличия только в синтаксисе по сути. Идеология за ними одна и та же, появились они с разницей в 2 года, ну и так далее. Как сишарп и джава — братья-близнецы. Разве что те еще и по синтаксису один в один. А вот если сравнить Java/F#, то получится очень похоже.
Ещё типично, когда на одной операционке #include сделал вроде бы для всего, а эти #include потащили другие #include, а на другой целевой платформе не потащили. И вот, значит, в неподходящий момент мы узнаём об этом. Сильнейшее желание свалить из этого дурдома.
Строки на стеке — это где угодно. Я слышал в додо пицце их даже на сишарпе делали. А-ля
struct String8
{
public char Char1 { get; set; }
public char Char2 { get; set; }
public char Char3 { get; set; }
public char Char4 { get; set; }
public char Char5 { get; set; }
public char Char6 { get; set; }
public char Char7 { get; set; }
public char Char8 { get; set; }
}
Ну или более разумно (для общего случая):
unsafe struct StackStirng
{
public fixed char Value[8];
}
Хотя лучше всего конечно в расте — там все стандартные функции будут работать с такими строками, в сишарпе пришлось накопипастить реализацию. Но — работает же.
Да, в Расте строки делали по подобию адских
В расте тоже стековая строка будет фиксированного размера, см. smallvec или heapless.
Мне даже интересен механизм как должны работать строки динамического размера на стеке, а то ведь это противоречит функциональности стекфрейма который статически знает сколько у него локальных переменных и сколько им нужно места суммарно.
{stackstring x; x += "added"} ->
{ x.buf = alloca(x.len+5), copy(oldbuf, newbuf)}
да и с передачей таких параметров по ссылке проблема…А если в стекфрейме нет столько места, то что делать?
The alloca() function returns a pointer to the beginning of the allocated space. If the allocation causes stack overflow, program behavior is undefined.
Не очень удобно. Не говоря о том, что вернуть такую строку из функции не выйдет.
Впрочем, дефолтный размер стека уже давно не менее 1МБ (win), 10МБ (lin), так что на пару строчек должно хватить.
Конечно, цикл вроде
for i:=1 to 100000 do s := s + 'a'
сломает такую системуВопрос в переполнении стекфрейма, а не всего стека, потому что мы еще другие функции вызывать может хотим, ну да ладно.
В любом случае остается вопрос — как эту строчку из функции вызывать? Потому что в сишарпе вон в примере выше я её могу вернуть — просто её содержимое будет скопировано в стекрейм вызывающей функции. А с этой штукой компилятор никак заранее не может узнать солько ему места резервировать под результат.
В Pascal строка на стеке называется ShortString, может иметь длину до 255 символов.
Кстати, написать парсер (сервер) HTTP — задача не сложная и не дорогая даже без каких-либо библиотек. Протокол сложный в реализации на клиенте, а на сервере можно ограничиться весьма простой реализацией. У меня сервер игры как-раз работает как HTTP-сервер. А SCGI еще проще.
HTTP относительно простой протокол, но он всё еще сложный, потому что начинаются приколы при попытки реализации:
стриминга и пайплайнинга
Keep-alive и бэкпрешура
вебсокетов
Прозрачной компрессии контента (br, gzip, deflate)
Multipart стримов
ССЛ
И это я не говорю про корнер-кейсы, которые хттп разрешает (например, побить один файл на несколько мультипарт стримов).
И это кстати не иезуитское знание, вполне реально словить sql injection атаку в общем случае.
Интересный опыт, спасибо за публикацию. Для меня Паскаль — это приятная ностальгия, язык, который ассоциируется с понятиями "простота" и "стабильность", отлично подходящий для изучения базовых алгоритмов. Во многих школах Паскаль до сих пор используют для обучения программированию. И после вашей статьи стало особенно приятно осознавать, что старичок Паскаль может в бэкэнд :)
Другое дело, позор тем, кто для nginx выбрал не Аду или хотя бы Паскаль. Фу таким быть
Мне как бывшему паскалисту, это было интересно. И вполне соответствует моей теорией, что веб движется к более широкому использованию компилируемых языков.
Интересно было бы узнать на каком сервере крутится этот сайт. А также, какие-нибудь числа о производительности – например какое типичное время обработки запроса. (понятно, что это варьирует), какая СУБД использована и подобное.
Ну, чтобы сравнить с моим наработкам на ассемблере.
Сервер: Xeon 3430@2.4GHz
База: MySQL 5.1
Типичное время обработки запроса к главной странице — 50 мс (12 SQL-запросов).
В данном случае производительность упирается в БД, форматирование текста — это мизер. Если поставить задачу повысить производительность, то в первую очередь надо избавиться от лишних запросов к БД.
форматирование текста — это мизер
Ну-у-у, я бы не сказал… У меня время получается вроде 50:50 запросы/текстообработка. Правда у меня БД SQLite — она может и побыстрее будет. Количество запросов сравнимое.
А это физический сервер или VPS? И сколько ядер и RAM у него?
По статье несколько вопросов.
Про медленный Perl. Тут хочется отметить, что Perl всё же довольно быстр, но в стеке с CGI могло быть что-то не оптимально настроено. Никому не говорите про медленный Perl. Во многих вещах Perl невозможно заменить по параметру скорости выполнения. Например, те же регулярные выражения.
Про NodeJS. Напрасно вы так про JS. Я понимаю, конечно, когда есть неприязнь, например, к ФП. Но JS как сам ЯП ничем особым не выделяется, чтобы прямо совсем быть таким неприятным.
Я бы и сам уже не делал ничего на JS. В двадцать первом веке есть Go. И даже Go медленно но верно сменяет поколение Rust. Но, опять же, я считаю, что бы эффективно программировать на Go и тем более на Rust, хороший большой опыт работы на NodeJS просто необходим. Это моё личное мнение. Был бы рад услышать обратное, если таковые программеры среди нас присутствуют.
Медленный скорее сам CGI, а не Perl (из-за создания процесса). Но даже в случае CGI, гораздо быстрее запустить скомпилированный бинарник, чем интерпретатор, который при запуске грузит либы (сотни файловых операций!) и парсит код. На этом фоне скорость выполнения собственно кода логики скрипта имеет мало значения.
Но даже в случае CGI, гораздо быстрее запустить скомпилированный бинарник, чем интерпретатор
perlcc поставляется вместе с perl. Но скомпилированный код запускается не на много быстрее скрипта. Та проблема требует кастомизации ядра ОС — настроить быстро можно, но на это уходит немного времени, так как это не универсальные настройки, а непосредственно под CGI.
Эти операторные скобки конечно дно, на delphi не то что сайт, на нем программы под windows писать это конкретное потрясение, а про андроид я вообще молчу. Помню один раз начинал писать проигрыватель видео под андроид, так неделю потратил, звук идёт, а картинки нет + приложение пустое весило 30мб. Бросил я этот колхоз, сутки почитал примеры java и за 5 минут плеер заработал запоказывал видео и звук. По сути для каждой задачи нужно свое нативное решение, а не универсальные колхозы. Это как подобрать универсальный чехол на телефон - там три дырки под две камеры, тут щель, иногда чехол спадает и т.д.
И как долго вы разбирались как делать приложение под Андроид? Поняли ли, что есть и нативный фреймворк для создания приложение под iOS/Android на Delphi? Где ваш видео плеер - это пол минуты работы.
Я тут пытаюсь VPN службу на Android Delphi распинать. В пересчёте на 8-часовые дни, наверное, тоже на неделю потянет. В принципе, есть много, с чем согласиться и не согласиться.
Можно согласиться в том плане, что за пределами исследованной области на Delphi бывает жестковато. Диалог создания службы в Delphi выглядит так:

Вот просто смотришь, и фрустрация. Эм… ну… VPN бы мне. А что из этого VPN? После изучения иерархии классов понятно, что точно не Intent. А что тогда? VpnService = Local или Remote? А если я ошибся и выбрал не то, как исправить. На что это влияет?
Тут, конечно, много открытий ждало меня. Но вспоминая полностью независимую разработку на Objective-C 2.0, я всё ещё считаю, что оно того не стоит. Только Elevation через XPC был оправдан, а всё остальное не стоило того. UI и JSON постоянно менять в двух клиентах, и отказались от этого.
Примеры игрушечных VPN на Java/Kotlin есть, но я же ничего действительно толкового не могу с ними сделать, если я не врубился, так как же всё устроено. Android VpnService = Local или Remote? Started или Bound? Как узнать, что служба запущена? Для VPN несколько примеров на Java/Kotlin, и они отличаются. Запросто может отсутствовать проверка, что VpnService уже запущена. Остановка службы из программы сделана по-разному. Без понимания сути не сильно бы это помогло. А с пониманием сути удобнее поддерживать кроссплатформенный единый код, допиливая рашпилем только выходы наружу в операционную систему.
Ну да, кое-что Embarcadero стоило бы расписать получше в документации.
Разработка веб-сайта на паскале (backend)