LINUX.ORG.RU

А может пора переходить на лисп?

 ,


1

2

Меня тут обвинил коллега в том, что я на любом языке пишу как на лиспе. Я посмотрел свой код в новом проекте и понял что обвинения были не на совсем пустом месте, практически все написано примерно вот в таком стиле

    public List<MethodDescription> available(MethodType type) {
        return ctx.getBeansWithAnnotation(MethodProvider.class).entrySet()
            .stream()
            .map(Map.Entry::getValue)
            .flatMap(e -> Arrays.asList(e.getClass().getMethods()).stream())
            .filter(m -> m.getAnnotation(Method.class) != null && m.getAnnotation(Method.class).type() == type)
            .map(fm -> fm.getAnnotation(Method.class))
            .map(a -> new MethodDescription(
                a.value(),
                src.getMessage("method." + a.value(), null, a.value(), dh.getLocale()),
                src.getMessage("method." + a.value() + ".description", null, a.description(), dh.getLocale())))
            .collect(toList());
    }

Может действительно пора переходить на тот же clojure?

Перемещено maxcom из talks

★★★★

Ответ на: комментарий от vurdalak

Вот этот кусок кода он и написал как положено, имхо

stevejobs ★★★★☆
()
Ответ на: комментарий от Legioner

лучше переписать в императивном стиле

и получить две страницы невнятных циклов. Вот это повышение читаемости!

думаешь, через годик-другой чтения такого кода он не станет казаться очевидным настолько же, насколько циклы?

stevejobs ★★★★☆
()

Может действительно пора переходить на тот же clojure?

вероятно все эти фичи в Java8 добавили как раз затем, что перейти на кложур нереально?

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)

Всё лучше чем джава, даже клисп.

fenris ★★★★★
()
Ответ на: комментарий от post-factum

Ну ясно.

Кстати, я встречал подход где все лямбдочки-аргументы выносятся в отдельные переменные (по-моему, даже статические), называются говорящими именами и от этого операции на стримах читаются прямо как естественный язык. Кто что про это думает?

anonymous
()
Ответ на: комментарий от stevejobs

и получить две страницы невнятных циклов. Вот это повышение читаемости!

Конечно повышение. Сейчас это прочитать вообще невозможно. С циклами это станет возможно.

думаешь, через годик-другой чтения такого кода он не станет казаться очевидным настолько же, насколько циклы?

Тут проблема не в циклах, а в отсутствии нормального именования идентификаторов и явного указания типов в первую очередь. Ну и когда всё в кучу - это тоже сказывается, хотя и в меньшей степени. Если тут каждую переменную назвать нормально, явно прописать все типы, читать станет проще. Только каждую строчку раздует так, что захочется уже написать нормально, а не переносами.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Ты по работе на 6 йаве пишешь или не 7?

anonymous
()
Ответ на: комментарий от Legioner

Конечно повышение. Сейчас это прочитать вообще невозможно. С циклами это станет возможно.

Да ты же просто не осилил. Перепиши с циклами и сравни. Количество шума увеличиться в разы, что цикл что-то там фильтрует, например, будет понятно далеко не сразу. Зато появится куча дебильных итераторов.

Kuzy ★★★
()
Последнее исправление: Kuzy (всего исправлений: 1)
Ответ на: комментарий от Legioner

Сейчас это прочитать вообще невозможно

Ты читать-то умеешь?

И да, толсто.

tailgunner ★★★★★
()
Ответ на: комментарий от Legioner

про названия идентификаторов частично согласен. Лучше было бы вообще сделать идентификаторы без названия. Мы же не обращаемся к промежуточным элементам, зачем нам их имена? Но джава так не умеет, приходится писать какое-нибудь говнецо в имя.

а вот про типы не согласен. Нам же неважно, что там будут за промежуточные типы, мы их нигде не используем, это просто какие-то переходные формы в трансформации

вот и пример скалы как «улучшенной джавы»

более полно:

scala> val helpers = Vector("adam", "kim", "melissa")
helpers: scala.collection.immutable.Vector[java.lang.String] =
    Vector(adam, kim, melissa)

// the long form
scala> val caps = helpers.map(e => e.capitalize)
caps: scala.collection.immutable.Vector[String] = Vector(Adam, Kim, Melissa)

// the short form
scala> val caps = helpers.map(_.capitalize)
caps: scala.collection.immutable.Vector[String] = Vector(Adam, Kim, Melissa)

слева никаких типов, только val. У вектора никакого спецификатора типа. Компилятор сам выведет тип, если ему очень надо.

Из (e => e.capitalize) выбросили нафиг идентификатор e.

Всё работает, всё ок.

Т.е. код из топика можно было бы еще лучше записать, если бы Джава не заставляла тащить вместе с кодом мусор.

Конечно повышение. Сейчас это прочитать вообще невозможно. С циклами это станет возможно.

ты привык к циклам, привык смотреть на цикл и выводить из него «что этот цикл делает». К цепи трансформаций тоже надо привыкнуть.

ты к циклам сколько привыкал, годы? К этому тоже нужно привыкать. Но меньше, потому что тебя не беспокоит, как именно происходит трансформация. Она происходит КАК-ТО, это не твоя забота, это забота компилятора. Если там написано мап - значит мап, и это всё что тебя должно беспокоить.

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 2)
Ответ на: комментарий от quantum-troll

на clojure вполне в похожем стиле можно все нарисовать, если использовать форму (-> или (->>

Маленький пример на титульной странице http://clojuredocs.org/

;; Let's define some data using list / map
;; literals:

(def scenes [{:subject  "Frankie"
              :action   "say"
              :object   "relax"}

             {:subject  "Lucy"
              :action   "❤s"
              :object   "Clojure"}

             {:subject  "Rich"
              :action   "tries"
              :object   "a new conditioner"}])

;; Define a function
(defn people-in-scenes [scenes]
  (->> scenes
       (map :subject)
       (interpose ", ")
       (reduce str)))


;; Who's in our scenes?

(println "People:" (people-in-scenes scenes))

;;=> People: Frankie, Lucy, Rich
habamax ★★★
()

TL;DR.

А причём тут Лисп? У вас, батенька, монады головного мозга. Не отчаивайтесь! Специально для таких моральных уродов как вы, придумали Хаскель.

Macil ★★★★★
()
Ответ на: комментарий от habamax

Ох это чудное сочетание отсутствия синтаксиса с его наличием. Ок, тогда может быть.

quantum-troll ★★★★★
()

По-моему, ты пишешь как на Скале.

Miguel ★★★★★
()
Ответ на: комментарий от vertexua

Не знаю, в (http://shop.oreilly.com/product/0636920028499.do) есть пример для одного фильтра, в котором && и двух отдельных фильтров, и хоть стримы и ленивые, производительность была выше в случае, когда два условия в одном. То есть, ящатаю, если можно слегка быстрее делать это за счет простого скидывания в один синк всех операций - нужно это делать. Если хочется красоты - наделать функторов и через andThen потом их в самой карте слепить.

anonymous
()
Ответ на: комментарий от anonymous

ой, заговорился. s/в самой карте/внутри map.

anonymous
()
Ответ на: комментарий от anonymous

Да нет, он сначала фильтрует, а потом map. А можна наоборот и будет короче. И меньше вызовов той пурги с getAnnotation

vertexua ★★★★★
()

Этот код норм. Раз коллеги дают замечания, то видимо проблема таки глобальнее. Видимо там где нужно писать понятный и поддерживаемый код ты пищешь не его. По чаще давай ревьювать коллегам. Также не мешает почитать Clean Code Мартина.

ii8_ ★★★★
()
Ответ на: комментарий от Nagwal

Не уберу, мне нравится это почти что селфи :)

Не правда! Ты - робот. Только роботы могу такой код писать, и тем более понимать ;)

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от ii8_

коллеги могут сказать «этот пример кода непонятный и неподдерживаемый, потому что мы не знаем и знать не хотим этих фильтров». И «результат» их ревью будет в том, чтобы всё стереть и написать по-своему на циклах. Тащем-то видим в этом треде подобный настрой

stevejobs ★★★★☆
()
Ответ на: комментарий от vertexua

Там нет особых странностей. Просто я не полностью описал задачу. Есть бины, помеченные аннотацией @MethodProvider, в них есть методы, помеченные аннотацией @Method - у которой еще параметр MethodType, ограничивающий его применимость.

Задача - найти все методы, применимые к переданному в параметр функции типу.

Nagwal ★★★★
() автор топика
Последнее исправление: Nagwal (всего исправлений: 1)
Ответ на: комментарий от ii8_

Раз коллеги дают замечания, то видимо проблема таки глобальнее. Видимо там где нужно писать понятный и поддерживаемый код ты пищешь не его. По чаще давай ревьювать коллегам. Также не мешает почитать Clean Code Мартина.

Я делаю проще - посылаю коллег с их замечаниями нафиг. Поскольку просто не берусь за проект, если я там не буду главным по технической части :) И никаких проблем с чтением всякой нудятины.

Nagwal ★★★★
() автор топика
Ответ на: комментарий от Nagwal

Хотя да, можно наверное избавиться от первого мапа, да и от второго тоже, но тогда как раз в третьем будет мешанина.

Nagwal ★★★★
() автор топика
Ответ на: комментарий от vertexua

Я вижу, что он фильтрует. Я о том, что если в один вызов .мап() впихнуть все, что размазано сейчас, можно выиграть в производительности.

anonymous
()
Ответ на: комментарий от stevejobs

Кстати, справедливости ради стоит отметить, что такие вырожденные случаи в йаве тоже решаются короче - с помощью method reference.

anonymous
()
Ответ на: комментарий от anonymous

Я о том, что если в один вызов .мап() впихнуть все, что размазано сейчас, можно выиграть в производительности.

Ну, там можно по идее обойтись одним flatMap и одним filter. Вопрос в том, что не особо нужно. Конкретно этот метод дергается только при старте сервера или изменении настроек системы, так что над производительностью я даже не задумывался. Да и объемы данных там минимальны. Десяток-другой классов, в каждом по 5-10 методов, говорить не о чем.

Nagwal ★★★★
() автор топика
Ответ на: комментарий от Nagwal

просто я хоть и сторонник этих штучек, но здесь чтение такой цепочки похоже на слушанье заики - на каждый .мап у тебя самого что-то внутри запинается)

anonymous
()
Ответ на: комментарий от anonymous

Ну фиг знает, по моему все логично довольно таки, кроме самомго первого мапа. Сложить все методы всех классов в линейный стрим, потом отфильтровать нужные, потом собрать из нужных объекты, описывающие эти методы.

Nagwal ★★★★
() автор топика

Почитай MC Конелла разок штоле

Раз ты такой из себя «старший индус в проекте»

И, да, этот говнокод - близко не лиспстайл.

d_Artagnan ★★
()

Все верно. Такой стиль и пошел от первых лиспов. Еще до появления Common Lisp. Некоторые современные лисперы, правда, не любят почему-то его, но это уже тараканы тех некоторых лисперов)

dave ★★★★★
()
Ответ на: комментарий от Nagwal

Это всё хорошо. Но в команде работать веселее и лучше во всех отношения, даже качества кода) ЧСВ - это хорошо, но перебарщивать не надо же. Важно же продукт годный на выходе почить, имхо.

ii8_ ★★★★
()
Ответ на: комментарий от ii8_

По моим наблюдениям качество кода ортогонально тому стилю, в котором такой код написан. Либо код качественный, либо нет. Стиль и парадигмы программирования тут обычно ни причем.

Есть лишь та связь, что более эрудированный человек может писать лучший код, что верно для хорошего программиста, но сейчас развелось так много понтующихся бездарей. Вроде бы и говорят и пишут умно, слова складные знают, а делать ни фига не умеют. Есть такие и из тех, кто пытается использовать ФП.

dave ★★★★★
()
Ответ на: комментарий от NeXTSTEP

Не так потому что надо напрягаться и вчитываться длинные строки читать. 13 строк, а понимание только через минуту достигается. Всё должно быть понятно при беглом окидывании взгляда.

turtle_bazon ★★★★★
()
Ответ на: комментарий от Nagwal

У кложуры минус один есть, что практически единственная среда разработоки для него более или менее нормальная - это емакс.

turtle_bazon ★★★★★
()
Ответ на: комментарий от turtle_bazon

Ну да, писать такое на анонимных классах - это совсем уж звиздец получается. А тут все вроде довольно просто читается, вопрос привычки.

Nagwal ★★★★
() автор топика
Ответ на: комментарий от turtle_bazon

Фиг знает, я пока на counterclockwise посмотрел, вроде работает. Эклипс конечно после идеи ужасен, но люди пользуются и не жалуются.

Nagwal ★★★★
() автор топика
Последнее исправление: Nagwal (всего исправлений: 1)
Ответ на: комментарий от turtle_bazon

Вот и я говорю, ниша у лиспа одна - писать плагины к emacs. Возможно именно поэтому емакс получился таким комбайном.

Siado ★★★★★
()
Ответ на: комментарий от rupert

Угу. Чище некуда.

(defn create-prognoze-table
  ""
  [parent]
  (let [table-viewer (new TableViewer parent SWT/NONE)
        table (.getTable table-viewer)
        column-layout (new TableColumnLayout)
        accuracy-profiles (find-accuracyprofiles)
        ap-count (count accuracy-profiles)]
    (reset! current-display (Display/getCurrent))
    (reset! observed-table-viewer table-viewer)
    (.setHeaderVisible table true)
    (.setLinesVisible table true)
    (let [event-id-column (new TableColumn table SWT/NONE)
          event-name-column (new TableColumn table SWT/NONE)]
      (.setText event-id-column "Ид")
      (.setText event-name-column "Событие")
      (.setColumnData column-layout event-id-column (new ColumnPixelData 70))
      (.setColumnData column-layout event-name-column (new ColumnWeightData 1)))
    (doseq [aprofile accuracy-profiles]
      (let [apcolumn (new TableColumn table SWT/NONE)]
        (.setText apcolumn (str "AP:" (get aprofile :id)))
        (.setColumnData column-layout apcolumn (new ColumnPixelData 40))))
    (doseq [[_ _ pname] bet-params :when pname]
      (let [column (new TableColumn table SWT/NONE)]
        (.setText column pname)
        (.setColumnData column-layout column (new ColumnPixelData 40))))
    (.setLayout parent column-layout)
    (doto table-viewer
      (.setContentProvider
        (proxy [ArrayContentProvider IStructuredContentProvider] []
          (getElements
            [input-element]
            (let [accuracy-profiles-computed (into {} (for [aprofile (compute-accuracyprofile-count)]
                                                        [(get aprofile :accuracyprofileid) aprofile]))
                  sorted-event-ids (sort (keys @cached-footballs))]
              (to-array
                (for [event-id sorted-event-ids]
                  (let [db-event (find-event event-id)
                        content (atom (assoc (make-persistence-event
                                               (get @cached-footballs event-id))
                                             :name (get db-event :name)))]
                    (doseq [aprofile accuracy-profiles]
                      (let [normalized-event (normalize-event aprofile @content)
                            aprofile-id (get aprofile :id)
                            event-count (count-footballgoalevents aprofile normalized-event)
                            sum-ap (get (get accuracy-profiles-computed aprofile-id) :sumcount)]
                        (reset! content (assoc @content (str "AP" (get aprofile :id))
                                               (if sum-ap (/ (if event-count event-count 0) sum-ap) 0)))))
                    @content)))))))
      (.setLabelProvider
        (proxy [BaseLabelProvider ITableLabelProvider ITableColorProvider] []
          (getColumnImage
            [object column])
          (getColumnText
            [object column-number]
            (match
              column-number
              0 (str (get object :eventid))
              1 (get object :name)
              _ (let [corrected-column-number (- column-number 2)]
                  (if (< corrected-column-number ap-count)
                    (format "%d%%" (int (+ 0.5 (* 100 (nil-double (get object (str "AP" (get (get accuracy-profiles corrected-column-number) :id))))))))
                    (let [bet-paramed-column-number (- corrected-column-number ap-count)
                          bet-param (get bet-params bet-paramed-column-number)
                          cname (first bet-param)
                          ctype (second bet-param)]
                      (match
                        (name cname)
                        "time" (monotonic-time-format
                                 (get object :eventid)
                                 (get object cname)
                                 (get object :timeus))
                        "p_total" (nil-format "%.1f" (nil-double (get object cname)))
                        _ (match
                            (name ctype)
                            "int" (str (get object cname))
                            "double" (nil-format "%.2f" (nil-double (get object cname)))
                            _ nil)))))))
          (getForeground
            [object column])
          (getBackground
            [object column]
            (let [event-id (get object :eventid)
                  bet-paramed-column-number (- column 2 ap-count)
                  bet-param (get bet-params bet-paramed-column-number)
                  cname (first bet-param)
                  ctype (second bet-param)
                  mutated-color (if (score-mutated? event-id) (get-color SWT/COLOR_CYAN) nil)
                  cmp-common (fn [param]
                               (match
                                 (name (nil-cmp (param-mutates event-id param)))
                                 "+" (get-color SWT/COLOR_GREEN)
                                 "-" (get-color SWT/COLOR_YELLOW)
                                 "0" mutated-color))]
              (match
                (name (if cname cname ""))
                "p_bol" (cmp-common :pB)
                "p_men" (cmp-common :pM)
                _ mutated-color)))))
      (.setInput :initial-data))))
turtle_bazon ★★★★★
()
Ответ на: комментарий от Nagwal

На анонимных - это вешалка. Но мой коллега один так писал-писал, потом свалил. :) Ну и вопрос про простоту я уже раскрывал.

turtle_bazon ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.