<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/dino-kovac/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Fri, 17 Apr 2026 13:59:15 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>8090https://infinum.com/uploads/2020/11/AWS-HoneyCode-Review-0.webp</url>
				</image>
				<title>Building a Workspace Reservation App with AWS HoneyCode: A Review</title>
				<link>https://infinum.com/blog/aws-honeycode-review/</link>
				<pubDate>Wed, 02 Sep 2020 16:25:00 +0000</pubDate>
				<dc:creator>Dino Kovač</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/aws-honeycode-review/</guid>
				<description>
					<![CDATA[<p>Here&#8217;s our take on AWS HoneyCode, Amazon&#8217;s new low-code development tool in Beta.</p>
<p>The post <a href="https://infinum.com/blog/aws-honeycode-review/">Building a Workspace Reservation App with AWS HoneyCode: A Review</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-224"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-93">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-94'
	>
	AWS HoneyCode is a new low-code development tool by Amazon, currently in Beta. Amazon offers a lot of great services as part of AWS, so we wanted to try this new thing out.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-96">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-97'
	>
	Putting HoneyCode to use amidst the global pandemic</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-99">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-100'
	>
	In the past months as the world spiraled into a global health crisis, we had to deal with the new reality – just like everybody else. As the health situation in Croatia started to improve, we needed a way to organize so that people could safely work from the office.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-102">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-103'
	>
	We set up a system where we limit the office capacity so we can uphold the social distancing rules.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-105">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-106'
	>
	Some people preferred working from home, while others were eager to return to the office where the free coffee flows in vast rivers and where there is a dedicated workspace and a great work atmosphere. Those people had to write their names in the spreadsheet to reserve their spot in the office.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-112"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-108">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-109'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-110'
	>
	To try HoneyCode out, we built an app for reserving a workplace on one of the office floors.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-115"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-113">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-114'
	>
	Users could log in, see their reservations, and add new reservations – assuming there is available room. The system wouldn’t allow more than one reservation per person per day, and it also took care of enforcing the capacity rules for each floor.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-118"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-116">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-117'
	>
	The admins would see all the reservations in the system, along with the stats on floor capacity for each day.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-121"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-119">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-120'
	>
	Did it work – and how?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-124"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-122">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-123'
	>
	Indeed, all of this was possible in HoneyCode. It took about 6 hours to build this app from scratch, never having seen the software before.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-127"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-125"
	 data-media-type='video'>

	<div class="video__wrapper" data-id="es-126">
		<video
		class="video block-media__video js-video js-block-media-video video--cursor-takeover-use"
		 loop autoplay playsinline muted preload='metadata'>
		<source  src='https://infinum.com/uploads/2022/04/honeycode-preview-opt-1.mp4' type='video/mp4' />	</video>
	</div></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-130"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-128">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-129'
	>
	General workflow</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-133"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-131">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-132'
	>
	HoneyCode provides a web app where you can create Workbooks, and each Workbook can have multiple tables, automation, and apps. You can also have multiple teams – this is probably used to separate who can see which apps, but we haven’t tried that part out.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-136"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-134">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-135'
	>
	Data source</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-139"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-137">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-138'
	>
	Defining the data source for the app is very simple. Simply create a series of tables in the Workspace, which can then be referenced from other tables and from the UI – either directly or by using functions.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-142"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-140"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-141">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2020/09/AWS-HoneyCode-Review-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="368"
															width="867"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-145"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-143"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-144">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/09/AWS-HoneyCode-Review-2-1400x501.webp				media='(max-width: 699px)'
				type=image/webp								height="501"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/09/AWS-HoneyCode-Review-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="626"
															width="1748"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-148"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-146">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-147'
	>
	You can also set up reminders and alerts for when the data changes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-151"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-149">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-150'
	>
	UI</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-154"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-152">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-153'
	>
	The UI is built by adding screens and objects to them. Each screen can appear in the top-level navigation if you add it explicitly, otherwise, the only way to get to it is with an action by clicking a button or table row.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-157"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-155">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-156'
	>
	You get a mobile and web interface without doing any work to support the different form factors – that part just works.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-160"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-158"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-159">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2020/09/AWS-HoneyCode-Review-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1518"
															width="1264"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-163"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-161">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-162'
	>
	The basics work well enough, once you connect the data to a field you even get a live preview with just a couple of seconds lag between changing something in the UI object properties and seeing the preview.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-166"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-164">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-165'
	>
	To display data in the UI elements, link it to some data source which could be a table, a function that references a table, a local variable, or a combination of those.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-169"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-167">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-168'
	>
	Authentication</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-172"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-170">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-171'
	>
	To use the apps created via HoneyCode, everyone needs to have a HoneyCode account and be invited to the team. I’ve played around with implementing my own authentication by building a users table, and login/register screens, but that’s not really possible because there’s no way to send an email or hash a password.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-175"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-173">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-174'
	>
	Having that possibility would also be a problem for their pricing which is per user.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-178"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-176">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-177'
	>
	Authorization</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-181"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-179">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-180'
	>
	There is no nice way of locking parts of the app for some users. In order to distinguish an admin from a user, a new table with a list of app admins must be added. Then you can check if $SYS_USER (global variable with currently logged in user) is on that list and based on that, hide some UI elements.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-184"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-182"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-183">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/09/AWS-HoneyCode-Review-4-1400x769.webp				media='(max-width: 699px)'
				type=image/webp								height="769"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/09/AWS-HoneyCode-Review-4.webp"
					class="image__img block-media__image-img"
					alt=""
										height="854"
															width="1554"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-187"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-185">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-186'
	>
	End-user usability</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-190"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-188">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-189'
	>
	For users to use the app, they need to be invited to HoneyCode and log into the web interface or inside the HoneyCode mobile app. There doesn’t seem to be a way to export the app and publish it to a standalone web server or app store. This makes it a bit cumbersome for users.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-193"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-191">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-192'
	>
	Papercuts in development</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-196"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-194">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-195'
	>
	There is no way to add images to screens, and the UI options are spartan. It’s good for displaying tables and forms, and you can size and color the text, but not much else. Forget about images, graphs, and similar.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-199"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-197">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-198'
	>
	Adding a new record and getting back to the list doesn’t display the new record. It’s there after relaunching the app, though.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-202"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-200">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-201'
	>
	There is no way to mark a form field as required and no way of defining some validations on the field itself. The workaround is to write a convoluted visibility rule so that the submit button is hidden if the form is not filled in correctly.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-205"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-203">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-204'
	>
	This is the visibility rule for the done button when adding a reservation:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-207"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #6f42c1;">NOT</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">OR</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6f42c1;">ISBLANK</span><span class="token">(</span><span class="token">$</span><span class="token">[</span><span class="token" style="color: #005cc5;">Date</span><span class="token">]</span><span class="token">)</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6f42c1;">ISBLANK</span><span class="token">(</span><span class="token">$</span><span class="token">[</span><span class="token" style="color: #005cc5;">Location</span><span class="token">]</span><span class="token">)</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6f42c1;">FILTER</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">Reservations</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Reservations[Date]=% AND Reservations[Person]=%</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      $</span><span class="token">[</span><span class="token" style="color: #005cc5;">Date</span><span class="token">]</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      $</span><span class="token">[</span><span class="token" style="color: #005cc5;">Person</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">0</span><span class="token">,</span><span class="token"> 
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6f42c1;">IFERROR</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #6f42c1;">FINDROW</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #005cc5;">Summary_Reservations</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Summary_Reservations[Date]=% AND Summary_Reservations[Location]=%</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">        $</span><span class="token">[</span><span class="token" style="color: #005cc5;">Date</span><span class="token">]</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">        $</span><span class="token">[</span><span class="token" style="color: #005cc5;">Location</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">)</span><span class="token">[</span><span class="token" style="color: #005cc5;">Remaining</span><span class="token"> </span><span class="token" style="color: #005cc5;">Reservations</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #d73a49;">&lt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">FALSE</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-210"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-208">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-209'
	>
	It will hide the done button if any of the fields are blank, if the user already has a reservation for that date or if the location is full for that date.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-213"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-211">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-212'
	>
	All things considered</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-216"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-214">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-215'
	>
	The basics for working with the data are not bad, it works like excel and that’s good because it fits and it’s familiar.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-219"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-217">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-218'
	>
	Programming the UI with these excel-like rules is quite tiresome (just look at the code sample above). There’s no good way to do input field validation, just a hacky workaround.<br />
It’s also not cheap for a larger number of users. For 250 people, it would cost around $5k/month.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-222"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-220">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-221'
	>
	In its current state, I wouldn’t recommend this tool for any project – not even the simple ones. It’s just way too easy for the requirements to outgrow what you can currently do with HoneyCode. Hopefully, this changes in the future as Amazon adds more functionalities.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/aws-honeycode-review/">Building a Workspace Reservation App with AWS HoneyCode: A Review</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>8135https://infinum.com/uploads/2017/11/most-mobile-projects-fail-at-the-api-0.webp</url>
				</image>
				<title>Most Mobile Projects Fail at the API: How to Minimize Risk</title>
				<link>https://infinum.com/blog/most-mobile-projects-fail-at-the-api/</link>
				<pubDate>Thu, 23 Nov 2017 14:59:00 +0000</pubDate>
				<dc:creator>Dino Kovač</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/most-mobile-projects-fail-at-the-api/</guid>
				<description>
					<![CDATA[<p>Whether app developers are creating their own APIs or piggybacking off a larger system, a successful API will lead to a better working, faster mobile app.</p>
<p>The post <a href="https://infinum.com/blog/most-mobile-projects-fail-at-the-api/">Most Mobile Projects Fail at the API: How to Minimize Risk</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-359"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-225">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-228"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-226">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-227'
	>
	<strong>APIs (application programming interfaces)</strong> make mobile apps and browser apps work. A great API serves as the building block for all the other components of a successful mobile app. Whether app developers are creating their own API or piggybacking off a larger system, a successful API will lead to a better working, more timely mobile app.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-231"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-229">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-230'
	>
	While creating a consistent and timely API is not the flashiest or the most visible part of a new mobile app, it is arguably one of the most important aspects of any well-developed app.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-234"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-232">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-233'
	>
	Here are a few aspects of a strong API strategy that leads to productive mobile development:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-237"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-235">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-236'
	>
	Create heavy-duty API planning</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-240"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-238">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-239'
	>
	APIs should be planned strategically for the long-term stability.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-243"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-241">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-242'
	>
	Before the API development can start, as much as possible of the requirements needs to be known and the developers themselves need to have a strong understanding of the problem they are solving. That usually means that developers need to dive deep into the problem domain and get very specific answers about everything that’s unclear.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-246"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-244">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-245'
	>
	Once the development team has a good understanding of the problem, it’s time to design the system. Most APIs need a way to store data and for most use cases, <a href="https://en.wikipedia.org/wiki/Relational_database">relational databases</a> are a great way to store data.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-249"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-247">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-248'
	>
	The way data is stored can have a <strong>big impact on the performance and functionality</strong> of the API so it’s very important to invest an appropriate amount of time into defining the database entities and relationships between them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-252"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-250"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-251">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2017/11/most-mobile-projects-fail-at-the-api-1-1400x756.webp				media='(max-width: 699px)'
				type=image/webp								height="756"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2017/11/most-mobile-projects-fail-at-the-api-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="761"
															width="1410"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-255"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-253">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-254'
	>
	This is a great investment of time because it ensures you build the system on a solid foundation.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-258"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-256">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-257'
	>
	If API design is not done properly before development starts, massive changes might be required later on in the project and the costs are considerably larger at that point. Any change on the API may cause changes on all of the clients using it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-261"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-259">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-260'
	>
	Principle of least surprise</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-264"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-262">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-263'
	>
	Good API design follows standard conventions which are appropriate for the problem the API solves. By following standards, the API is more intuitive to mobile developers and therefore creates a certain ease of use.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-267"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-265">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-266'
	>
	By following standards in API development, app developers can use existing knowledge and tools – making app development less costly. Having logical naming and consistency throughout the API goes a long way to minimize development costs for users of the API.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-270"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-268">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-269'
	>
	A typical modern API is a <a href="https://en.wikipedia.org/wiki/Representational_state_transfer">RESTful</a> API which uses <a href="http://json.org/">JSON</a> as the data transfer format. For some use cases, standards like <a href="https://grpc.io/">gRPC</a>, <a href="https://thrift.apache.org/">Thrift</a> and <a href="http://graphql.org/">GraphQL</a> are more appropriate.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-273"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-271">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-272'
	>
	As much as is possible, the <strong>API should behave predictably and work without (unpleasant) surprises</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-276"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-274">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-275'
	>
	That includes using a consistent format of error responses and the appropriate HTTP status codes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-279"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-277">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-278'
	>
	Test rigorously and consistently</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-282"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-280">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-281'
	>
	API tests are as important as app testing, in that API tests ensure that applications, systems, databases, and networks can communicate with each other and exchange information. Testing should both prove the API is working as expected (i.e., without bugs) and according to its specifications.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-285"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-283">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-284'
	>
	As much as is possible, <strong>testing of the API should be automated</strong> by using a <a href="https://infinum.com/blog/a-ruby-on-rails-continous-integration-process-using-semaphore-github-codeclimate-and-hipchat/">continuous integration</a> setup.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-288"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-286"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-287">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2017/11/most-mobile-projects-fail-at-the-api-2-1400x308.webp				media='(max-width: 699px)'
				type=image/webp								height="308"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2017/11/most-mobile-projects-fail-at-the-api-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="310"
															width="1410"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-291"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-289">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-290'
	>
	Testing should focus on use cases which are as close as possible to those that are or will be happening in production.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-294"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-292">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-293'
	>
	Use test environments</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-297"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-295">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-296'
	>
	In order to make integration of mobile apps with the API easier, there should always be one or more test environments. Test environments are API deployments to separate endpoints which allow for various testing which can’t and shouldn’t be done in production. In fact, <strong>testing in production should be avoided</strong> altogether if at all possible.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-300"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-298">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-299'
	>
	If the production API is already live, a good way to get representative test data into the test environments is simply copying the data over from production periodically. When doing this it’s very important to remove all personal information like names, email addresses, bank account numbers since the test environments don’t imply the same level of data security and same access rules.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-303"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-301"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-302">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2017/11/most-mobile-projects-fail-at-the-api-3-1400x757.webp				media='(max-width: 699px)'
				type=image/webp								height="757"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2017/11/most-mobile-projects-fail-at-the-api-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="762"
															width="1410"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-306"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-304">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-305'
	>
	By ensuring the test environments work in the exact same way as the production environment, integration with production for the mobile teams should be much easier. Switching to using the production APIs should be as simple as changing the host name from <code>test.example.com</code> to <code>example.com</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-309"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-307">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-308'
	>
	Maintain accountability and accessibility</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-312"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-310">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-311'
	>
	For the API to work consistently (and to troubleshoot any later problems), <strong>API developers should document everything</strong>. The documentation should be clear, correct, and easy to understand. The documentation should also be updated as the API changes so it doesn’t contain outdated and incorrect information.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-315"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-313">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-314'
	>
	While API documentation is very important, it’s often regarded as tedious and boring work by developers so it’s important to make the documentation process as easy and automated as possible. The API documentation should be automatically deployed with the API, without any manual intervention needed.<br>We can take this a step further and eliminate a lot of the manual work by generating documentation with examples from API test cases using tools like our own <a href="https://github.com/infinum/dox">dox</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-318"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-316">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-317'
	>
	Handle API changes gracefully</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-321"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-319">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-320'
	>
	Business requirements change over time, the supporting software also needs to change to keep solving the right problems. <strong>When the API changes, we want the API clients to keep working</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-324"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-322">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-323'
	>
	Since non-breaking changes, like just adding new functionality to an API, are usually not a problem — let’s focus on the breaking changes.<br>How do we handle those?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-327"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-325">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-326'
	>
	The naive solution would be to immediately update all the API clients, but that isn’t as simple with mobile apps. iOS apps need to undergo a <a href="https://developer.apple.com/app-store/review/">review process</a> by Apple which can take days, sometimes even weeks. Even after the mobile app updates end up in the respective app stores, many users won’t update soon (or ever) to a newer version of the app.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-330"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-328">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-329'
	>
	The main tool for solving this problem is API versioning. The most straightforward way to use API versioning is to copy all the functionality of the API and start serving the new version of the API on different endpoints, including the breaking changes. Usually the new endpoints are just prefixed with a different version, so the API would support calls to both <code>/api/v1/login</code> and <code>/api/v2/login</code> — with the old endpoint retaining the old behavior.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-333"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-331">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-332'
	>
	While API versioning is a powerful tool, sometimes it isn’t enough. Maintaining multiple versions of an API can be time consuming, and thus costly. Sometimes, for various reasons, API versioning may not even be possible. It’s wise to design a mechanism which can force clients to update to a newer version. For mobile apps we use <a href="https://github.com/infinum/Android-prince-of-versions">Prince of Versions</a> to specify a minimum client version per platform.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-336"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-334">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-335'
	>
	While this mechanism should rarely be used, when you truly need it — it’s invaluable. You can use it not only for breaking API changes, but for any situation when you may need to force the client to update.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-339"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-337">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-338'
	>
	To handle breaking changes on the API you can either deploy a new version of the API which increases the maintenance burden or force all the clients to update which is intrusive to users of mobile apps.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-342"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-340">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-341'
	>
	Choose wisely.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-345"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-343">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-344'
	>
	Conclusion</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-348"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-346">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-347'
	>
	To minimize the risk for mobile projects, when building APIs you should:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-351"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-349">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-350'
	>
	<li>invest time in planning the API architecture</li><li>use existing standards whenever possible</li><li>automate testing and deployment</li><li>use multiple multiple server environments</li><li>ensure API documentation and support from the API development team</li><li>be prepared for (breaking) changes</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-354"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-352">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-353'
	>
	APIs are the foundation upon which modern mobile and web apps are built. They’re not easy to plan and build, and the decisions you make whilst building them will come back to reward (or haunt) you for years to come.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-357"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-355">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-356'
	>
	So choose wisely and enjoy the challenge.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/most-mobile-projects-fail-at-the-api/">Most Mobile Projects Fail at the API: How to Minimize Risk</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7911https://infinum.com/uploads/2017/02/continuous-integration-on-android-why-we-ditched-jenkins-for-circle-ci-0.webp</url>
				</image>
				<title>Continuous Integration on Android: Why We Ditched Jenkins for Circle CI</title>
				<link>https://infinum.com/blog/continuous-integration-on-android-why-we-ditched-jenkins-for-circle-ci/</link>
				<pubDate>Tue, 13 Oct 2015 08:45:00 +0000</pubDate>
				<dc:creator>Dino Kovač</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/continuous-integration-on-android-why-we-ditched-jenkins-for-circle-ci/</guid>
				<description>
					<![CDATA[<p>Any CI solution that helps you code is better than nothing, but some are better than others. For us, Circle CI is a better fit than Jenkins.</p>
<p>The post <a href="https://infinum.com/blog/continuous-integration-on-android-why-we-ditched-jenkins-for-circle-ci/">Continuous Integration on Android: Why We Ditched Jenkins for Circle CI</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-521"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-360">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-363"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-361">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-362'
	>
	In our Android development team, we use the <a href="https://www.youtube.com/watch?v=G5AfE32pQ5I">Navy Seals Android Development Process</a>. It includes getting automatic feedback from static analysis tools and running tests using a Continuous Integration server. While <a href="https://jenkins-ci.org/">Jenkins</a> is a solid tool, it has its quirks. So when <a href="http://circleci.com/">Circle CI</a> announced Android support, we decided to give it a spin.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-366"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-364">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-365'
	>
	We used Jenkins CI for a while in combination with <a href="https://github.com/">Github</a> and <a href="https://bitbucket.org/">Bitbucket</a> repositories. Jenkins was installed on a local machine in the company and each time someone pushed to a repository, a web-hook triggered a build. Then Jenkins fetched the current code, built it, ran static analysis and our tests. If there was any problem at all, it notified us via the appropriate <a href="https://slack.com/">Slack</a> channel.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-369"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-367">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-368'
	>
	That sounds pretty straightforward, right? Unfortunately, there’s a big difference between how things should work and how they actually work.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-372"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-370">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-371'
	>
	Jenkins is not polished</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-375"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-373">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-374'
	>
	Jenkins is a mature piece of software and has a large number of available plugins to make your life easier. However, the UI looks really ugly and a large percentage of plugins do not work as advertised.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-378"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-376"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-377">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2017/02/continuous-integration-on-android-why-we-ditched-jenkins-for-circle-ci-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="592"
															width="1000"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-381"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-379">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-380'
	>
	Somebody needs to maintain the Jenkins machine</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-384"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-382">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-383'
	>
	This problem is not specific only to Jenkins, but to any self-hosted CI solution. Somebody needs to ensure that the machine is secure because it contains a lot of code that is core to our business. This includes securing access to the machine and regularly updating to patch the latest <a href="https://www.openssl.org/news/vulnerabilities.html">OpenSSL vulnerabilities</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-387"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-385">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-386'
	>
	Security issues are not the only issues you might encounter. In our case, builds started failing across all projects at one point. The disk was full because of all the archived build artifacts and the builds kept failing until somebody found the time to clean up the disk. We ended up buying a larger hard drive to accommodate more projects.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-390"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-388">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-389'
	>
	These are not unsolvable or even difficult issues, but they take time to solve – time that we could otherwise spend improving our apps.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-393"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-391">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-392'
	>
	The code and configuration live separate lives</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-396"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-394">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-395'
	>
	In our Jenkins setup, you install all the tools you need to build the app locally on the machine. They are used in the build script when your build is run (think build tools, Android SDK, support libraries, etc.). And when you update your code so that it needs a new version of a tool, you also have to remember to log onto the Jenkins machine and manually install the new version. If you don’t – your build fails.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-399"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-397">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-398'
	>
	Circle CI to the rescue</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-402"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-400">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-401'
	>
	About ten months ago, Circle CI <a href="http://blog.circleci.com/announcing-ios-and-android-support/">announced support for Android and iOS projects</a>. Pretty soon, we started trying it out since we weren’t satisfied with our setup. We discovered that it had some great advantages over our old Jenkins setup.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-405"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-403"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-404">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2017/02/continuous-integration-on-android-why-we-ditched-jenkins-for-circle-ci-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="592"
															width="1000"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-408"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-406">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-407'
	>
	Completely independent builds</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-411"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-409">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-410'
	>
	Each time a build is triggered, a new virtual container is spun up. The project GitHub repository is cloned and the <code>circle.yml</code> configuration file in the root of the project is read and used in the rest of the process.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-414"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-412">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-413'
	>
	The configuration file is used to:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-417"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-415">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-416'
	>
	<li>install the dependencies,</li><li>build the project,</li><li>run static analysis tools (lint, findbugs, pmd, checkstyle),</li><li>run tests and</li><li>archive artifacts.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-420"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-418">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-419'
	>
	Sleek and intuitive UI</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-423"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-421">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-422'
	>
	Unlike Jenkins, which has a rudimentary and cumbersome UI, Circle has obviously put a lot of work into their Web UI because it’s a breeze to set up and use.<br>Circle CI lists all your GitHub repositories so you can set up CI for your project in just a few clicks. It also automatically adds the deploy key to the repository.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-426"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-424"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-425">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2017/02/continuous-integration-on-android-why-we-ditched-jenkins-for-circle-ci-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="790"
															width="935"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-429"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-427">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-428'
	>
	Lots of ways to notify you</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-432"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-430">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-431'
	>
	Mail, Slack, Hipchat, IRC.. you name it. There’s also an option to notify you only if the build status changes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-435"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-433">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-434'
	>
	Sensible pricing</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-438"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-436">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-437'
	>
	The first container is free, an additional container (two parallel builds in total) is <code>$50 per month</code>. You can compare that to <a href="https://travis-ci.org/">Travis CI</a>, where the lowest tier is <code>$129 per month</code>. For a smaller project, you could probably get away with one container.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-441"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-439">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-440'
	>
	The configuration lives with the code</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-444"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-442">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-443'
	>
	All the configuration needed for Circle to run your build is in <code>circle.yml</code> inside your project. When you need to update your build tools, you do it right inside of your project. When you push your code, you do it knowing that the new build tools will be installed before your build is run. Also, if you want to retry any older build, you don’t have to worry about not having the older build tools installed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-447"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-445">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-446'
	>
	Great GitHub integration</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-450"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-448">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-449'
	>
	When you create a pull request, GitHub displays the Circle CI build status. You can also <a href="https://github.com/blog/2051-protected-branches-and-required-status-checks">tell GitHub</a> to disallow merging the pull request if the build was not successful.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-453"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-451"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-452">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2017/02/continuous-integration-on-android-why-we-ditched-jenkins-for-circle-ci-4.webp"
					class="image__img block-media__image-img"
					alt=""
										height="255"
															width="777"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-456"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-454">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-455'
	>
	Circle CI downsides</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-459"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-457">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-458'
	>
	Long build times if using emulator</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-462"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-460">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-461'
	>
	Circle CI does not support KVM emulation. This means you can’t use <code>x86</code> emulators like <a href="https://infinum.com/blog/is-your-android-emulator-just-too-slow/">Genymotion</a> and you’re stuck with <code>arm</code> emulators which take forever to boot. It also needs a small amount of time to spin up a new container – but that’s negligible next to the emulator boot time!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-465"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-463">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-464'
	>
	Although we initially experimented with running Android instrumentation tests on the emulator, we are now using <a href="http://robolectric.org/">Robolectric</a> unit tests and are quite happy with them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-468"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-466">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-467'
	>
	Our typical build on a project with 130 tests takes 14 minutes, but if you’re using the Android emulator, it will take more than 20 minutes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-471"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-469">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-470'
	>
	No Bitbucket support</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-474"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-472">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-473'
	>
	Circle CI has great GitHub integration. I especially like that it indicates if the tests passed or not for each pull request, so I don’t even need to look at the code if the tests fail. However, there is absolutely no Bitbucket support. As far as I know from speaking to their tech support – there are no plans to implement it in the near future.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-477"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-475">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-476'
	>
	We’re still hoping Circle CI might add Bitbucket support one day. For the time being, we’ve relocated some of our Bitbucket repositories to GitHub.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-480"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-478">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-479'
	>
	Your code is in the Cloud</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-483"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-481">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-482'
	>
	When you use a hosted CI solution, you need to be aware that your code will be downloaded to a server that you do not control. If a security breach should happen on that server, your code may be compromised. If your company has strict security policies, you may not be able to use Circle CI.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-486"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-484">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-485'
	>
	Other commercial CI solutions</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-489"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-487">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-488'
	>
	There are several commercial CI solutions that support Android, like Travis and Ship.io. However, we’ve found Circle CI to best fit our needs. Travis Android support is still in beta and we haven’t found a simple way to store build artifacts with it. At the time when we were looking for a Jenkins replacement, Ship.io was still in public beta and we liked the Circle CI pricing model better.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-492"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-490">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-491'
	>
	I’m sure time did not stand still for Travis and Ship.io, so it might be a good idea to take another look at them. There are also some hosted Jenkins solutions out there if that fits your use case.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-495"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-493">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-494'
	>
	Update: <strong>Ship.io is shutting down</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-498"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-496">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-497'
	>
	Conclusion</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-501"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-499">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-500'
	>
	The problems we had with Jenkins:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-504"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-502">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-503'
	>
	<li>ugly UI and broken plugins,</li><li>build configuration outside of the repository,</li><li>maintenance overhead of the Jenkins machine.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-507"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-505">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-506'
	>
	Circle CI solves all these problems for us.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-510"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-508">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-509'
	>
	The bottom line is that while any kind of CI solution which helps you code is better than nothing, some are better than others. We found that Circle CI is a better fit than Jenkins for our development process, but something else may work better for a different company.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-513"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-511">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-512'
	>
	Thanks to my colleagues Ivan Kocijan and <a href="https://twitter.com/ZeljkoPlesac">Željko Plesac</a> for reading drafts of this post and giving great feedback!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-516"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-514">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-515'
	>
	If you are interested in how our Rails team approaches Continuous Integration and delivery, you can read about it in <a href="https://infinum.com/blog/a-ruby-on-rails-continous-integration-process-using-semaphore-github-codeclimate-and-hipchat/">this article</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-519"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-517">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-518'
	>
	Are you using Continuous Integration in your projects? What kind of tools do you use? Let us know in the comments!</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/continuous-integration-on-android-why-we-ditched-jenkins-for-circle-ci/">Continuous Integration on Android: Why We Ditched Jenkins for Circle CI</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>