Skip to content

About SCRUM - Hamid Shojaee Axosoft
Syndicate content
Software development plus Axosoft and GitKraken product-related articles.
Updated: 1 hour 56 min ago

GitKraken v2.6

Tue, 05/23/2017 - 21:26

“You know my methods, Watson,” said Sherlock. “There was not one finder command which I did not apply to the inquiry.”

Okay, so maaaaaybe that’s not quite what Sir Arthur Conan Doyle wrote, but Sherlock’s detective skills surely inspired the new and improved Fuzzy Finder in GitKraken version 2.6.

With this release, we’re trying something a little bit different. We’ve put together a video—and this article—to cover what’s new. Watch the video or keep reading, the choice is yours! Let us know which you prefer.

Fuzzy Finder

To bring up the improved Fuzzy Finder, use the keyboard shortcut Cmd+P for Mac or Ctrl+P for Windows and Linux.

GitKraken Fuzzy Finder

After you’re done looking into the curious incident of the dog in the night-time, you can use the Fuzzy Finder to perform any of the following actions:

Repo:
  • Init
  • Open
  • Open in file manager
  • Clone
Settings:
  • General
  • Git Config
  • Authentication
  • GitFlow
  • UI Preferences
View:
  • Toggle Left Panel
  • Increase Zoom
  • Decrease Zoom
  • Reset Zoom
  • Keyboard Shortcuts
History:
  • History + filename

The Fuzzy Finder has replaced the Command Palette; however, the old keyboard shortcuts Cmd+Shift+P for Mac and Ctrl+Shift+P for Windows and Linux, will still bring up the Fuzzy Finder.

gitkraken fuzzy finder keyboard shortcut

The actions listed below were previously performed through the Command Palette, but can now be performed using the Fuzzy Finder:

Core:
  • Undo
  • Redo
File:
  • Stage all changes
  • Unstage all changes
  • Discard all changes
Stash:
  • Create
  • Pop
  • Apply
Branch:
  • Create
  • Fetch
Checkout:
  • Checkout + branch name

Additionally, if you click the search box in the upper right corner—or use the keyboard short Cmd+F for Mac / Ctrl+F for Windows and Linux—it will search through commits by default.

Fuzzy Finder Shortcut

#GitKrakenTip: Use the Cmd+backspace / Ctrl+backspace shortcut to quickly clear out any searches or filters.

Other Updates

GitKraken will now politely inform you when you have an external rebase in progress. GitKraken will show this message and temporarily lock parts of the application until the external rebase has finished. You can still resolve conflicts from inside GitKraken at each step of the external rebase.

gitkraken external rebase message

Lastly, we updated the macOS title bar color for both dark and light themes.

gitkraken macOS title bar

As Sherlock once sarcastically put it, “The world is full of obvious things which nobody by any chance ever observes.” We hope our Fuzzy Finder helps put things in plain sight so that you need not have Holmes’ mind to perform actions that are quite elementary. To see what else is new and improved in GitKraken v2.6, continue your investigation over in our release notes.

Categories: Companies

GitKraken Tips V

Wed, 05/17/2017 - 20:03

Here is a roundup of our most recent 11 tips to help you become a bit more productive when you’re working. If this series is new to you, check out our previous tip roundups.

GitKraken Tips
  1.  Instantly open your current repo in a terminal window with alt/option + t, or from the File menu.
  2.  Push changes and start a pull request with one action. If you don’t have an upstream set, you’ll be prompted to set one first.
  3. Remote avatars in the graph help you see who is working on a branch. Get more info by hovering over those and other icons.

  4. The “Viewing” count displays how many branches/tags are visible in the graph. Quickly show all hidden items with “Show All”.
  5. Store HTTP & Proxy credentials to save time when pushing to remotes. They can be cleared in Preferences > Authentication
  6.  Create project groups in the new repo management view to keep your repositories organized.
  7. Open the Command Palette (cmd/ctrl + shift + p) or Fuzzy Finder (cmd/ctrl + p) and arrow down to see a list of shortcuts.

  8. You can drag-and-drop ref labels in the graph to merge, rebase, reset, etc. Multiple refs on one commit will expand on hover. 
  9. Pro users can create and switch between multiple profiles, each with unique settings and hosting service account integrations. 
  10. GitKraken’s easy-to-use conflict tool is even more powerful with Pro, giving you the ability to edit and save the output. 
  11. Hover icons on ref labels to view PR numbers and titles. Right-click the label for options to open them on GitHub.com.
Categories: Companies

GitKraken.com Now 100x Artsier

Wed, 05/03/2017 - 18:09

What do you get when you cross a traveling salesman with a Kraken? Art. You get art.

GitKraken v2.5 is now 3x faster than SourceTree, and gitkraken.com is 100x artsier. We’ve combined our love for art and technology and launched a brand new version of our website. Turns out we have a lot of digital artists at Axosoft! One of which is Kyle Smith, a GitKraken developer, a master at digital mark-making, and our first featured artist on the website.

GitKraken v2.5 Featured Artwork

Kyle has been an artist since he started doodling in high school. “My default doodle was a single squiggly line that tightly curved around itself, which from a distance just looked like one large shape,” said Kyle.

He reminisces, “When I began programming, I loved the idea of one day reproducing my high school doodles with code.” So, he started to learn about computer generated art in college, and after graduation, Kyle stumbled upon a paper that described exactly what he wanted to do: turn an image into points on a grid (in a way that resembles stipple art), then connect them using a solution to the traveling salesman problem. He implemented the process in JavaScript and created an SVG, which when animated with vivus, made the image appear to be drawn.

*Knock Knock* Enter Traveling Salesman

The traveling salesman problem (TSP) is a well-known problem in which one must find the shortest route between a set of cities, where each city is visited once and only once. “The great thing about an optimal solution to a 2D traveling salesman problem is that the lines are proven to never cross. So, like my early doodles, this gives images the effect of lines tightly curving around themselves,” said Kyle.

However, rather than creating a single path, as the paper describes, he split the image into many paths. Now, when the svg is animated with vivus, multiple paths are drawn at once, creating a more visually interesting animation.
v2.5 featured artwork
Like I said, we have a lot of digital artists at Axosoft, and it got us thinking that we probably have a lot more in our community too. So, we invite you to create a GitKraken-inspired digital art piece that could be featured on GitKraken.com. Check out our submission guidelines, and get to it!

Categories: Companies

GitKraken v2.5

Wed, 05/03/2017 - 17:26

While working on improvements for GitKraken v2.4, we noticed that GitKraken was not running as efficiently as we would like, especially on Windows. As many Windows Git client users may know, most Git GUIs run at the speed of a tortoise, while GitKraken runs its race as the hare.

Sadly, we all know how this story goes… Similar to the hare, GitKraken would blaze ahead when performing certain actions and take its time when performing other actions. So, we decided to give GitKraken a bit of a jolt to see what would happen!

the flash

GitKraken’s new found power of super speed kicked in, and the performance improvements were immediately noticeable when checking out a branch:

branch checkout v2.5

That jolt really got GitKraken going—it will no longer take a nap when you request to view the history of a file:

file history v2.5

While experimenting, and benchmarking the improvements GitKraken had made, we noticed that another Mac and Windows Git client (that is most definitely not SourceTree) had made “significant” improvements to its Windows platform. While they were impressed with their results, we really only had one thing to say:

the Flash

For a bit of fun, we decided to benchmark their improvements against our own. And hey, the more the merrier, right? So, we threw the CLI in there too:

windows checkout speeds

That’s right, GitKraken v2.5 is nearly 3 times faster than SourceTree v2.0! And if you’re wondering ‘how can GitKraken be faster than the CLI?!’ The answer is: because GitKraken does not rely on Git tools and because it does all Git operations directly, speeds can be increased through multi-threading and other techniques. Game, set, match!

Be sure to check out our release notes to see the rest of the improvements and bug fixes in v2.5. 

Categories: Companies

An Introduction to Functors

Tue, 04/25/2017 - 18:18
Introduction

In a previous article, we talked about Semigroups and Monoids, which are abstractions that let us combine values of the same type together. In this post, we’ll take a look at Functors, which allow us to operate on values inside containers without having to know any of the implementation details of the containers themselves.

NOTE: This article is based on an Axosoft Dev Talk titled Practical Category Theory: Functors. Watch that video or keep reading!

Before we embark on our journey, we should probably take a quick trip through higher-kinded types!

Higher-Kinded Types

When we program in a language like C# or Java, we often run into “concrete” types like int, string, and bool. The neat thing about concrete types is that we always know all the operations that we can perform on them (ints can be added, bools can be negated, and so on).

One step up on the abstraction ladder are “generic” types, like List<T>. A fancy term for generic types is “parametric polymorphism:” “parametric” because we’re working with a type parameter, and “polymorphism” because the parameter in question can have multiple (“poly-“) shapes (“-morphism”). So, we know what operations we can perform on the List itself (iterate over all its elements, Add an item, etc.), but we know absolutely nothing about the type represented by T. This gives us a lot more power of abstraction because we can write methods that manipulate these generic structures and have them guarantee to work no matter what type we eventually fill in for the type parameter.

In Haskell and Purescript, we’d write List<T> as List t: the name of the generic type (List) comes first, and the name of the type parameter (t) comes next, separated by a space. Haskell and Purescript know that t isn’t the name of a concrete type (like if we had written Int or String) because it starts with a lowercase letter.

We can go one step further and write a type like IEnumerable<T>, where our container type isn’t a concrete type but is only an interface. Now, we know only a little bit about the container type itself (specifically, that it has elements over which we can iterate), and we still know nothing about T. The number of operations we can perform on a value of type IEnumerable<T> is even smaller than those for List<T>. This limitation is actually a good thing because now we can pass in a Stack or a Queue to a method that takes an IEnumerable, for example, and the method will work as expected.

Usually, this is where we would have to stop because most languages don’t let us go any more abstract. However, Haskell and Purescript don’t have this restriction and support so-called “higher-kinded” types, where we can make both the internal type and the container type fully generic. If C# had syntactical support for this, it might look something like T1<T2>. T1 could be IEnumerable, Queue, etc., while T2 could be int, string, etc. Haskell and Purescript, however, do support this concept of higher-kinded types and use this syntax: f t (where f is the container type and t is the type parameter). Because f is lowercase, we know that it’s generic as well as t, and so can be any type that requires exactly one type parameter. For example, the following types would fulfill f:

  • List, which holds zero or more values of the same type.
  • Queue, which also holds zero or more values of the same type, but doesn’t allow random access.
  • Maybe (A.K.A. Option or Optional), which can contain either one value or be empty.
  • Promise, which eventually produces a value.
  • A Redux store, which we can think of being parameterized by the type of the state it contains.

Whereas the following cannot be used for f:

  • Map, because that requires two type parameters, one for the key and one for the value.
  • string, because that doesn’t have any type parameters (another way of saying that is that the type string is already fully concrete).
  • Tuple, because that also requires two or more type parameters (depending on the number of elements it contains).
  • A Redux reducer, which requires two type parameters, one for the message and one for the state.
Fun Fact!

In Haskell or Purescript, the higher-kinded type parameter (f in f t) is usually named f or m, while the type parameter it takes (t in f t) is usually named a (or b or c if more than one is needed).

Constraints

Granted, we really can’t do very much with a value of type f t because we intentionally don’t know very much at all about it. However, we can put constraints on our type parameters. In C#:

class Foo<T> where T : SomeConstraint

Now, T can’t be just anything but instead has some restrictions on what can be plugged in for it. After we’ve put one or more constraints on T, we now know more about what we can do with it. For example, if T is constrained to be an instance of IComparable, that means Foo will only accept types that support the CompareTo method, like int or char (but not, say, List<string>). In Haskell or Purescript, this type can be written SomeConstraint t => Foo t, which means that type t must support the operations in SomeConstraint.

In Haskell and Purescript, we can also place constraints on our higher-kinded type parameters, like so: SomeConstraint f => f t. Now, we know that f supports whatever operations are included in SomeConstraint, and we can plug in any type that supports them. This is approximately analogous to the idea behind IEnumerable<T>, where the container type is abstract and so we can choose a specific type, like List or Queue, to make the type concrete. (We might write that example in Haskell and Purescript as IEnumerable f => f t.) We can also use more than one constraint on a single parameter or place constraints on more than one parameter at a time, like so:

(SomeConstraint f, SomeOtherConstraint f, AnotherConstraint t, YetAnotherConstraint t) => f t
Recap

What all this allows us to do is to have a system of specifying the structures of values, which will come in handy when we get to Functors below. Higher-kinded types allow us to focus on values that have general structure, and we can narrow the possibilities down with constraints.

Phew, that’s a lot to digest. Here’s a summary of how the different concepts (roughly) translate between C# and Haskell and Purescript.

Concrete Types

We know everything there is to know about these types.

C#
int
Haskell, Purescript
Int
Generic Types

We know everything there is to know about part of these types.

C#
Foo<T>
Haskell, Purescript
Foo t
Constraints

We know some things about various parts of these types.

C#
// Constraint on the "traditional" type parameter
Foo<T> where T : IBar
// Constraint on the container type itself
// Approximately:
IFoo<T>
Haskell, Purescript
-- Constraint on the "traditional" type parameter
IBar t => Foo t
-- Constraint on the container type
IFoo f => f t
Higher-Kinded Types

We only know about the very general shape of these types, but we can place constraints on them in order to do useful things with them.

C#
// Doesn't exist, but might look something like:
T1<T2>
Haskell, Purescript
f t
Functors

Lo and behold, we’ve made it to Functors!

We’ve been making statements about the “structures” of types without a clear definition, so here goes:

Structure

Rules about how you can use a type (i.e. the operations that can be performed on it). In an object-oriented (OO) language, this might be represented by interfaces; in a functional language, this might be represented by modules or typeclasses.

IEnumerable<T>, for example, has a different structure from IComparable<T>, because IEnumerables can be iterated over, sorted, etc., while IComparables can be compared.

Functor is a specific structure that supports exactly one operation: map. map allows us to operate on value(s) inside a Functor (which we can think of as a container of some sort) without knowing (or caring) how the Functor is implemented. Each Functor has its own rules for how map works, but this general theme of manipulating contained values is the same.

You’ve already used map if you’ve ever used Array.prototype.map in JavaScript or LINQ’s IEnumerable.Select in C#, for example. You didn’t have to know how the container (the Array or specific IEnumerable) was implemented, since its implementation of map took care of that for you. All you needed to do was provide a function that takes an element of the list and returns something else, and the container handled the rest.

Without further ado, let’s take a look at map‘s type signature!

C#
public interface IFunctor {
    // There's no second parameter, because this method is on the `IFunctor` we want to map over
    IFunctor<TResult> Map<TResult>(Func<T, TResult> fn);
}
Haskell, Purescript
-- Here, we explicitly write the Functor to map over as the second parameter, because Haskell is functional rather than object-oriented
map :: Functor f => (a -> b) -> f a -> f b

map takes a function and a Functor and returns the Functor after the function has been applied to its element(s). The type of the element(s) inside the Functor is allowed to change.

So, Functors are really, really simple. Their only special “skill” is that they allow you to apply a function to what’s inside them.

What Can (and Can’t) Be a Functor?

So far, we’ve only seen List‘s implementation of Functor, but what else could be a Functor?

Queue can, because it can allow a function to be applied to all its elements. Maybe can also be a Functor: if there is no value, then an empty Maybe is returned; otherwise, a Maybe with its value modified by the provided function is returned. Promise can implement map by allowing you to modify the value that the Promise will eventually resolve to (e.g. somePromise.then(x => x + 1)).

So what can’t be a Functor? Well, a Redux store probably can’t. While it certainly allows its state to be modified, being a Functor would mean that the type of the state could change, since any function we use with map with must be allowed to change the type of the elements inside the Functor. We usually don’t want the type of our Redux state to change over time, so a Redux store isn’t a valid Functor.

Let’s see some quick examples of Functors in use. Here’s what it looks like to map over a list in JavaScript, C#, and Haskell and Purescript:

JavaScript
[1, 2, 3].map(x => x.toString()) // ["1", "2", "3"]
C#
new[] { 1, 2, 3 }.Select(x => x.ToString()).ToList() // new[] { "1", "2", "3" }
Haskell, Purescript
map show [1, 2, 3] -- ["1", "2", "3"]

Note that in the above example, the List started out as a List<int> but was converted to a List<string>. This is another important property of map that we’ll get to below.

And here’s what it looks like to map over JavaScript’s Promise type instead:

JavaScript
Promise.resolve(1)
// Think of `then` as `map`
.then(x => x.toString()) // resolves to "2"

In both cases, we’re handing map a function and each Functor is doing the rest for us in its own specific way.

As we can see, the concept of a Functor is intentionally very general, and this idea of very general abstractions is what makes category theory so powerful.

Example

To summarize: Functors allow us to treat “what to do” and “how to do it” as separate concerns. After a map implementation is written for a type, it can be used the same way with any function (as long as its parameters are the correct types, of course).

Now for a real-world example! Let’s pretend that we have a Maybe type of some sort in JavaScript, along with a corresponding fromMaybe function that takes a modifying function, a default value, and the Maybe to map over. If the Maybe contains a value, fromMaybe will return a modified version of that value; if, however, the Maybe does not contain a value, fromMaybe will return the default value that it was passed.

As an example, we might traditionally work with possibly nonexistent values like so:

const result = thingThatMightFail();
return result.value
    ? result.value + otherValue
    : 0;

The issue with this approach, however, is that we can forget to check that result is null or undefined (‘cannot read property of undefined,’ anyone?). If, however, we use some sort of Maybe object, we might be able to rewrite the above using fromMaybe as follows:

const result = thingThatReturnsAMaybe();
return fromMaybe(
    v => v + otherValue, // Function to apply if we have a value
    0, // Default value
    result // Maybe object
);

Now, if we forget to use fromMaybe on our result, we’ll catch it when we try to actually use this value. Granted, this isn’t as useful in JavaScript as it is in a statically-typed language like C# where we’d be able to catch such errors at compile-time, but using Maybe like this everywhere we’d use null or undefined still allows us to reason about our code and know what can return a value that might not exist (instead of just hoping that we remembered to check for null or undefined everywhere we use a potentially nonexistent value).

If we want to run multiple operations in sequence on a value that might not exist, we might think to do it like this:

const json = someAjaxRequest();

let result = defaultUser;
if (json) {
    const id = extractId(json);
    const user = getUserById(id);
    result = upgradeUser(user);
}

However, with Maybe, we can write it differently:

Note: R.pipe is a function from the Ramda.js library that “composes” functions: it takes several functions and chains them together to create a new function (for more details, see the docs).

Also, for clarity, psuedo Flow function type annotations are included.

const maybeJson: Maybe<JSON> = someAjaxRequest(); // someAjaxRequest: () => Maybe<JSON>

const result: User = R.pipe(
    (maybeJson: Maybe<JSON>) => map((extractId: (JSON) => Id), maybeJson),
    (maybeId:   Maybe<Id>)   => map((getUserById: (Id) => User), id),
    (maybeUser: Maybe<User>) => fromMaybe(
        (upgradeUser: (User) => User),
        (defaultUser: User),
        maybeUser
    )
)(maybeJson);

And here’s the same example, but this time we’ll remove unnecessary Flow type annotations and take advantage of a technique called currying in order to see what the same code might look like in a real-world situation:

const maybeJson: Maybe<JSON> = someAjaxRequest();

const result: User = R.pipe(
    map(extractId),
    map(getUserById),
    fromMaybe(upgradeUser, defaultUser)
)(maybeJson);

So, let’s see what we gain from using Functors. As opposed to in the first, ‘traditional’ example, we didn’t have to manually handle the case where no value was returned. The Maybe Functor itself was able to decide how to do so, and all we needed to worry about was giving map the functions that we’d like to perform if a value does happen to exist. We can use any functions we want for each step in the pipeline, as long as they have the correct types (namely, the return type of each one must be the type of the next one’s parameter).

Functors are incredibly common in practice, and a good rule-of-thumb is to ask yourself whenever you begin to write a function that operates on a data structure if the function could be made general enough to operate on a Functor instead. For example, Haskell/Purescript functions like replace and zip could be defined to work with lists specifically, but they’re instead implemented to only require that their parameters are Functors; as such, they work on many different structures for free! They don’t need to know anything about how each of those Functors works on the inside because map handles the details for them.

Laws

Finally, Functors have two associated “laws” to ensure that the Functor will behave as one would expect. Don’t worry, you won’t go to jail if you get these laws wrong (although it is certainly an unpleasant surprise when a Functor is “unlawful”).

Law #1: Identity

Mapping the identity function over a Functor has no effect.

Fancy pseudo-Haskell way to say it:

map id = id

This one’s pretty self-explanatory: if your function doesn’t actually do anything to the element(s) inside the Functor, then it would certainly be surprising if you got back a different result than what you passed in.

JavaScript Example
map(x => x, [1, 2, 3]) // [1, 2, 3]
Law 2: Composition

Multiple maps in a row can be composed into one without any changes in the overall behavior.

Fancy pseudo-Haskell way to say it ((.) is the function composition operator):

map f . map g = map (f . g)
JavaScript Example

We could write our earlier JSON-manipulation example like so if we combine the two-in-a-row maps into a single map, with the new function to use being the composition of the two steps in our pipeline.

R.pipe(map(extractId), map(getUserById))(json) // map(R.pipe(extractId, getUserById), json)
Go forth and map!

And that’s it for Functors! They’re very simple structures that give us a lot of power. Just like Semigroups and Monoids, they’re used very commonly because they’re so simple to reason about. And, because they’re so general they allow us to write functions once and use them on all sorts of different data structures, guaranteed!

Categories: Companies

GitKraken v2.4

Wed, 04/19/2017 - 22:14

In GitKraken version 2.4, substantial improvements have been made to lots of actions you perform every day. You know those little quirks in GitKraken that sometimes made you say an expletive out loud? It turns out that one of our own, Dan Suceava, regularly swears at his monitor, oftentimes with GitKraken being the recipient of his wrath.

Who is this Dan Suceava?

Hmm, where should we begin…. You don’t know Dan, but you probably use his deftly-coded API regularly. Dan is the VP of Engineering here at Axosoft and has been with the company for more than 11 years. Even though he’s not an active GitKraken developer, his work touches all aspects of Axosoft as a company. You could say that a piece of Dan goes into every release—but that’s a somewhat disturbing thought!

Anyways, what does he actually do, you might also ask? This question is harder to answer. All we know is, he turns up to work, and then, later, he leaves. Between his comings and goings, Dan enjoys saying “no,” a lot, he swears at his computer, and he drinks more Jack Daniel’s than any mortal man should. A sort of engineering equivalent to a Boo Radley–Sasquatch hybrid; he sits in a dark corner of one of our dev rooms, only to be rarely spotted in the kitchen. Some say he eats squirrels. Some say he uses Windows ME. But one thing no-one disputes is that Dan is a coding powerhouse. Much of Axosoft’s success can be attributed directly to Dan!

A rare sighting of Suceava outside of his natural habitat

So when it became apparent that one of Dan’s favorite products, GitKraken, is also the recipient of some of his curse words, the GitKraken team wanted to make things right. As a tribute to Dan, the GitKraken team is dedicating a release (or two) to fixing the issues that made Dan go through his stockpile of Jack Daniel’s at twice the rate he normally would. After getting a demo of his issues with GitKraken, the team realized these issues are going to make a lot of people (except for Jack Daniel) very happy.

Suceava updates
  • Before: GitKraken would dismiss 99.7% of issues as “user error,” muttering profanities under its breath.
  • Now: GitKraken is polite as can be, updating submodules correctly when switching branches, and initializing them faster (and recursively, if a submodule has submodules).
  • Before: When refreshing, there was a 90% chance that GitKraken DSRC either shrugged or barked “NO!” The other 10% of the time, the app took 3 days to complete the action.
  • Now: Commit sorting algorithm improvements mean the app is faster when refreshing.
  • Before: The app got drunk and forgot where it was, randomly disappearing only to reappear several hours later.
  • Now: the app remembers whether or not it was in full-screen mode when shut down, and the location of its Window. It will restore these settings when restarted.
  • Before: Checking out a remote branch beyond the graph history made the app highly irritable, giving the message “I should have started a farm,” and then accusing you of user error.
  • Now: Checking out a branch beyond 2,000 commits creates a local ref and checks out the branch, error-free.

This release includes 15 more bug fixes and other improvements. See the release notes for all the details.

P.S. Release notes can be translated from English to Suceava—enjoy!

Categories: Companies

Axosoft v17.1: Burndown Chart Update

Tue, 04/18/2017 - 22:59

In Axosoft v17.1, we made a small adjustment to the way burndowns work, which should provide more accurate velocities for our users. Prior to v17.1, velocity was strictly based on the number of hours that were entered using work logs. This was great for the apple polishers that entered all of their work logs at the end of the day, for all items, without exception—but it lead to a lot of confusion for teams that weren’t adding work logs for all of their items (or any of their items).

We heard your protests about not having to add work logs for every single item, and we’ve accepted your peace offering of a Pepsi can to free you from the oppression of work logs.

pepsi commercial

Too soon? Sorry.

Burndown Velocity Update

Prior to this release, teams that used story points for estimation had burndowns that were often nonsensical—or that disappeared because work logs didn’t often make sense when completed work was estimated in points. The one behavior that changed in this release is decreasing an item’s remaining estimate manually, or by setting the item to `completed`. Axosoft will now update the burndown velocity as you’re getting work done.

For example, let’s say you have a bug fix that is estimated to be 4 hours worth of work, and you move the item to ‘completed’ without adding a work log. Previously, Axosoft would update all of the data points in the burndown and subtract 4 hours worth of work, as if the item was never in the release.

Prior to v17.1: burndown prior to v17.1 4 hours of work removed from all days. (First day goes from 164 down to 160 hours.)

Now, moving an item with 4 hours of work remaining to ‘completed’, will only subtract the 4 hours from the current day, and the work you completed will be reflected in the velocity.

After v17.1: burndown after v17.1 4 hours removed only from today. (First day remains at original value.) What you can expect with this change

Because Axosoft was previously only using logged work for velocity, you may notice that your velocity is now greater than it was for any previous sprint. This should be a more accurate representation of the rate at which your team is getting work done because Axosoft is now taking into account all the work you’ve completed for your items.

For more details about Axosoft burndown charts and velocity calculations, check out our support documentation.

Categories: Companies

Learning Git with GitKraken: Rebasing in GitKraken vs CLI

Tue, 04/18/2017 - 01:00

In these videos, Brett Goldman compares the experience of performing a very basic rebase in the CLI vs GitKraken, followed by a demonstration of what happens, and what to do, when conflicts occur. Take a look and subscribe to our YouTube channel for more videos about learning Git with GitKraken.

Categories: Companies

Introducing Axosoft Version 17.1

Fri, 04/14/2017 - 16:00

Some software releases have big, visual changes that you see the very moment you open the app. Version 17.0 of Axosoft was one of those big ones, with a huge visual overhaul that tidied up the UI, and big improvements to the user experience.

However, version bumps are also often cause for a large amount of development work being applied to complex solutions that are designed to be, at the front end, almost invisible. These feature sets are in place to remove friction, make you notice the app less, and so you can spend less time doing things.

Axosoft version 17.1 is one such release. In this release, not only have we fixed a bunch of smaller issues that some users on previous versions were experiencing, but we’ve continued the tradition of introducing subtle, elegant solutions to “quality of life” issues that have, until now, made certain repeated tasks less efficient than they could have been.

Version 17.1 has several marked interaction improvements that will soon become so commonplace in your day-to-day use of Axosoft, you’ll forget they’re there at all. So, what’s new?

Fuzzy Finding Duplicates Before You Duplicate Them

Collaborating on projects and releases can create duplication. For example, more than one person might create a task that has been discussed communally. In an effort to reduce the likelihood of the same item being created twice, Axosoft now has a fuzzy finder style drop down to show you existing items in your account that match or share similar names to the item name you are typing.

You can still create the new item as you did before, but if you happen to notice an existing item that you’d like to view or edit, simply select it from the drop-down. Cutting down on duplicated items means less confusion across your team.

Renaming Email Accounts

A lot of users have requested the ability to rename email accounts to something a little more friendly than ihatejira4353234@hotmail.com.

As an admin, simply go to Manage Account > Other Settings > Email Accounts. Open the account whose name you wish to change, and in Account Settings, use the Account Name field to edit the name to whatever you want. Simple!

You Literally Come First

When editing the Assigned To field, there’s a fairly good chance you’ll want to assign yourself to that item, so that’s a pretty reasonable default, right? When creating an item in v17.1, you will now appear at the top of the list of users. Typing another name will narrow down the options as before.

Other Improvements Reports

When exporting a report, you can now include a new field: Parent Item. This allows you to see more easily where sub-items sit in your projects.

Email

In your email lists, you can now filter by emails that are auto-reply emails. Simply click the gear icon in the top-right of the email list, and then select Email > Is Auto Reply filter.

You can also now view the size of attachments for an email, so you know just how large they are.

We hope you enjoy using these new features in version 17.1. As always, this release brings a bunch of other improvements and fixes to the app, and you can see the full list in the 17.1 version history.

Categories: Companies

Reduxifying GitKraken

Tue, 04/11/2017 - 16:59

GitKraken is a React app. We’ve been using React since version 0.12.2 (in January of 2015) when we migrated from Angular.js. When we started using React, we architected with the flux library from Facebook as our state model and forged ahead into glory. At first, it was good. Much performance. Many code. Wow!

The initial excitement subsided, and the honeymoon was over. We looked back at our strange mess of state and decided to make a move to Redux. It’s fair to say we had problems scaling with Flux.

The GitKraken team is now finishing up the transition from Flux to Redux, and everything is looking really amazing. There are already a lot of benefits that we are seeing from Redux as we write new code for the application.

Redux vs Flux

For those unfamiliar with Redux, but familiar with Flux, you can think of Redux as a stricter implementation of Flux. Instead of multiple stores and a dispatcher to bind all of the stores together, there is one store that holds all of the state in the application.

For those unfamiliar with both libraries, the Flux library is the implementation of the Flux pattern. The Flux pattern is similar to Model View Controller (MVC), but has a strict one-way data flow constraint.

Flux pattern

At each step in the flow, data is limited to only one movement direction. A view can start an action at the request of a user, the action can generate new data and pass it to the dispatcher, the dispatcher dispatches the results of actions to the stores, and the stores can then emit an update to the views.

In the Redux library, we’ve reduced our total store count to one, and thus we don’t need a dispatcher at all. The dispatcher was originally there to manage the order in which we update stores with action results and keep the stores behaving. Instead, we just directly inform the Redux store of an action that has occurred. So we’ve kept the basic premise of the Flux pattern, but shrank the pattern’s flow by combining the dispatcher and the store.

Redux state

Since we only have one store now, my first reaction was that the store would be a monolithic hellspawn of a maintenance issue, but we actually keep some semblance of order by using Redux’s reducer pattern for our separating concerns. The main mechanism for Redux is the reducer pattern; we have one top level reducer, and we can branch substate trees into smaller reducers.

A reducer is a pure function of state and message to state. We take the previous state tree, a message, and apply some transformation of the state to produce a new state tree. The top level reducer has this shape, and any subreducers also have this shape.

The process of reducing utilizes a constraint we place on the Redux state, that it is immutable. When a message is passed into Redux land, the message is passed through a series of these reducers. Those reducers then decide whether or not to perform an update according to the message.

In our case, the reducers decide whether or not to produce a brand new object. To clarify, we update every reference along a path to an updated value, such that we have made no mutations to the previous state tree. When our reducers produce a brand new object, we know that changes happened to that particular substate tree. In fact, we can trace the new object references to the exact set of changes that have taken place between the previous state and the next state.

Benefits of Redux

What makes this transition so nice to work with is that exactly one message changes state at a time in a very consistent and straightforward manner (a → b). It might seem a bit daunting at first to hoist all state of the app into a single state tree, but the benefits are an amazing trade-off.

Things like time travel can be implemented in a trivial fashion (just store the sequence of state updates). Holding all state in an immutable data structure also allows React to, erm, react better! We can utilize referential transparency when the Redux store emits a change. React can perform a check before updating to see if the top level object reference has changed, and it if hasn’t, shortcircuit the entire rendering tree.

Another nice benefit of the pattern we build with Redux comes into play when we organize our view around our Redux state. We build containers which listen to Redux state, and when a state update occurs, those containers retrieve the relevant changes and choose whether or not to react. Those containers pass any state they care about to a presentation layer. These layers are largely stateless view components (components that only receive props).

Ok! Ok. The benefit I’m describing is that the view layer scales horizontally by top level containers, which hold onto a pure render tree. When we want to add more containers, we can do it in a clean manner (a container is responsible for a full view), even though every container talks to the same store. We’ve basically built an architecture that adds one connection per new UI container when scaling. That’s really clean!

That’s not the only place we scale better. The Redux state itself scales per reducer. We can grow the size of the total state by building new reducers with their own substate, but we don’t have to increase the complexity of already written reducers, nor do we have to manage an explicit dispatch order like we did in Flux. There’s only one store, and our reducers run synchronously, producing a new state one message at a time.

Scaling example

So there you have it. We have an architecture that now provides a cleaner scaling experience in GitKraken.

Categories: Companies

Axosoft Dev Talk: Practical Category Theory

Wed, 04/05/2017 - 17:37

It’s time for another video in our Axosoft Dev Talk series! In the first of two talks about Practical Category Theory, David Koontz explains Semigroups and Monoids. Watch this video to learn more, and don’t forget to subscribe to our YouTube channel for more videos about software development.

Could your Git client list be represented as the monoid ""? Maybe you should add GitKraken!

Categories: Companies

GitKraken v2.3

Tue, 04/04/2017 - 00:14

As you’re probably aware by now, we work hard to address the needs and requests of ye faithful users of your favorite Git client, GitKraken. Version 2.3 implements a widely requested feature that everyone here at Axosoft is excited to see in a release: Git hooks!

We’re aware that this has been a barrier that has prevented some users from being able to adopt GitKraken for use in their teams, where specific functionality during certain actions is an absolute necessity. With Git hooks support, we’re hoping that GitKraken now incorporates the best of both worlds: an intuitive and simple to use interface, with the super-user functionality of Git hooks.

What are Git hooks?

Well, a hook might be defined as a trigger. If you’re familiar with JavaScript, you’ve probably used hooks before, in the form of events. Event listeners can be set up to fire custom actions when certain events (e.g. click, ‘click’) occur. Those events might be considered “hooks,” since you’re ‘hooking’ into them to do what you need to do.

WordPress users might also be familiar with hooks in the context of action hooks. At certain points in a page or post being rendered, various actions are fired off, into which the programmer can hook custom functions to work with the information at hand at that point in the rendering process.

Git hooks are very similar. They allow a user to create custom scripts that fire off at certain points during Git processes. GitKraken does not require that you install Git on your system, so until now, that independence had meant no Git hooks support. But, with a lot of blood, sweat and tears, v2.3 allows you to hook your way to a bounty of control over your Git actions!

Watch this short video to learn about Git hooks, and to see how Git hooks work in GitKraken.

What hooks are supported by GitKraken?

Beneath each hook is a list of the actions during which GitKraken calls that hook:

  • pre-commit:
    • Commit
    • Amend
    • Merge Resolve
  • prepare-commit-msg:
    • Commit
    • Amend
    • Cherrypick
    • Merge
    • Squash
    • Revert
  • commit-msg:
    • Commit
    • Amend
    • Merge Resolve
  • post-commit:
    • Commit
    • Amend
    • Cherrypick
    • Merge Resolve
    • Revert
  • pre-rebase:
    • Rebase
    • Squash
  • post-checkout:
    • Checkout
    • Discard Changes (selectively)
  • post-merge:
    • Merge (Without Conflicts)
    • Fast-Forward
  • post-rewrite:
    • Amend
    • Squash
    • Rebase
  • pre-push:
    • Push Branch
    • Push Tag
    • Delete Remote Branch
    • Delete Remote Tag

So that’s Git hooks. We hope you enjoy getting your tentacles all up in our actions!

Regional Date Settings

Another widely-requested feature has been the ability to set region-specific display dates for commits. Y’all might not be from these here parts and might have some region-specific ways of presenting your dates. Viewing another format can be jarring and counter-productive when you’re trying to decipher dates at-a-glance.

Well, guess what? GitKraken will now think to itself, where am I? and will update its date format accordingly, based on your system locale. You’re welcome! De rien! Bitte schön! De nada! Don’t mention it! Pip pip! As you were.

New Onboarding Experience

It’s now easier than ever before to get the rest of your team set up in GitKraken. V2.3 introduces a brand new onboarding screen for first-time users. It’s easier to see where to set preferences and start working with repos. It also introduces users to our Intro to GitKraken video which gives a quick 90-second overview of GitKraken’s functionality, our support site which provides lots of helpful documentation, and the GitKraken Slack Community where our users come together to help each other and help our team improve GitKraken.

But, there is just one more thing…

Try GitKraken Pro for free

If you’ve been wanting to try out GitKraken Pro features—like the merge conflict output editor, multiple profiles for work and personal use, or GitHub Enterprise integration—nows your chance!

Start a free GitKraken Pro trial by simply clicking the 

button in-app. You’ll be able to test these awesome features for up to 14 days before deciding if you want to upgrade to a paid account!

Categories: Companies