Java >> Java Tutorial >  >> Java

Helfen Sie mir, meinen Schreibstil zu verbessern

Vor einiger Zeit las ich einen Blog mit dem Titel:Finden Sie Ihre Stimme beim Schreiben eines Fachbuchs. Es erinnerte mich daran, dass ich diesen Blog seit viereinhalb Jahren schreibe, aber meiner „Stimme“ nicht viel Aufmerksamkeit geschenkt habe. Das wird sich jetzt ändern.

Wenn ich an meine vergangenen Blogbeiträge denke, kann ich zwei verschiedene Stimmen identifizieren, die ich seit viereinhalb Jahren verwende.

Die Wahrheit ist, dass ich mit keinem von beiden glücklich bin.

Das größte Problem dieser beiden Stimmen ist, dass meine erste Stimme nichts beschrieb und meine jetzige Stimme alles beschreibt .

Lass uns weitermachen und mir meine alte Stimme genauer ansehen.

Stimme 1:Beschreibe nichts

Lassen Sie uns meine erste Stimme anhand eines Beispiels demonstrieren. Der erste Teil meines Spring Data JPA-Tutorials ist ein perfektes Beispiel für meine erste Stimme.

Wenn ich beschreibe, wie der Leser den Spring-Anwendungskontext konfigurieren kann, verwende ich den folgenden Text und Beispielcode:

Zweiter , müssen Sie den Spring-Anwendungskontext konfigurieren. Wie Sie sich vielleicht erinnern, müssen Sie die Factory-Beans für Datenquelle, Transaktionsmanager und Entitätsmanager konfigurieren. Wenn Sie Spring 3.1 und Servlet 3.0 verwenden, können Sie dies tun, indem Sie eine Java-Konfigurationsklasse implementieren und diese Konfigurationsklasse in Ihren Webanwendungsinitialisierer laden. Der Inhalt meiner Anwendungskontext-Konfigurationsklasse ist im Folgenden angegeben:

import com.jolbox.bonecp.BoneCPDataSource;
import org.hibernate.ejb.HibernatePersistence;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.*;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
 
import javax.annotation.Resource;
import javax.sql.DataSource;
 
/**
 * An application context Java configuration class. The usage of Java configuration
 * requires Spring Framework 3.0 or higher with following exceptions:
 * <ul>
 *     <li>@EnableWebMvc annotation requires Spring Framework 3.1</li>
 * </ul>
 * @author Petri Kainulainen
 */
@Configuration
@ComponentScan(basePackages = {"net.petrikainulainen.spring.datajpa.controller"})
@EnableWebMvc
@ImportResource("classpath:applicationContext.xml")
@PropertySource("classpath:application.properties")
public class ApplicationContext {
     
    private static final String VIEW_RESOLVER_PREFIX = "/WEB-INF/jsp/";
    private static final String VIEW_RESOLVER_SUFFIX = ".jsp";
 
    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
 
    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
    private static final String PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY = "hibernate.ejb.naming_strategy";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
 
    private static final String PROPERTY_NAME_MESSAGESOURCE_BASENAME = "message.source.basename";
    private static final String PROPERTY_NAME_MESSAGESOURCE_USE_CODE_AS_DEFAULT_MESSAGE = "message.source.use.code.as.default.message";
 
    @Resource
    private Environment environment;
 
    @Bean
    public DataSource dataSource() {
        BoneCPDataSource dataSource = new BoneCPDataSource();
 
        dataSource.setDriverClass(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
        dataSource.setJdbcUrl(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
        dataSource.setUsername(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
        dataSource.setPassword(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
 
        return dataSource;
    }
 
    @Bean
    public JpaTransactionManager transactionManager() throws ClassNotFoundException {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
 
        transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
 
        return transactionManager;
    }
 
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws ClassNotFoundException {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
 
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
 
        Properties jpaProterties = new Properties();
        jpaProterties.put(PROPERTY_NAME_HIBERNATE_DIALECT, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
        jpaProterties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
        jpaProterties.put(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY));
        jpaProterties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
 
        entityManagerFactoryBean.setJpaProperties(jpaProterties);
 
        return entityManagerFactoryBean;
    }
 
    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
 
        messageSource.setBasename(environment.getRequiredProperty(PROPERTY_NAME_MESSAGESOURCE_BASENAME));
        messageSource.setUseCodeAsDefaultMessage(Boolean.parseBoolean(environment.getRequiredProperty(PROPERTY_NAME_MESSAGESOURCE_USE_CODE_AS_DEFAULT_MESSAGE)));
 
        return messageSource;
    }
 
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
 
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix(VIEW_RESOLVER_PREFIX);
        viewResolver.setSuffix(VIEW_RESOLVER_SUFFIX);
 
        return viewResolver;
    }
}

Diese Stimme hat ein großes Problem:

Wenn der Leser nicht bereits weiß, wie er den Spring-Anwendungskontext mithilfe der Java-Konfiguration konfigurieren kann, ist es sehr schwer zu verstehen, was vor sich geht. Mit anderen Worten, dieser Stil geht davon aus, dass der Leser bereits weiß, was er zu tun hat .

Nachdem ich dieses Problem erkannt hatte, beschloss ich, meinen Schreibstil zu ändern.

Stimme 2:Beschreibe alles

Das Problem meiner ersten Stimme war, dass ich den Code überhaupt nicht beschrieben habe. Ich habe mich entschieden, das zu beheben, indem ich die Implementierung des Beispielcodes beschreibe, bevor ich dem Leser irgendeinen Code zeige.

Mein letzter Blog-Beitrag mit dem Titel:Using Asciidoctor with Spring:Rendering Asciidoc Document with Spring MVC hat ein gutes Beispiel für meine zweite Stimme.

Wenn ich beschreibe, wie der Leser eine abstrakte Ansichtsklasse erstellen kann, die Asciidoc-Dokumente in HTML umwandelt und das erstellte HTML rendert, verwende ich den folgenden Text und Code:

Zuerst , müssen wir die AbstractAsciidoctorHtmlView implementieren Klasse. Diese Klasse ist eine abstrakte Basisklasse, die Asciidoc-Markup in HTML umwandelt und das erstellte HTML rendert. Wir können diese Klasse implementieren, indem wir diesen Schritten folgen:

  1. Erstellen Sie die AbstractAsciidoctorHtmlView Klasse und erweitern Sie die AbstractView Klasse.
  2. Fügen Sie der erstellten Klasse einen Konstruktor hinzu und setzen Sie den Inhaltstyp der Ansicht auf „text/html“.
  3. Fügen Sie eine geschützte abstrakte Methode getAsciidocMarkupReader() hinzu zur erstellten Klasse und setzen Sie ihren Rückgabetyp auf Reader . Diese Methode muss von den Unterklassen dieser Klasse implementiert werden und die Implementierung dieser Methode muss einen Reader zurückgeben Objekt, das verwendet werden kann, um das gerenderte Asciidoc-Markup zu lesen.
  4. Fügen Sie ein privates getAsciidoctorOptions() hinzu -Methode auf die erstellte Klasse. Diese Methode gibt die Konfigurationsoptionen von Asciidoctor zurück. Implementieren Sie es, indem Sie diesen Schritten folgen:
    1. Erstellen Sie eine neue Option Objekt.
    2. Stellen Sie sicher, dass Asciidoctor sowohl die Kopf- als auch die Fußzeile des Asciidoctor-Dokuments darstellt, wenn es in HTML umgewandelt wird.
    3. Gib die erstellten Optionen zurück Objekt.
  5. Überschreiben Sie das renderMergedOutputModel() Methode der AbstractView Klasse und implementieren Sie sie, indem Sie die folgenden Schritte ausführen:
    1. Erhalten Sie den Inhaltstyp der Ansicht, indem Sie getContentType() aufrufen Methode der AbstractView -Klasse und verwenden Sie das zurückgegebene Objekt, wenn Sie den Inhaltstyp der Antwort festlegen. Dies setzt den Inhaltstyp der Antwort auf „text/html“.
    2. Erstellen Sie einen neuen Asciidoctor Objekt durch Aufrufen von create() Methode der Asciidoctor.Factory Klasse.
    3. Holen Sie sich Optionen -Objekt durch Aufrufen des privaten getAsciidoctorOptions() Methode.
    4. Holen Sie sich den Reader -Objekt, das zum Lesen des Asciidoctor-Markups verwendet wird, indem getAsciidocMarkupReader() aufgerufen wird Methode.
    5. Holen Sie sich den Writer -Objekt, das verwendet wird, um erstelltes HTML-Markup in den Antworttext zu schreiben, indem getWriter() aufgerufen wird Methode der ServletResponse Schnittstelle.
    6. Transformieren Sie das Asciidoc-Markup in HTML und schreiben Sie das erstellte HTML in den Antworttext, indem Sie render() aufrufen Methode des Asciidoctor Klasse. Reichen Sie den Leser weiter , Schriftsteller und Optionen Objekte als Methodenparameter.

Der Quellcode der AbstractAsciidoctorHtmlView Klasse sieht wie folgt aus:

import org.asciidoctor.Asciidoctor;
import org.asciidoctor.Options;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.view.AbstractView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Reader;
import java.io.Writer;
import java.util.Map;

public abstract class AbstractAsciidoctorHtmlView extends AbstractView {

    public AbstractAsciidoctorHtmlView() {
        super.setContentType(MediaType.TEXT_HTML_VALUE);
    }

    protected abstract Reader getAsciidocMarkupReader();

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model,
                                           HttpServletRequest request,
                                           HttpServletResponse response) throws Exception {
        response.setContentType(super.getContentType());

        Asciidoctor asciidoctor = Asciidoctor.Factory.create();
        Options asciidoctorOptions = getAsciidoctorOptions();

        try (
                Reader asciidoctorMarkupReader = getAsciidocMarkupReader();
                Writer responseWriter = response.getWriter();
        ) {
            asciidoctor.render(asciidoctorMarkupReader, responseWriter, asciidoctorOptions);
        }
    }

    private Options getAsciidoctorOptions() {
        Options asciiDoctorOptions = new Options();
        asciiDoctorOptions.setHeaderFooter(true);
        return asciiDoctorOptions;
    }
}

Auch wenn ich denke, dass meine zweite Stimme viel besser ist als die erste, habe ich dennoch das Gefühl, dass sie zwei ernsthafte Probleme hat:

  • Das macht meine Blogbeiträge schwer lesbar, weil ich jedes Implementierungsdetail (selbst triviale) beschreibe, bevor der Leser irgendeinen Code sehen kann.
  • Dadurch werden meine Blogbeiträge länger als sie sein sollten.

Es ist an der Zeit, diese Probleme zu beheben, und ich hoffe, dass Sie mir dabei helfen können.

Stimme 3:Den Mittelweg finden

Ich denke, dass meine dritte Stimme ein Kompromiss zwischen meiner ersten und meiner zweiten Stimme sein sollte. Ich denke, wenn ich diesen Kompromiss eingehen möchte, sollte ich mich an diese Regeln halten:

  • Beschreiben Sie, was der Code tut und warum er es tut.
  • Alle anderen Kommentare zum Quellcode hinzufügen.
  • Fügen Sie weitere Links zu einem Feld "zusätzliche Informationen" hinzu, das sich unterhalb des Quellcodes befindet.

Wenn ich diesen Schritten folge, würde der Text, der beschreibt, wie der Leser eine abstrakte Ansichtsklasse erstellen kann, die Asciidoc-Dokumente in HTML umwandelt und das erstellte HTML darstellt, wie folgt aussehen:

Zuerst , müssen wir die AbstractAsciidoctorHtmlView implementieren Klasse. Diese Klasse ist eine abstrakte Basisklasse, die Asciidoc-Markup in HTML umwandelt und das erstellte HTML rendert. Wir können diese Klasse implementieren, indem wir diesen Schritten folgen:

  1. Erstellen Sie die AbstractAsciidoctorHtmlView Klasse und erweitern Sie die AbstractView Klasse.
  2. Fügen Sie der erstellten Klasse einen Konstruktor hinzu und setzen Sie den Inhaltstyp der Ansicht auf „text/html“.
  3. Fügen Sie eine geschützte abstrakte Methode getAsciidocMarkupReader() hinzu zur erstellten Klasse und setzen Sie ihren Rückgabetyp auf Reader . Diese Methode muss von den Unterklassen dieser Klasse implementiert werden und die Implementierung dieser Methode muss einen Reader zurückgeben Objekt, das verwendet werden kann, um das gerenderte Asciidoc-Markup zu lesen.
  4. Fügen Sie ein privates getAsciidoctorOptions() hinzu -Methode auf die erstellte Klasse und implementieren Sie sie, indem Sie die Konfigurationsoptionen von Asciidoctor zurückgeben.
  5. Überschreiben Sie das renderMergedOutputModel() Methode der AbstractView Klasse, und implementieren Sie es, indem Sie das Asciidoc-Dokument in HTML umwandeln und das erstellte HTML rendern.

Der Quellcode der AbstractAsciidoctorHtmlView Klasse würde wie folgt aussehen:

import org.asciidoctor.Asciidoctor;
import org.asciidoctor.Options;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.view.AbstractView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Reader;
import java.io.Writer;
import java.util.Map;

public abstract class AbstractAsciidoctorHtmlView extends AbstractView {

    public AbstractAsciidoctorHtmlView() {
        super.setContentType(MediaType.TEXT_HTML_VALUE);
    }

    protected abstract Reader getAsciidocMarkupReader();

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model,
                                           HttpServletRequest request,
                                           HttpServletResponse response) throws Exception {
        //Set the content type of the response to 'text/html'
        response.setContentType(super.getContentType());

        Asciidoctor asciidoctor = Asciidoctor.Factory.create();
        Options asciidoctorOptions = getAsciidoctorOptions();

        try (
                //Get the reader that reads the rendered Asciidoc document
                //and the writer that writes the HTML markup to the request body
                Reader asciidoctorMarkupReader = getAsciidocMarkupReader();
                Writer responseWriter = response.getWriter();
        ) {
            //Transform Asciidoc markup into HTML and write the created HTML 
            //to the response body
            asciidoctor.render(asciidoctorMarkupReader, responseWriter, asciidoctorOptions);
        }
    }

    private Options getAsciidoctorOptions() {
        Options asciiDoctorOptions = new Options();
        //Ensure that Asciidoctor renders both the header and footer of the Asciidoctor 
        //document when it is transformed into HTML.
        asciiDoctorOptions.setHeaderFooter(true);
        return asciiDoctorOptions;
    }
}

Ich denke, dass dieser Schreibstil eine große Verbesserung wäre, weil:

  • Meine Blogbeiträge wären kürzer und leichter zu lesen, weil ich nicht jedes Implementierungsdetail erklären würde, bevor der Leser irgendeinen Code sieht.
  • Der Leser würde immer noch die Informationen erhalten, die er braucht, um meinen Code zu verstehen. Der einzige Unterschied besteht darin, dass sie die Informationen zur „richtigen Zeit“ erhält.

Was denkst du?

Jetzt haben Sie die Möglichkeit, mir Feedback zu meinem Schreibstil zu geben. Ich interessiere mich für die Antworten auf die folgenden Fragen:

  • Denken Sie, dass mein aktueller Schreibstil zu ausführlich ist?
  • Glauben Sie, dass die Stimme drei eine Verbesserung wäre?
  • Haben Sie sonstiges Feedback für mich?

Vielen Dank im Voraus!


Java-Tag