Вот именно такую заметку я нашел, когда пытался подыскать подходящую версию CSV парсера для нашего приложения, - Stop Rolling Your Own CSV Parser.
Каждое предложение было до боли знакомо - после безуспешных попыток привести код в приемлемое состояние, захотелось все же воспользоваться готовым решением. Читая заметку, я был согласен с автором на 100%.
Дальнейший анализ все же показал, что не все так просто.
Во-первых, предлагаемый в заметке FileHelpers нам не подошел. Во-вторых, другие человеческие варианты было сложно найти (интернет засоряют написанные на коленке варианты). В-третьих, вот этот комментарий помог понять, что сложность CSV парсера слегка преувеличена:
I'm sorry, I don't get it. What's so hard about writing a CSV parser? It's just a finite state machine (one state variable + one large switch statement). And why would one want to use regular expressions here?Я уже писал об этом (по ссылке чуть-чуть UML, кода, паттернов), на самом деле CSV парсер - это не сложно, зато вы получаете именно тот интерфейс и именно ту функциональность, которые нужны для вашего приложения. К примеру, в нашем случае это потоковое чтение данных, поддержка gzip (сжатых файлов), работа с большими файлами (тестировалось на файлах объемом до нескольких сотен мегабайт).
На этот раз, правда, по просьбам читателей код теперь на github, так что CSV parser теперь еще можно и скачать, а можно и что-нибудь поменять в нем прямо на github-e. Как видите, все очень просто. Парсер не универсален, но он успешно парсил реальные файлы - именно те, которые нам нужно было парсить.
Свое vs. Чужое
Однако, я бы хотел подробней остановиться на дилемме - писать свое или взять готовое. CSV парсер, конечно, маленький, не заслуживающий внимания пример, но неплохо иллюстрирующий в принципе глобальную проблему. Ведь иногда большая часть проекта основана на неком готовом решении (например, ETL проекты).
Эволюция программиста проходит через 3 этапа:
- Все время писать свое (переоценка сил, незнание популярных библиотек)
- Все время брать чужое (зрелое понимание реалий жизни - лучше взять готовое и быстрее сделать проект)
- Смешанный подход
Предугадать развитие событий сложно, обычно выходит так, что когда начинаешь осознавать проблемы, все уже в глубокой разработке и слишком поздно переключаться на свое решение. Поэтому если я сомневаюсь в доступных фреймворках, то я предпочитаю свое решение.
На что тратиться основное время при использовании готовых решений?
Поиск готового решения Сложно преувеличить масштаб вложений в поиск готовых решений. Все знают, что интернет сейчас не тот, что был. Отделить зерна от плевел, оценить подходящие решения, вникнуть в их плюсы и минусы, прочитать отзывы, разобраться в архитектуре, отбросить маркетинговую шелуху... Все это требует значительных усилий.
Изучение Когда разрабатывается некое решение для рынка, то обычно очень много тратиться времени на: хорошую архитектуру, гибкость, богатую функциональность. Эта болезнь всей индустрии и название ей швейцарский нож. Обычно решения очень перегружены и требуют неординарных усилий по изучению архитектурных плюшек, которые конкретно для вашего приложения не нужны. Немаловажно отметить высокую стоимость этого пункта для проекта - изучить решение требуется всем членам проекта, как старым, так и вновь прибывающим.
Кастомизация Редко когда удается найти решение, идеально подходящее для вашего проекта. Обычно чего-то не хватает и приходится дописывать. В лучшем случае. В худшем случае то, что вам требуется, не укладывается в архитектуру готового решения, и вам приходится с ней сражаться. Программисты это называют костылями. Стоит добавить, что при добавлении разработчиков в команду, такие костыли как минимум вызывают недоумение, а вообще тратится драгоценное время на дополнительные разъяснения.
Исправление ошибок Ошибки бывают, иногда их много. Иногда вы можете сами их исправить (в случае open source и со значительными затратами времени на погружение), иногда нет. Иногда их исправляют быстро, иногда вам приходится жить с ними, наслаивая очередной костыль на без того сложное решение. Если, конечно, ошибку можно обойти. Отдельно стоит упомянуть случаи, когда обработка ошибок (в правильном понимании) отсутствует как класс, и вы получаете абсолютно загадочные сообщения наподобие ThisNeverHappensError.
Проблема в квадрате И что также стоит принять во внимание - один из приведенных выше факторов может вырасти до проблемы просто неприличных размеров:
- Готовое решение более чем на 80% кастомизировано (я такое видел)
- Изучение готового решения не заканчивается никогда, новички просто не могут осилить его сложность
- Оно просто не справляется со своими обязанностями, там слишком много ошибок
Чем же привлекательно свое решение?
У вас есть шанс построить максимально простое решение, которое:
- Легко понимать
- Легко поддерживать
Кастомизация теряет свой смысл - ваше решение изначально максимально кастомизировано под ваши нужды.
Вы контролируете качество решения, например, вы можете быть уверены, что юнит-тесты пишутся. Если возникют проблемы с качеством, то вы можете предпринять корректирующие шаги, улучшить обработку ошибок.
Последний, но немаловажный фактор, - это интересно. Не поймите меня превратно, это интересно не только вам, но и вашей команде, а сплоченная команда работает гораздо эффективней.
Грязные детали
"Первый блин комом" - удачно характеризует многие попытки разрабатывать свои решения.
Понимание, что пошел не по тому пути и почему это не тот путь, приходит уже после того, как путь выбран. Мой маленький пример удачно это иллюстрирует - мы попытались написать свое, но первая попытка не удалась. После того, как она провалилась, и мы поискали решения. мы и узнали, как нужно было правильно писать парсер.
Серьезные решения требуют опытных разработчиков. Да, если вы только ступили на путь разработки, задумайтесь, а не стоит ли для начала поучиться на готовых примерах.
Примеры
Мои мысли результат не только моего опыта, у меня в запасе есть пара ярких примеров обоснования описанной концепции (Подчеркивая мысль, указанную в Грязных деталях выше - Ayende и Jeremy пришлось сначала наступить на грабли и только потом они уже написали свое. К сожалению, такова реальность):
Ayende Rahien (разработчик Rhino Mocks, NHibernate Profiler, etc.) настолько возненавидел SQL Server Integation Services, что решил написать свой ETL framework, в чем и преуспел - Rhino ETL.
Jeremy D. Miller пишет о том, как построить свой, родной Composite UI Application Block - How to build your own CAB, объясняет зачем это делать, почему это сравнимо по скорости с использованием CAB и рассказывает как это сделать.
Disclaimer
В конце концов, я просто за здоровую конкуренцию - много разных решений под всякие нужды и мир станет лучше. Но хотел бы еще раз подчеркнуть, что я скорее за смешанный подход - ведь существуют готовые решения, которые не нужно изучать (их все знают), они стабильны (потому что их все используют) и их легко кастомизировать (требования шли от реальных нужд разработчиков). Поэтому везде нужна своя золотая середина, а уметь соблюдать баланс - это и есть то самое, чему научить нельзя.
Если *возникют* проблемы с качеством
ОтветитьУдалить