blob: d8518316a6f248f6d49c192ae2ed28c927541be7 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<title>Apache BookKeeper&trade; - Coding Guide</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/css/normalize.css">
<link rel="stylesheet" href="/css/tippy.css">
<link rel="stylesheet" href="/css/style.css">
<link rel="shortcut icon" href="/img/favicon.ico">
<script src="/js/tippy.min.js"></script>
<script type="text/javascript">
var shiftWindow = function() { scrollBy(0, -25); };
window.addEventListener("hashchange", shiftWindow);
window.addEventListener("pageshow", shiftWindow);
function load() { if (window.location.hash) shiftWindow(); }
</script>
</head>
<body class="body">
<main class="main">
<nav class="navbar bk-topnav">
<div class="navbar-brand">
<a class="navbar-item bk-brand" href="/">
Apache BookKeeper&trade;
</a>
<div class="navbar-burger burger" data-target="bkNav">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="bkNav" class="navbar-menu">
<div class="navbar-start">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">Documentation</a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/docs/latest/overview/overview">
Version 4.14.0-SNAPSHOT
<span class="tag is-warning">Development</span>
</a>
<a class="navbar-item" href="/docs/latest/api/javadoc">
<span class="icon bk-javadoc-icon">
<img src="/img/java-icon.svg">
</span>
Javadoc
</a>
<hr class="dropdown-divider">
<a class="navbar-item" href="/docs/4.13.0/overview/overview">
Release 4.13.0
</a>
<a class="navbar-item" href="/docs/4.12.1/overview/overview">
Release 4.12.1
</a>
<a class="navbar-item" href="/docs/4.12.0/overview/overview">
Release 4.12.0
</a>
<a class="navbar-item" href="/docs/4.11.1/overview/overview">
Release 4.11.1
<span class="tag is-success">Stable</span>
</a>
<a class="navbar-item" href="/docs/4.11.0/overview/overview">
Release 4.11.0
</a>
<a class="navbar-item" href="/docs/4.10.0/overview/overview">
Release 4.10.0
</a>
<a class="navbar-item" href="/archives/docs/r4.9.2">
Release 4.9.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.9.1">
Release 4.9.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.9.0">
Release 4.9.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.8.2">
Release 4.8.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.8.1">
Release 4.8.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.8.0">
Release 4.8.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.7.3">
Release 4.7.3
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.7.2">
Release 4.7.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.7.1">
Release 4.7.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.7.0">
Release 4.7.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.6.2">
Release 4.6.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.6.1">
Release 4.6.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.6.0">
Release 4.6.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.5.1">
Release 4.5.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.5.0">
Release 4.5.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.4.0">
Release 4.4.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.3.2">
Release 4.3.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.3.1">
Release 4.3.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.3.0">
Release 4.3.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.4">
Release 4.2.4
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.3">
Release 4.2.3
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.2">
Release 4.2.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.1">
Release 4.2.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.0">
Release 4.2.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.1.0">
Release 4.1.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.0.0">
Release 4.0.0
<span class="tag is-warning">EOL</span>
</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">Community</a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/community/mailing-lists">Mailing lists</a>
<a class="navbar-item" href="/community/slack">Slack</a>
<a class="navbar-item" href="https://github.com/apache/bookkeeper/issues">Github Issues</a>
<a class="navbar-item" href="/community/releases">Release Management</a>
<a class="navbar-item" href="/community/meeting">Community Meetings</a>
<hr class="dropdown-divider">
<a class="navbar-item" href="/community/contributing">Contribution Guide</a>
<a class="navbar-item" href="/community/coding_guide">Coding Guide</a>
<a class="navbar-item" href="/community/testing">Testing Guide</a>
<a class="navbar-item" href="/community/issue-report">Issue Report Guide</a>
<a class="navbar-item" href="/community/release_guide">Release Guide</a>
<hr class="dropdown-divider">
<a class="navbar-item" href="/community/presentations">Presentations</a>
<a class="navbar-item" href="/community/bookkeeper_proposals">BookKeeper Proposals</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">Project</a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/project/who">Who are we?</a>
<a class="navbar-item" href="/project/bylaws">Bylaws</a>
<a class="navbar-item" href="http://www.apache.org/licenses/">License</a>
<hr class="dropdown-divider">
<a class="navbar-item" href="/project/privacy">Privacy policy</a>
<a class="navbar-item" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
<a class="navbar-item" href="http://www.apache.org/foundation/thanks.html">Thanks</a>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="field is-grouped">
<p class="control">
<a class="button bk-twitter" href="https://twitter.com/asfbookkeeper">
<span class="icon">
<i class="fa fa-twitter"></i>
</span>
<span>Twitter</span>
</a>
</p>
<p class="control">
<a class="button" href="https://github.com/apache/bookkeeper">
<span class="icon">
<i class="fa fa-github"></i>
</span>
<span>GitHub</span>
</a>
</p>
<p class="control">
<a class="button is-primary" href="/releases">
<span class="icon">
<i class="fa fa-download"></i>
</span>
<span>Download</span>
</a>
</p>
</div>
</div>
</div>
</div>
</nav>
<div class="bk-community-container">
<div class="columns">
<div class="column is-12">
<header class="docs-title">
<nav class="level">
<div class="level-left">
<div class="level-item">
<h1 class="title">Coding Guide</h1>
</div>
</div>
</nav>
</header>
<hr />
<div class="content is-medium">
<section class="bk-community-content">
<p>These guidelines are meant to encourage consistency and best practices among people working on <em>Apache BookKeeper</em> code base.
They should be observed unless there is compelling reason to ignore them. We are also using checkstyle to enforce coding style.
Please refer to our <a href="https://github.com/apache/bookkeeper/blob/master/buildtools/src/main/resources/bookkeeper/checkstyle.xml">checkstyle rules</a> for all enforced checkstyle rules.</p>
<h3 id="java">Java</h3>
<p>Apache BookKeeper code should follow the <a href="http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html">Sun Java Coding Convention</a>, with the following additions.</p>
<ul>
<li>Lines can not be longer than 120 characters.</li>
<li>Indentation should be <strong>4 spaces</strong>. Tabs should never be used.</li>
<li>Use curly braces even for single-line ifs and elses.</li>
<li>No @author tags in any javadoc.</li>
<li>Use try-with-resources blocks whenever is possible.</li>
<li><strong>TODO</strong>s should be associated to at least one issue. E.g. <code class="highlighter-rouge">// TODO: make this parameter configurable (https://github.com/apache/bookkeeper/issues/280)</code></li>
</ul>
<h3 id="dependencies">Dependencies</h3>
<p>Apache BookKeeper uses following libraries a lot:</p>
<ul>
<li><a href="https://github.com/google/guava">Guava</a>: as a fundamental core library</li>
<li><a href="http://netty.io/">Netty</a>: for network communications and memory buffer management.</li>
</ul>
<p>Please use these libraries whenever possible rather than introducing more dependencies.</p>
<p>Dependencies are bundled with our binary distributions, so we need to attach the relevant licenses. See <a href="/community/licensing">Third party dependencies and licensing</a> for a guide on how to do this correctly.</p>
<h4 id="future">Future</h4>
<p>We prefer Java-8 Future over Guava’s Listenable Future. Please use Java-8 Future whenever possible.</p>
<h4 id="memory">Memory</h4>
<p>We prefer using netty <em>ByteBuf</em> over java nio <em>ByteBuffer</em> for internal usage. As we are using Netty Buffer for memory management.</p>
<h3 id="logging">Logging</h3>
<ul>
<li>Logging should be taken seriously. Please take the time to access the logs when making a change to ensure that the important things are getting logged and there is no junk there.</li>
<li>Logging statements should be complete sentences with proper capitalization that are written to be read by a person not necessarily familiar with the source code.</li>
<li>All loggings should be done with <strong>SLF4j</strong>, never <em>System.out</em> or <em>System.err</em>.</li>
</ul>
<h4 id="logging-levels">Logging levels</h4>
<ul>
<li><em>INFO</em> is the level you should assume the software will be run in. INFO messages are things which are not bad but which the user will definitely want to know about every time they occur.</li>
<li><em>TRACE</em> and <em>DEBUG</em> are both things you turn on when something is wrong and you want to figure out what is going on. <em>DEBUG</em> should not be so fine grained that it will seriously affect performance of the program. <em>TRACE</em> can be anything. Both <em>DEBUG</em> and <em>TRACE</em> statements should be considered to be wrapped in an <em>if (logger.isDebugEnabled)</em> or <em>if (logger.isTraceEnabled)</em> check to avoid performance degradation.</li>
<li><em>WARN</em> and <em>ERROR</em> indicate something that is <strong>BAD</strong>. Use <em>WARN</em> if you aren’t totally sure it is bad, and <em>ERROR</em> if you are.</li>
</ul>
<p>Please log the <em>stack traces</em> at <strong>ERROR</strong> level, but never at <strong>INFO</strong> level or below. They can be logged at <strong>WARN</strong> level when they are interesting for debugging.</p>
<h3 id="monitoring">Monitoring</h3>
<ul>
<li>Apache BookKeeper uses a pluggable <a href="https://github.com/apache/bookkeeper/tree/master/bookkeeper-stats">StatsProvider</a> on exporting metrics</li>
<li>Any new features should come with appropriate metrics for monitoring the feature is working correctly.</li>
<li>Those metrics should be taken seriously and only export useful metrics that would be used on production on monitoring/alerting healthy of the system, or troubleshooting problems.</li>
</ul>
<h3 id="unit-tests">Unit Tests</h3>
<ul>
<li>New changes should come with unit tests that verify the functionality being added</li>
<li>Unit tests should test the least amount of code possible. Don’t start the whole server unless there is no other way to test a single class or small group of classes in isolation.</li>
<li>Tests should not depend on any external resources. They need to setup and teardown their own stuff.</li>
<li>It is okay to use the filesystem and network in tests since that’s our business but you need to clean up them after yourself.</li>
<li><em>Do not</em> use sleep or other timing assumptions in tests. It is always, always, wrong and will fail intermittently on any test server with other things going on that causes delays.</li>
<li>We are strongly recommending adding a <em>timeout</em> value to all our test cases, to prevent a build from completing indefinitely.
<code class="highlighter-rouge">@Test(timeout=60000)</code></li>
</ul>
<h3 id="configuration">Configuration</h3>
<ul>
<li>Names should be thought through from the point of view of the person using the config.</li>
<li>The default values should be thought as best value for people who runs the program without tuning parameters.</li>
<li>All configuration settings should be added to <a href="https://github.com/apache/bookkeeper/blob/master/bookkeeper-server/conf/bk_server.conf">default configuration file</a> and <a href="https://github.com/apache/bookkeeper/blob/master/site/_data/config/bk_server.yaml">documented</a>.</li>
</ul>
<h3 id="concurrency">Concurrency</h3>
<p>Apache BookKeeper is a low latency system. So it is implemented as a purely asynchronous service. This is accomplished as follows:</p>
<ul>
<li>All public classes should be <strong>thread-safe</strong>.</li>
<li>We prefer using <a href="https://github.com/apache/bookkeeper/blob/master/bookkeeper-common/src/main/java/org/apache/bookkeeper/common/util/OrderedExecutor.java">OrderedExecutor</a> for executing any asynchronous actions. The mutations to same instance should be submitted to same thread to execute.</li>
<li>If synchronization and locking is required, they should be in a fine granularity way.</li>
<li>All threads should have proper meaningful name.</li>
<li>If a class is not threadsafe, it should be annotated <a href="https://github.com/misberner/jsr-305/blob/master/ri/src/main/java/javax/annotation/concurrent/NotThreadSafe.java">@NotThreadSafe</a>. The instances that use this class is responsible for its synchronization.</li>
</ul>
<h3 id="backwards-compatibility">Backwards Compatibility</h3>
<ul>
<li>Wire protocol should support backwards compatibility to enable no-downtime upgrades. This means the servers <strong>MUST</strong> be able to support requests from both old and new clients simultaneously.</li>
<li>Metadata formats and data formats should support backwards compatibility.</li>
</ul>
</section>
</div>
</div>
</div>
</div>
</main>
<footer class="footer">
<div class="container">
<div class="content has-text-centered">
<p>
Copyright &copy; 2016 - 2021 <a href="https://www.apache.org/">The Apache Software Foundation</a>,<br /> licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, version 2.0</a>.
</p>
<p>
Apache BookKeeper, BookKeeper®, Apache®, the Apache feature logo, and the Apache BookKeeper logo are either registered trademarks or trademarks of The Apache Software Foundation.
</p>
</div>
</div>
</footer>
</body>
<script src="/js/app.js"></script>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-104419626-1', 'auto');
ga('send', 'pageview');
</script>
</html>