Управление очень повторяющимся кодом и документацией на Java

StackOverflow https://stackoverflow.com/questions/2337170

Вопрос

Очень повторяющийся код, как правило, плохая вещь, и есть шаблоны дизайна, которые могут помочь минимизировать это. Однако иногда это просто неизбежно из -за ограничений самого языка. Возьмите следующий пример из java.util.Arrays:

/**
 * Assigns the specified long value to each element of the specified
 * range of the specified array of longs.  The range to be filled
 * extends from index <tt>fromIndex</tt>, inclusive, to index
 * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
 * range to be filled is empty.)
 *
 * @param a the array to be filled
 * @param fromIndex the index of the first element (inclusive) to be
 *        filled with the specified value
 * @param toIndex the index of the last element (exclusive) to be
 *        filled with the specified value
 * @param val the value to be stored in all elements of the array
 * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
 * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
 *         <tt>toIndex &gt; a.length</tt>
 */
public static void fill(long[] a, int fromIndex, int toIndex, long val) {
    rangeCheck(a.length, fromIndex, toIndex);
    for (int i=fromIndex; i<toIndex; i++)
        a[i] = val;
}

Приведенный выше фрагмент появляется в исходном коде 8 раз, с очень небольшим изменением в подписи документации/метода, но точно тот же метод корпус, один для каждого из типов корневых массивов int[], short[], char[], byte[], boolean[], double[], float[], а также Object[].

Я считаю, что, если никто не прибегает к размышлению (что само по себе является совершенно иным предметом), это повторение неизбежно. Я понимаю, что как утилита, такая высокая концентрация повторяющегося кода Java очень нетипична, но даже с лучшей практикой, Повторение происходит! Рефакторинг не всегда работает, потому что это не всегда возможно (очевидный случай - это когда повторение находится в документации).

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

Блог Google Research - Extra, Extra - Прочитайте все об этом: почти все бинарные поиски и Mergesorts сломаны (Джошуа Блох, инженер -программист)

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

    // int mid =(low + high) / 2; // the bug
    int mid = (low + high) >>> 1; // the fix

Вышеупомянутая линия Появится 11 раз в исходном коде!

Итак, мои вопросы:

  • Как эти виды повторяющихся кода/документации Java обрабатываются на практике? Как они развиваются, поддерживаются и протестируются?
    • Вы начинаете с «The Original» и делаете его как можно более зрелым, а затем копируете и вставьте по мере необходимости, и надеетесь, что вы не совершили ошибку?
    • И если вы совершили ошибку в оригинале, то просто исправьте ее везде, если вы не чувствуете себя комфортно, удаляя копии и повторяя весь процесс репликации?
    • И вы также применяете этот же процесс для кода тестирования?
  • Будет ли Java выиграть от какой-либо предварительной обработки исходного кода с ограниченным использованием для такого рода вещей?
    • Возможно, Sun имеет свой собственный препроцессор, который поможет писать, поддерживать, документировать и проверить этот вид повторяющегося библиотечного кода?

Комментарий запросил еще один пример, поэтому я вытащил этот из коллекций Google: com.google.common.base.predicates строки 276-310 (AndPredicate) против строк 312-346 (OrPredicate).

Источник для этих двух классов идентичен, за исключением:

  • AndPredicate против OrPredicate (Каждый появляется по 5 раз в своем классе)
  • "And(" против Or(" (в соответствующем toString() Методы)
  • #and против #or@see Комментарии Javadoc)
  • true против falseapply; ! может быть переписано из выражения)
  • -1 /* all bits on */ против 0 /* all bits off */ в hashCode()
  • &= против |= в hashCode()
Это было полезно?

Решение

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

Та же проблема возникает в вычислениях производительности, где вам нужен один и тот же комплекс, чтобы работать как для Float, так и для двойного (скажем, некоторые из методов, показанных в Голдберде "Что каждый компьютерный ученый должен знать о номерах с плавающей запятой" бумага).

Есть причина, почему ПодъемникS. TIntIntHashMap Бежит кругами вокруг Явы HashMap<Integer,Integer> При работе с аналогичным количеством данных.

Как написано исходный код Trove Collection?

Используя инструментацию исходного кода, конечно :)

Существует несколько библиотек Java для более высокой производительности (намного выше, чем Java -по умолчанию), которые используют генераторы кодов для создания повторного исходного кода.

Мы все знаем, что «инструментация исходного кода» является злым, и это поколение кода - дерьмо, но все же именно так люди, которые действительно знают, что они делают (то есть люди, которые пишут такие вещи, как Trove), делают это :)

Для того, что стоит, мы генерируем исходный код, который содержит большие предупреждения, такие как:

/*
 * This .java source file has been auto-generated from the template xxxxx
 * 
 * DO NOT MODIFY THIS FILE FOR IT SHALL GET OVERWRITTEN
 * 
 */

Другие советы

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

«Обходной путь», может быть, чтобы добавить ContentType Check в вашем ListEnumerator.moveNext()

Если вы измените следующее:

ctx.load(this.allDocumentsCol, "Include(FileLeafRef, ServerUrl, ContentType)");
.

и:

 while(ListEnumerator.moveNext())
     {      
        var currentItem = ListEnumerator.get_current();
        var ct = currentItem.get_contentType();
        if(ct.get_name() != "Folder") {
            var currentItemURL = domURL + currentItem.get_item('ServerUrl');
            libList += currentItem.get_item('FileLeafRef') + ' : ' + currentItemURL + '\n';
        }
     }
.

<Сильное> Обновление:

Хорошо, я должен был проверить это сам :) использовал CreatealLitemsQuery () и добавить генеракодицетагкод в CAML.Этот подход должен работать:

function documentQuery() {
    var ctx = new SP.ClientContext.get_current();
    var oLibDocs = ctx.get_web().get_lists().getByTitle("Dokumenter");
    var caml = SP.CamlQuery.createAllItemsQuery();
    caml.set_viewXml("<View Scope='RecursiveAll'><Query><Where><Neq><FieldRef Name='ContentType' /><Value Type='Text'>Folder</Value></Neq></Where></Query></View>");
    this.allDocumentsCol = oLibDocs.getItems(caml);
    ctx.load(this.allDocumentsCol, "Include(FileLeafRef, ServerUrl)");
    ctx.executeQueryAsync(Function.createDelegate(this, this.onSucceededCallback), Function.createDelegate(this, this.onFailedCallback));
}

function onSucceededCallback(sender, args) {
    var libList= "";
    var ListEnumerator = this.allDocumentsCol.getEnumerator();

    while(ListEnumerator.moveNext())
     {      
        var currentItem = ListEnumerator.get_current();
        var currentItemURL = _spPageContextInfo.webServerRelativeUrl + currentItem.get_item('ServerUrl');
        libList += currentItem.get_item('FileLeafRef') + ' : ' + currentItemURL + '\n';
     }
     alert(libList);
 }

function onFailedCallback(sender, args) {
 alert("failed. Message:" + args.get_message());

}
.

Чтобы добавить срок под любым родительским термином, вам следует нуждаться в двух вещах:

    .
  • Термин идентификатор магазина и соответствующие термин набор
  • Идентификатор родительского срока (к которому будет добавлен новый дочерний срок)

    Код обновления будет следующим:

         function execOperation()
         {
            //Current Context
            var context = SP.ClientContext.get_current();
    
            //Current Taxonomy Session
            var taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
    
            //Term Stores
            var termStores = taxSession.get_termStores();
    
            //Term Store under which to create the term.
            var termStore = termStores.getByName("Taxonomy_Dmxzz8tIBzk8wNVKQpJ+xA==");
    
            //Term Set under which to create the term.
            var termSet = termStore.getTermSet("b49f64b3-4722-4336-9a5c-56c326b344d4");
    
    
            //get the parent term ID, say it's "cf46hujkl-3344-4336-9a5c-56c326b344d4"
            var parentTerm = termSet.getTerm("cf46hujkl-3344-4336-9a5c-56c326b344d4");
    
            //create new child term under the parent term
            var newTerm = parentTerm.createTerm("SharePoint Rocks", 1033, newGuid.toString());
    
            context.load(newTerm);
            context.executeQueryAsync(function(){
            alert("Term Created: " + newTerm.get_name());
             },function(sender,args){
            console.log(args.get_message());
            });}
    
    .

Я получаю, что солнце должно документировать, как это, для кода библиотеки Java SE, и, возможно, другие авторы библиотеки.

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

Примитивные типы Java приводят вас, особенно когда дело доходит до массивов. Если вы специально спрашиваете о коде с участием примитивных типов, то я бы сказал, просто постарайтесь избежать их. Метод объекта [] достаточно, если вы используете штучные типы.

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

Ну это зависит, в SharePoint World это просто маркетинг.

Ссылка «Skydrive» в верхнем баре «Suites» отвечает вам в библиотеку «Skydrive Pro» (которая в основном, просто ваша личная библиотека документов в том, что используется для того, чтобы их называли Вашим «моим сайтом»). Тогда у вас также есть Office 2013 «Skydrive Pro 2013» Desktop Client, который позволяет выполнять 2-контактную синхронитуру между библиотеками документов и локальным компьютером.

Чтобы запутать вещи больше, если вы синхронизируете свою библиотеку «Skydrive Pro», то она синхронизирует его к другой папке в обычные библиотеки.

Я написал подробный список в блоге по этому вопросу: http://www.martinhatch.com/2013/02/skydrive-and-skydrive-pro-xplained.html

Учитывая два фрагмента кода, которые, как утверждаются, являются одинаковыми, большинство языков имеют ограниченные средства для построения абстракций, которые объединяют фрагменты кода в монолит. Чтобы абстрагировать, когда ваш язык не может этого сделать, вы должны выйти за пределы языка:-{

Самый общий механизм «абстракции» - это полный макропроцессор, который может применять произвольные вычисления к «корпусу макроса», когда он испытывает его (подумайте Post или string-rewriting система, которая способна). М4 а также GPM являются типичными примерами. Предварительный прозакр C не является одним из них.

Если у вас есть такой макропроцессор, вы можете построить «абстракцию» в качестве макроса и запустить макропроцессор в вашем «абстрактном» исходном тексте, чтобы создать фактический исходный код, который вы компилируете и запускаете.

Вы также можете использовать более ограниченные версии идей, часто называемых «генераторами кода». Обычно они не способны, но во многих случаях они работают достаточно хорошо. Это зависит от того, насколько сложной должна быть ваша «макроам -экземпляра». (Причина, по которой люди влюблены в механизм шаблона C ++, является, несмотря на его безобразие, оно является Тьюринг способен, и поэтому люди могут выполнять по -настоящему уродливые, но удивительные задачи генерации кода). Другой ответ здесь упоминает Trove, что, по -видимому, в более ограниченной, но все еще очень полезной категории.

Действительно общие макропроцессоры (например, M4) манипулируют только текстом; Это делает их мощными, но они плохо справляются с структурой языка программирования, и действительно неловко писать генератор в таком процессоре McARO, который может не только производить код, но и оптимизировать сгенерированный результат. Большинство генераторов кода, с которыми я сталкиваюсь, «подключите эту строку к этому шаблону строки», и поэтому не могут сделать какую -либо оптимизацию сгенерированного результата. Если вы хотите, чтобы генерация произвольного кода и высокой производительности для загрузки вам нужно что -то, что способно, но понимает структуру сгенерированного кода, чтобы он мог легко манипулировать (например, оптимизировать) им).

Такой инструмент называется Система преобразования программы. Анкет Такой инструмент анализирует исходный текст, как и компилятор, а затем несет анализ/преобразования для достижения желаемого эффекта. Если вы можете поместить маркеры в исходный текст вашей программы (например, структурированные комментарии или аннотации в Langauges, у которых их есть), направляя инструмент Program Transformaiton What To Do, тогда вы можете использовать его для выполнения такой экземпляры абстракции, генерации кода и /или оптимизация кода. (Предложение одного плаката о зацеплении в компилятор Java является вариацией этой идеи). Используя общую систему трансформации PUProse (например DMS Software Reenerineering Takenit означает, что вы можете сделать это по существу любого языка.

Теперь можно избежать много такого рода повторений благодаря дженерикам. Они находки при написании того же кода, где меняются только типы.

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

Чтобы ответить на ваш вопрос о том, как обрабатывать код, который абсолютно должен быть продублирован ... отметьте каждый экземпляр легко искать комментарии. Есть несколько препроцессоров Java, которые добавляют макросы в стиле C. Я думаю, что я помню, как у Netbeans был один.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top